/ Payouts v1 Dashboard ↗

Webhooks

We tell you when a payout changes state, so you do not have to poll. Webhooks are the nudge; the API is the truth. Build reconciliation against GET /payments/organizations/{orgId}/orders/{payoutId} and treat a delivery as a reason to look, never as the record itself.

Signing: Standard Webhooks#

We sign with Standard Webhooks, the same scheme Svix popularised — so you can verify with an off-the-shelf library in your language instead of hand-rolling against a format only we speak.

Three headers arrive with every delivery:

Header Meaning
svix-id The delivery id. Idempotency key — dedupe on this.
svix-timestamp Unix seconds. Reject anything far from your own clock.
svix-signature v1,<base64> — a space-separated list, so a rotation can ship two valid signatures on one request

The signed content is the delivery id, the timestamp and the raw body, joined by dots:

code
signedContent = `${svix-id}.${svix-timestamp}.${rawBody}`
signature     = base64(HMAC_SHA256(base64decode(secret minus "whsec_"), signedContent))

Verify over the bytes you received, before any JSON parsing. Re-serializing the body changes it — a reordered key or a different float formatting produces a signature mismatch on a delivery that was perfectly valid.

Your secret is issued with the endpoint, in the conventional whsec_ form. It is shown once.

Events#

Six event types, and they are the canonical payout states:

Event Meaning Terminal
payout.pending Accepted, not yet moving
payout.processing On its way
payout.completed The beneficiary has been paid; a later bank return is still possible
payout.failed It failed; inspect fundsReturned before changing your ledger
payout.returned It settled and the receiving bank later returned it
payout.canceled Stopped before it moved

The rail is never named. No provider's own status words appear in any payload, which is what lets us re-route your organization to a different payment network without your ledger changing. If you find yourself branching on something rail-shaped, you are reading a field you should not depend on.

New event types are a backwards-compatible change. Ignore ones you do not recognize rather than throwing — see Versioning.

Delivery#

We consider a delivery successful on any 2xx. Anything else — including a timeout — is retried on a fixed ladder:

Attempt Sent
1 Immediately
2 +1 minute
3 +5 minutes
4 +30 minutes
5 +2 hours
6 +6 hours

Six attempts over roughly 8.6 hours, after which the delivery is left failed and we stop. It is not lost: it stays in the delivery log, and you can replay it.

Return 2xx fast, and do the work afterwards. A receiver that finishes its own processing before responding is a receiver that times out under load and gets retried, which is how one slow database write becomes a duplicate.

Ordering, duplicates, and the two rules that follow#

Deliveries are at-least-once and not ordered. Both are consequences of retrying, and both are ordinary; every webhook system worth trusting has them.

  1. Dedupe on svix-id. The same event may arrive twice — a retry after a

timeout that actually succeeded is the common case.

  1. Never move a payout backwards. A delayed payout.processing can land

after payout.completed; ignore it. The one forward transition from completed is payout.returned, whose body carries status: failed and failureCode: returned_by_bank. Only failed, returned, and canceled are terminal.

Managing endpoints#

GET /organizations/{orgId}/webhook-endpoints List
POST /organizations/{orgId}/webhook-endpoints Register; returns the signing secret once
DELETE /organizations/{orgId}/webhook-endpoints/{id} Remove
POST /organizations/{orgId}/webhook-endpoints/{id}/enabled Pause or resume without losing the secret
GET /organizations/{orgId}/webhook-endpoints/{id}/deliveries Recent attempts, with status and next retry
POST /organizations/{orgId}/webhook-endpoints/{id}/deliveries/{deliveryId}/replay Re-fire one, with a fresh retry ladder

The delivery log is there for the integration you are debugging at 2am: it shows what we sent, what came back, how many attempts remain and when the next one is due. Reach for it before you reach for us.

These management routes use a human dashboard session and require a signer role. Partner API keys can receive and verify deliveries, but cannot create, pause, replay, or repoint live webhook endpoints.

Before you go live#