At-least-once delivery
Use theid field on the envelope for idempotency. If the same event
arrives twice, treat the second as a no-op. We retry on transient failures,
so duplicates are expected but rare.
Retry schedule
| Attempt | Delay from previous |
|---|---|
| 1 | Immediate (≤ 5 seconds after the event) |
| 2 | +1 second |
| 3 | +30 seconds |
| 4 | +5 minutes |
| After attempt 4 | Marked failed. Admins can retry manually from our partner detail page. |
Concurrency
Webhooks are dispatched in parallel. You may receive events out ofcreatedAt order. If ordering matters for your processing, sort on your
side before applying.
Receiver checklist
HTTPS endpoint, public, ideally idle latency ≤ 200 ms.
Verify the signature before parsing or trusting the body.
Return 2xx as soon as the event is enqueued — don’t do heavy work in-band.
Dedupe on
event.id — we will retry on transient failure.Treat unknown
event.type values as a no-op so you don’t 500 when we add new ones.What we send on each retry
Each retry signs a fresh timestamp, so thex-signature header
changes on every attempt — don’t try to dedupe by signature, only by
event.id. The body bytes stay identical.
Manual retry
If an event ages out of automatic retries (4 attempts failed), our admins can re-arm it from the partner detail page. This resets the attempt counter andfailedAt, and the dispatcher picks it up on the next tick. Tell us
the event.id (we have it in our logs too) and we can re-queue it for you.
Disabling a webhook
There is no “pause” toggle today. If you need to halt deliveries (e.g. your endpoint is down for planned maintenance), the practical options are:- Have your endpoint return HTTP 503 for the duration. We’ll retry up to 4 times per event, then mark them failed; admins can re-queue after.
- Ask us to disable your partner record temporarily. New events will still
be recorded but not dispatched, and JWT verification will reject your
tokens with
partner_disabled(403) for the duration.