ZAHLEN

Chapter 6

Payment Events API


image

Submit events, batch ingestion, event retrieval, and decision retrieval


Audience

Merchants | Developers | Integration Engineers


Commercial workflow

Payment Event -> Retry Decision -> Retry Outcome -> Investigation Run -> Reporting


Zahlen API User Guide v1.0

Source baseline: zahlen_deploy_0616A.tar.gz | June 2026

Chapter 6 - Payment Events API


Learning objectives

By the end of this chapter, you should be able to submit one or many payment events, validate

ingestion results, retrieve individual events, and consume generated retry decisions safely.

Payment events are the evidence layer of Zahlen. A merchant sends observed authorization or decline information; Zahlen validates and normalizes that evidence, creates durable batch and job identifiers, and makes related event, decision, summary, and processor-result resources available for retrieval.


Canonical retry schedule

Zahlen uses the fixed retry schedule Day 1, Day 2, Day 6, and Day 16. Payment-event evidence should accurately identify the attempt number and timing so the event can be interpreted within

this schedule.


    1. Endpoint overview


      Method

      Path

      Purpose

      POST

      /v1/payment-events

      Submit one or more events using the

      standard ingestion response.

      POST

      /v1/payment-events/batch

      Submit one or more events using the batch-

      oriented response.

      GET

      /v1/payment-events/{event_id}

      Retrieve normalized and raw event detail.

      GET

      /v1/payment-events/{event_id}/decision

      Retrieve the decision generated for one

      event.

      GET

      /v1/payment-events/{event_id}/processor-

      result

      Retrieve downstream processor execution

      evidence.

      GET

      /v1/payment-events/batches/{batch_id}

      Retrieve batch state and paginated event

      IDs.

      GET

      /v1/payment-events/batches/{batch_id}/

      summary

      Retrieve distributions and retry-candidate

      counts.

      GET

      /v1/payment-events/batches/{batch_id}/

      decisions

      Retrieve paginated decisions for a batch.

      GET

      /v1/payment-events/batches/{batch_id}/

      processor-results

      Retrieve paginated processor results.

      All merchant-facing requests use the X-API-Key header. Tenant ownership is derived from the authenticated key; clients do not choose tenant ownership by including tenant_id in the JSON body.

    2. PaymentEventInput

      Each item in the events array is a PaymentEventInput. Only event_id is required by the schema, but richer evidence improves explanation, correlation, reporting, and operational diagnosis. Unknown top-level fields are rejected because additional properties are forbidden.

      Required field


      Field

      Type

      Rule

      Purpose

      event_id

      string

      Required; minimum length 1

      Stable merchant-generated identifier for one payment

      event.


      Recommended evidence groups


      Group

      Fields

      Integration guidance

      Decline evidence

      decline_code, response_code,

      paymentech_code, decline_category

      Send the processor evidence available at the

      time of the event.

      Issuer context

      issuer_bin or bin, issuer, bank, country,

      card_brand

      Use safe issuer-level attributes; never send a

      full PAN.

      Money

      amount or amount_minor, currency

      Choose units consistently. amount_minor is

      an integer minor-unit value.

      Retry sequence

      attempt_number, attempt_day_in_cycle

      Align attempts with the fixed Day 1, 2, 6,

      and 16 schedule.

      Timing

      decline_timestamp, event_timestamp

      Use ISO 8601 strings and preserve the actual

      observed time.

      Merchant correlation

      payment_token, customer_id,

      subscription_id

      Use tokenized or merchant-safe references.

      Processor context

      processor, authorization_id,

      authorization_latency_ms

      Useful for execution analysis and

      diagnostics.

      Transaction context

      merchant_category_code,

      recurring_indicator, transaction_initiator

      Clarifies recurring and merchant-initiated

      payment behavior.

      Extensions

      metadata

      Use only for safe, non-sensitive merchant

      context.


      Sensitive-data rule

      Do not place a full card number, CVV, password, bank credential, or other prohibited secret in any

      field, including metadata. Use tokens and the minimum evidence necessary.

    3. Submit an event

      POST /v1/payment-events accepts PaymentEventsIngestRequest. Although this section demonstrates one event, the request body always contains an events array. The array must contain at least 1 and no more than 10,000 events. source is optional and defaults to payment_events_api.

      Minimal request


      curl -sS -X POST "$ZAHLEN_BASE_URL/v1/payment-events" \

      -H "Content-Type: application/json" \

      -H "X-API-Key: $ZAHLEN_API_KEY" \

      -d '{

      "events": [

      {"event_id": "evt_20260616_0001"}

      ]

      }'


Recommended enriched request


{

"source": "subscription_billing", "events": [{

"event_id": "evt_20260616_0001", "decline_code": "51",

"issuer_bin": "411111", "card_brand": "VISA", "amount_minor": 2999, "currency": "USD", "attempt_number": 1,

"attempt_day_in_cycle": 1, "event_timestamp": "2026-06-16T12:00:00Z", "payment_token": "tok_customer_001", "customer_id": "cus_001", "subscription_id": "sub_001",

"processor": "example_processor", "metadata": {"invoice_id": "inv_1042"}

}]

}


