Webhooks & callbacks
How delivery, signing, and retries work — so you don't have to poll.
If your partner record has a callbackUrl configured, the gateway POSTs you a notification the
moment a transaction reaches a terminal status — you don't need to poll
GET /api/v1/transactions/{orderId} unless you want to.
Configuring your callback
Set your callbackUrl and (optionally) a callbackSecret via the Partner Dashboard's Webhooks
page, or PUT /api/v1/partner/webhook. A freshly-generated secret is returned exactly once —
store it immediately; it's never shown again (the gateway only ever keeps a hash of it... same
"shown once" convention as a credential's AppKey).
Payload
{
"transactionId": "0192b7a4-6f1e-7c3a-9d2b-4e5f6a7b8c9d",
"partnerOrderId": "deposit-2026-10-10-001",
"status": "GW-01-SUCCESS",
"statusMessage": null
}status is the same GW-xxx code you'd get back from a status poll — see the
error/status reference.
Verifying the signature
If you configured a callbackSecret, every delivery carries:
X-Signature: <hex-encoded HMAC-SHA256, lowercase>signature = lowercase_hex( HMAC_SHA256(
key: your callbackSecret,
message: the exact raw request body bytes
))Unlike the inbound request signature, there's no timestamp component here — the gateway itself controls when it sends, so there's no replay window to protect against on an outbound call it initiated.
import hashlib
import hmac
expected = hmac.new(callback_secret.encode(), request_body_bytes, hashlib.sha256).hexdigest()
is_valid = hmac.compare_digest(expected, request.headers["X-Signature"])If you didn't configure a callbackSecret, deliveries arrive unsigned — fine for local testing,
not recommended for production.
Delivery, retries, and dead-lettering
Your endpoint has 10 seconds to respond with any 2xx status. Anything else — a non-2xx
status, a timeout, a connection failure — counts as a failed attempt and schedules a retry on a
fixed backoff:
| Attempt | Delay before this attempt |
|---|---|
| 1 | immediately |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 6 hours |
| 7 | 24 hours |
After attempt 7 fails, delivery stops — this is the dead letter; there's no separate notification or alert. An admin (or, for your own partner's deliveries, you) can inspect the delivery history and manually trigger a fresh redelivery (a new attempt 1) once your endpoint is fixed. One failing delivery attempt never blocks any other delivery — each is isolated.
Testing your handler without a real transaction
In Sandbox, you can re-fire the callback for an
already-resolved transaction on demand, as many times as you like, without re-running a whole
create-and-wait flow each time.
