Why operations are asynchronous
When you submit a payment through the Zeam API, the request passes through multiple systems: internal compliance checks, Stellar network settlement, external payment provider submission, and provider-side processing (bank transfers, mobile money delivery, KYC verification). Each of these steps operates on its own timeline. Some examples of operations that are inherently asynchronous:- A cross-border bank transfer that takes hours to settle at the destination
- A mobile money delivery waiting for the recipient’s provider to confirm
- A KYC check that requires manual review before the transaction can proceed
- A payment reversal triggered by a provider callback received after the initial confirmation
- A retry attempt after a temporary provider outage
Treat the initial API response as “accepted for processing”, not “completed”. The final state arrives via webhook or by polling the status endpoint.
Transaction lifecycle
Every transaction moves through a defined set of states. Only two states are terminal — the transaction either completes or fails permanently.| State | Terminal | Description |
|---|---|---|
created | No | Request accepted, prechecks running |
pending | No | Prechecks passed, preparing for submission |
processing | No | Submitted to the payment provider, awaiting confirmation |
requires_action | No | Paused — requires manual resolution (compliance hold, provider query) |
completed | Yes | Funds delivered, ledger finalized |
failed | Yes | Permanently rejected — reason code attached |
reversed | Yes | Previously completed, then reversed by the provider or by a compliance action |
Why webhooks are required
Polling the status endpoint works for debugging, but it is not sufficient for a production integration:- Latency — polling introduces delay between the state change and your system learning about it. Webhooks deliver within seconds.
- Efficiency — polling at high frequency wastes bandwidth and counts against rate limits. Webhooks deliver only when something changes.
- Completeness — some state transitions (reversals, compliance holds) happen hours or days after the initial request. Polling would need to run indefinitely.
Webhook events
The Zeam platform publishes webhook events when a transaction changes state. Each event represents a single state transition.Event types
| Event type | Trigger |
|---|---|
transaction.created | A new transaction has been accepted for processing |
transaction.pending | Prechecks passed, preparing for provider submission |
transaction.processing | Submitted to the external payment provider |
transaction.completed | Provider confirmed delivery — funds arrived |
transaction.failed | Permanently failed — see reason_code for details |
transaction.reversed | A previously completed transaction was reversed |
transaction.requires_action | Paused — requires manual resolution before processing can continue |
Example webhook payload
Signature header
Every delivery includes an HMAC-SHA256 signature in thex-zeam-signature header:
Acknowledging delivery
Respond with any2xx status code and an empty body. Zeam treats the delivery as successful once it receives the response:
2xx status or does not respond within 10 seconds, Zeam retries the delivery with exponential backoff.
How it fits together
This sequence shows the full lifecycle of an asynchronous payment:- Your application submits the transaction. The API returns a
transactionIdimmediately. - The gateway submits the payment to the external provider. A
transaction.processingwebhook fires. - The provider sends an asynchronous callback confirming delivery. The gateway updates the state and fires
transaction.completed. - Your application receives the webhook. If you need the full transaction record, call the status endpoint.
Client integration guidance
Persist the reference
When the API returns atransactionId, store it immediately. This is the correlation key between your system and the Zeam platform. All subsequent webhook events and status queries use this ID.
Handle eventual consistency
Your integration should be designed around the fact that the final state arrives later:- Do not block on the initial response. Accept the tracking ID and return control to your user.
- React to webhooks. Update your internal records when state-change events arrive.
- Use the status endpoint as a fallback. If you suspect a missed webhook, poll the status endpoint to reconcile.
Deduplicate events
Webhook deliveries may be retried if your endpoint was temporarily unavailable. Store theevent_id from each delivery and skip events you have already processed:
Verify signatures
Always verify thex-zeam-signature header before trusting the payload. An unverified webhook could be a replay attack or a forged request. See Webhooks for verification code in Go, TypeScript, and Dart.
Fetch full details on demand
Webhook payloads include enough context to identify the transaction and its new state, but they deliberately exclude unnecessary sensitive data. If you need the full transaction record (amounts, beneficiary details, provider metadata), call the status endpoint using theresource_id:
Best practices
Idempotency
Idempotency
Treat every webhook event as potentially duplicated. Use the
event_id as a deduplication key. If your system has already processed an event, acknowledge it with 200 and do nothing.Signature verification
Signature verification
Verify the HMAC-SHA256 signature on every delivery using constant-time comparison. Never skip verification, even in Sandbox mode. Rotate your webhook secret periodically using the secret rotation endpoint.
Fast acknowledgement
Fast acknowledgement
Respond to webhook deliveries within 10 seconds. Do not perform heavy processing in the request handler. Accept the event, queue it for async processing, and return
200 immediately.Retry safety
Retry safety
If your endpoint is unavailable, Zeam retries with exponential backoff. Your processing logic must be safe to run multiple times for the same event. Use database constraints or a deduplication store to enforce this.
Reconciliation
Reconciliation
Periodically reconcile your records against the Zeam API. Fetch transactions by status to catch any events your webhook endpoint may have missed during an outage. The status endpoint is the source of truth.
Eventual consistency
Eventual consistency
Design your user-facing flows around the fact that payment outcomes are not instantaneous. Show pending states in your UI. Do not promise delivery until you receive a
transaction.completed webhook. Handle transaction.failed and transaction.reversed gracefully.
