Skip to main content

At-least-once delivery

Use the id 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

AttemptDelay from previous
1Immediate (≤ 5 seconds after the event)
2+1 second
3+30 seconds
4+5 minutes
After attempt 4Marked failed. Admins can retry manually from our partner detail page.
Each attempt has a 10-second HTTP timeout. Anything else than a 2xx response, a network error, or a timeout counts as a failure.

Concurrency

Webhooks are dispatched in parallel. You may receive events out of createdAt 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 the x-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 and failedAt, 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:
  1. 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.
  2. 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.