Platform ToolsWebhooks

Webhooks

Register an endpoint, understand the delivery guarantees, and debug what was sent.

A webhook is what we send you. We never use the word for anything inbound.

Events are emitted transactionally with the state change they announce, so an event exists if and only if the change committed. Delivery is at least once, signed, retried with backoff, and inspectable in a delivery portal.

Three pages cover them:

Prerequisites

  • An HTTPS endpoint that responds quickly, before it does any work.
  • Somewhere to store processed event ids, for deduplication.
  • A place to keep the endpoint's signing secret, per environment.

Registering an endpoint

curl -s $BASE/api/webhooks \
  -H "Api-Key: $KEY" -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://yourapp.example/rasto/webhook"}'
{
  "id": "whk_033y9PqRsTuVwXyZaBcDe",
  "object": "webhook",
  "url": "https://yourapp.example/rasto/webhook",
  "event_kinds": ["*"]
}
  • Endpoints must be HTTPS.
  • Pass event_kinds to subscribe to a subset. Omit it for everything.
  • Endpoints are per environment. Register in sandbox and live separately, and store the two secrets separately.
  • GET /api/webhooks lists them. DELETE /api/webhooks/{webhook_id} removes one.
  • The whk_ id is ours and stable. It survives any change of delivery infrastructure on our side, so it is safe to store against your own records.

Sandbox webhooks are real: delivered and signed exactly like live ones, so a consumer you build against sandbox is production ready as is.

Delivery guarantees

GuaranteeWhat it means for your code
At least onceDeduplicate by event id. A retry reuses the same id
Retried with backoffA non-2xx or a timeout is retried. Slow handlers cause duplicates
Ordered by sequence, not arrivalApply events in sequence order to make your projection deterministic
Emitted transactionallyYou never receive an event for something that rolled back, and never miss one for something that did not
SignedVerify before parsing. See Verifying signatures

Processing

Verify the signature

Against the raw request body, before parsing it. Reject anything that does not verify, and anything whose timestamp is outside your tolerance window.

Acknowledge fast

Return 2xx as soon as the payload is stored, and process asynchronously. Every second your handler spends working is a second closer to a retry you did not need.

Deduplicate by event id

Retries and replays reuse the same id. Keep a processed-ids table and skip anything you have seen.

Order by sequence

Retries and parallel delivery reorder arrivals. sequence is a monotonically increasing per-partner counter, and it is the ordering that matters.

Treat events as signals, state as truth

An event tells you something changed. For decisions that matter, re-read the resource with a GET rather than acting on a payload that may have been sitting in a retry queue.

Debugging and replay

  • GET /api/webhooks/portal returns a link to the delivery portal: every attempt, response codes, response bodies, and manual retry. It is the first place to look when a webhook "never arrived", and it is where your endpoint's signing secret is shown.
  • GET /api/webhook_events is the event history, everything we emitted whether delivered or not, paginated and carrying sequence and published_at.
  • POST /api/webhook_events/{event_id}/replay re-delivers one event. The envelope carries the same id plus "replayed": true, so your dedupe still recognizes it as something you have already processed.

Recovering from downtime

Your endpoint being down does not lose events. It delays them.

  1. Deliveries retry with backoff automatically.
  2. GET /api/webhook_events lists everything, so page through anything newer than your last processed sequence to backfill.
  3. Replay individual events if you would rather re-run your handler than backfill by hand.

See Reconciliation for the full recovery procedure.