Skip to content
ZeroKYC Pay

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

EventFires when
payment.detectedA transaction matching the invoice is seen (mempool or early confirmations)
payment.confirmedThe required confirmations are reached — the "ship the product" signal
payment.underpaidObserved amount < required − amount_tolerance; your decision
invoice.expiredTTL elapsed without a valid payment
invoice.canceledInvoice canceled before payment
payout.sent / payout.failedTransit 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"
}
}
  • id is globally unique per event — store it and deduplicate.
  • order_id echoes whatever you sent at creation; that's your join key.
  • Overpayments confirm normally: amount_paid is 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

AttemptDelay
1immediate
21 minute
35 minutes
430 minutes
52 hours
612 hours → then failed
  • A delivery counts as successful on any 2xx response 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 ping you can verify end-to-end.

Idempotency rules for consumers

  1. Store event.id and skip duplicates — at-least-once delivery means the same event can arrive more than once.
  2. Treat webhooks as hints, not as the source of truth: GET /v1/invoices/{id} always gives the authoritative state.
  3. A rescan job re-checks all pending/detecting invoices every 10 minutes, so missed chain events self-heal — you may receive a payment.confirmed noticeably later than the transaction.
  4. React to payment.confirmed as the fulfillment trigger; use payment.detected only to show the buyer early feedback.