This page covers payout callbacks. Payin callbacks use the same URL, the
same headers and the same signature scheme — so the verification code below works unchanged — but
they carry a different body and, unlike payouts, they are retried. Read that page too if you
take payments.
When we send a callback
We send a callback whenever a live transaction reaches one of these final states:
We do not send callbacks for in-progress states (
pending, pending_approval, processing) — poll getPayoutStatus to observe those.
Payout callbacks are not sent for sandbox transactions. Payin
callbacks are — so sandbox is where you can exercise
your handler before real money moves.
Registering a URL
Set your Callback URL in Developer Tools. Requirements:https://only- Must resolve to a public IP (private, loopback, link-local, and cloud-metadata addresses are rejected — at save time and again at delivery time)
The request we send
Verify the signature
Recompute the HMAC and compare in constant time. Reject anything stale or mismatched.Idempotency
Every callback carries a uniquex-pontis-event-id. We do not currently retry, but you should still:
- Store recent event IDs (e.g. last 24 hours)
- Reject duplicates silently with a
200 OK - Always respond with 2xx even on duplicates — non-2xx is logged as a delivery failure
Delivery failures
If your endpoint returns non-2xx or times out (10 s), the failure is logged on our side and the callback is not retried. Fall back to pollinggetPayoutStatus if you suspect a missed callback.
Local testing
While you’re developing, point the callback URL at any publicly reachable HTTPS endpoint — a request-bin service or an HTTPS tunnel in front of your local server both work. We do not accept private IPs orlocalhost URLs — the address must resolve to a public endpoint over HTTPS.