Webhooks reference
Events, payload, signature headers, the 1m→12h retry ladder and idempotency rules for webhook consumers.
Everything about receiving ZeroKYC Pay events: the event catalogue, payload shape, signature headers, the retry ladder and idempotency rules.
Events
| Event | Fires when |
|---|---|
payment.detected | A transaction matching the invoice is seen (mempool or early confirmations) |
payment.confirmed | The required confirmations are reached — the "ship the product" signal |
payment.underpaid | Observed amount < required − amount_tolerance; your decision |
invoice.expired | TTL elapsed without a valid payment |
invoice.canceled | Invoice canceled before payment |
payout.sent / payout.failed | Transit sweep to your payout address succeeded / failed |
Multi-variant invoices (payment_currency=any) confirm on the first valid payment; remaining options close automatically.
Payload
{
"id": "evt_5c1a...",
"type": "payment.confirmed",
"created_at": "2026-09-06T14:02:33Z",
"data": {
"invoice_id": "inv_9f2k...",
"order_id": "order-1042",
"asset": "TON",
"network": "ton",
"amount_paid": "9.81",
"paid_amount_usd": "49.00",
"tx_hash": "9d24...",
"confirmations": 1,
"status": "confirmed"
}
}idis globally unique per event — store it and deduplicate.order_idechoes whatever you sent at creation; that's your join key.- Overpayments confirm normally:
amount_paidis the observed truth.
Signature
Every delivery includes:
X-ZKP-Signature: t=<unix seconds>,v1=<hex hmac-sha256>
Signed over {timestamp}.{raw_body} with your endpoint secret. Verify before trusting — full Node/PHP/Python snippets in HMAC verification. The timestamp window is 5 minutes.
Delivery and retries
| Attempt | Delay |
|---|---|
| 1 | immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 12 hours → then failed |
- A delivery counts as successful on any
2xxresponse within a few seconds. - After the ladder exhausts, the event is marked
failed; you can retry manually from the console (Webhooks → delivery log) or per-invoice (Invoices → retry webhook). - Configure and rotate the endpoint in Webhooks: a test-event button sends a signed
pingyou can verify end-to-end.
Idempotency rules for consumers
- Store
event.idand skip duplicates — at-least-once delivery means the same event can arrive more than once. - Treat webhooks as hints, not as the source of truth:
GET /v1/invoices/{id}always gives the authoritative state. - A rescan job re-checks all pending/detecting invoices every 10 minutes, so missed chain events self-heal — you may receive a
payment.confirmednoticeably later than the transaction. - React to
payment.confirmedas the fulfillment trigger; usepayment.detectedonly to show the buyer early feedback.