Request validation

    1. Understand the ingestion response

      The standard ingestion response confirms receipt and provides identifiers required for later retrieval and support correlation. Persist these identifiers before continuing the workflow.


      Field

      Meaning

      Client action

      status

      Current ingestion status

      Treat as the authoritative state, not as a

      settlement result.

      merchant_id

      Authenticated merchant context

      Use for diagnostics; do not use it to infer

      tenant ownership.

      tenant_id

      Resolved tenant context; nullable in schema

      Never submit or override this value from

      client input.

      payment_event_batch_id

      Batch created for the request

      Store with the local ingest operation.

      upload_job_id

      Background processing / investigation

      correlation

      Log and retain for status and support

      investigations.

      received_event_count

      Events received by the route

      Compare with the local intended count.

      total_rows / valid_rows / invalid_rows

      Validation and row totals

      Alert on unexpected invalid or missing

      rows.

      error_count

      Recorded ingestion errors

      Inspect ingestion detail when nonzero.

      created_at / completed_at

      Lifecycle timestamps

      completed_at may be null while work

      continues.

      ingestion

      Additional ingest detail object

      Treat as extensible and avoid brittle

      assumptions.


      Acceptance is not downstream completion

      A successful POST proves that the API accepted the request according to its response. It does not prove that every downstream decision, investigation, or reporting bridge has completed. Preserve

      upload_job_id and check the appropriate retrieval resources.


      Identifier chain


      Identifier

      Created by

      Use

      event_id

      Merchant

      Stable correlation for one event.

      payment_event_batch_id / batch_id

      Zahlen

      Groups an ingestion request.

      upload_job_id

      Zahlen

      Connects ingestion to background

      processing and investigation.

      decision_id

      Zahlen

      Identifies one generated retry decision.

      request_id

      Zahlen

      Trace and support correlation.

    2. Batch submission

      POST /v1/payment-events/batch uses the same PaymentEventsIngestRequest model but returns PaymentEventsBatchIngestResponse. Use it when the integration naturally groups multiple observations and needs an explicit batch resource.

      Batch request example


      curl -sS -X POST "$ZAHLEN_BASE_URL/v1/payment-events/batch" \

      -H "Content-Type: application/json" \

      -H "X-API-Key: $ZAHLEN_API_KEY" \

      --data-binary @payment-events.json


{

"source": "nightly_billing_export", "events": [

{

"event_id": "evt_batch_0001", "decline_code": "51",

"attempt_number": 1,

"attempt_day_in_cycle": 1

},

{

"event_id": "evt_batch_0002", "decline_code": "91",

"attempt_number": 2,

"attempt_day_in_cycle": 2

}

]

}


Batch response fields


Field

Meaning

submitted

Number presented in the request.

accepted

Number accepted for processing.

rejected

Number rejected.

batch_id

Durable batch identifier.

events_url

URL for retrieving the batch events resource.

upload_job_id

Background-processing correlation.

created_at / completed_at

Lifecycle timestamps.

ingestion

Optional extensible ingestion details.


Batch design checklist

    1. Retrieve a batch

      Use the batch resource to inspect state and obtain event IDs. The detail, decision, and processor-result list routes use offset-based pagination. offset must be at least 0; limit, when supplied, must be from 1 through 1,000.

      curl -sS \

      -H "X-API-Key: $ZAHLEN_API_KEY" \

      "$ZAHLEN_BASE_URL/v1/payment-events/batches/$BATCH_ID?offset=0&limit=250"


Resource

Important fields

Batch detail

status, submitted, accepted, rejected, event_ids, total_events,

returned, offset, limit, has_more

Batch summary

event_count, retry_candidates, top processors, decline codes, issuers, issuer BINs, card brands, confidence and decision

distributions

Batch decisions

decisions, total_events, returned, offset, limit, has_more,

decisions_source

Batch processor results

processor_results, total_events, returned, offset, limit, has_more,

processor_results_source


Pagination loop


offset = 0

limit = 250 while True:

page = get_batch_decisions(batch_id, offset=offset, limit=limit) process(page.get("decisions", []))

if not page.get("has_more", False): break

offset += page["returned"]


Pagination safety

Advance by the returned count and stop when has_more is false. Protect against a zero returned

count with has_more=true so a malformed or transient response cannot create an infinite loop.

    1. Retrieve an event

      GET /v1/payment-events/{event_id} returns PaymentEventDetailResponse. The result combines durable correlation fields, commonly used normalized attributes, the normalized_event object, and the raw_event object.

      curl -sS \

      -H "X-API-Key: $ZAHLEN_API_KEY" \

      "$ZAHLEN_BASE_URL/v1/payment-events/evt_20260616_0001"


