Reference
Webhooks
How you tell us what happened to a payout.
You send one webhook per payout status change. Webhooks are authenticated by a signature over the raw request body, not by cookies or tokens.
The event
{
"eventId": "evt_demo_4b1a9e",
"partnerRef": "pr_demo_7c91d2",
"status": "completed",
"occurredAt": "2026-10-19T14:32:11Z"
}On a failure, add a failureCode from the failure code list on the Errors page.
| Field | Meaning |
|---|---|
eventId | Your unique id for this event. We store it to remove duplicates and stop replays. |
partnerRef | The reference you returned when the payout was created. |
status | submitted, pending, completed, failed or returned. |
failureCode | Present only on failed and returned. |
occurredAt | When the status changed, in UTC. |
The signature
Sign the exact bytes of the body with HMAC-SHA256 using the shared secret from your onboarding pack, hex-encoded, and send it in the header named in your pack. The simulated environment uses x-sandbox-signature.
import { createHmac } from "node:crypto";
// raw is the body exactly as you will send it, before any parsing.
const signature = createHmac("sha256", process.env.WEBHOOK_SECRET)
.update(raw)
.digest("hex");How we treat it
- We verify over the raw body, in constant time, before we read any field.
- A missing signature or secret is a rejection, never a pass. We answer 401 invalid_signature.
- A body we cannot parse gets 400 invalid_event.
- A repeated eventId is accepted and ignored. Retrying is always safe.
- An event can only move a payout forward. Anything else is ignored and raised for review.
Delivery
Treat any answer other than 2xx as not delivered, and retry with the same eventId and the same body. Use increasing delays between attempts. Because duplicates are harmless, retry rather than guess.