How to use the response


Response area

Use

Correlation

event_id, payment_event_batch_id, upload_job_id, source,

source_row_number

Merchant context

merchant_id and resolved tenant_id when returned

Normalized common fields

decline_code, response_code, issuer_bin, issuer, country, card_brand, amount_minor, currency, attempt_number,

event_timestamp, processor, authorization_id

normalized_event

Preferred machine-readable normalized representation for

application logic.

raw_event

Original or source representation for diagnostics and evidence

review.

created_at / updated_at

Persistence lifecycle timestamps.


Normalized versus raw

Use normalized fields for routine client logic. Preserve raw_event for diagnostics, but do not build fragile production logic around processor-specific raw keys unless a separate contract guarantees

them.


Not-found behavior

A 404 can mean that the event does not exist or is not visible to the authenticated tenant. Verify the environment, API key, and exact event_id. Never bypass tenant filters to make a resource appear.

    1. Retrieve a decision

      GET /v1/payment-events/{event_id}/decision returns PaymentEventDecisionResponse. This is the recommendation generated from the event evidence. A recommendation is not the observed processor outcome and must not be treated as recovered revenue.

      curl -sS \

      -H "X-API-Key: $ZAHLEN_API_KEY" \

      "$ZAHLEN_BASE_URL/v1/payment-events/evt_20260616_0001/decision"


Field

Interpretation

decision

Explicit control signal. Follow this value rather than inferring

action from other fields.

recommended_retry_day

Nullable recommended day. When present, it should align with the

fixed Day 1, 2, 6, or 16 schedule.

confidence / confidence_score

Evidence strength, not a guarantee of payment success.

reason_codes

Machine-readable explanation categories.

reason_detail

Human-readable explanation; nullable.

policy_source / matched_policy_id

Policy provenance when available.

decision_id / request_id

Durable identifiers for logging, outcome reporting, and support.

idempotent_replay

Indicates that an earlier logical operation was safely replayed.

event

Event evidence associated with the decision.

issuer_context

Optional issuer-level context used or returned by the decision flow.


Never invent a retry day

If recommended_retry_day is null, do not select an arbitrary day. Follow the decision and reason fields. Where a retry is authorized by Zahlen, execution must remain within the fixed Day 1, Day 2,

Day 6, and Day 16 schedule.


Decision and processor result are separate

The decision tells the merchant what Zahlen recommends. GET

/v1/payment-events/{event_id}/processor-result reports downstream execution evidence, including result, processor reference, response code, description, and processing time. Chapter 8 explains how to report retry outcomes and close the learning loop.

    1. End-to-end client pattern

      1. Create a stable event_id and persist the local event record.

      2. Validate the payload and submit it with X-API-Key.

      3. Persist payment_event_batch_id or batch_id and upload_job_id from the response.

      4. Retrieve the event and verify normalized evidence when needed.

      5. Retrieve the generated decision and preserve decision_id and request_id.

      6. Execute only the authorized payment action and only on the fixed Day 1, Day 2, Day 6, or Day 16 schedule.

      7. Report the observed retry outcome through the Retry Outcome API.

      8. Monitor investigation and reporting resources for broader patterns.

    2. Error handling summary


      Status

      Meaning in this workflow

      Response

      400

      Malformed or business-invalid request

      Correct the payload; do not blindly retry.

      401

      Missing, invalid, revoked, or wrong-

      environment API key

      Verify X-API-Key and environment.

      403

      Authenticated but not permitted

      Check plan, capability, or endpoint

      authorization.

      404

      Event or batch absent or not tenant-visible

      Verify identifier and authenticated tenant

      context.

      409

      Conflict or replay mismatch

      Compare the logical operation and original

      request.

      422

      Schema validation failure

      Correct field spelling, types, limits, and

      unknown properties.

      429

      Rate or quota enforcement

      Back off and honor Retry-After when

      present.

      500/503

      Server or dependency failure

      Retry safely with backoff; preserve stable

      identifiers and idempotency behavior.


    3. Production readiness checklist

      • API keys are loaded from a secret manager, not source code.

      • event_id uniqueness and replay behavior are documented.

      • Client models reject unknown fields before sending.

      • amount and amount_minor units cannot be confused.

      • All timestamps are produced and parsed consistently.

      • Batch counts and invalid-row counts are monitored.

      • Batch pagination is bounded and loop-safe.

      • Identifiers are included in logs without exposing secrets.

      • Decision handling supports nullable fields.

      • Payment execution is constrained to Day 1, Day 2, Day 6, and Day 16.

      • Observed outcomes are reported separately from recommendations.


Chapter takeaway

A reliable Payment Events integration preserves evidence and identifiers. Submit accurate observations, treat ingestion as an asynchronous durable workflow, retrieve normalized events

and explicit decisions, and keep recommendation, execution, and outcome as separate facts.