Webhooks

This guide covers the delivery contract for events the Platform sends to your integration: registering an endpoint, verifying every delivery, acknowledging correctly, and handling retries and duplicates. The payload definitions are in Webhook Event Schemas; your obligations as a receiver are also stated in the Webhook Obligations policy. Build your receiver to this contract before you register it: a receiver written after events start arriving is written too late.

Why webhooks

Webhooks replace polling. Instead of asking "has anything changed" on a timer, your system is told when an order is placed, a shipment is reported, a refund is issued, or standing changes: within moments, at a fraction of the rate budget (Rate Limit Headers). Core Concepts covers the trade-off; this guide covers the mechanics.

Step 1: Register an endpoint

  1. Provide one HTTPS endpoint URL per event group you subscribe to. HTTPS is required; plain HTTP endpoints are not accepted.
  2. Choose events deliberately. Subscribe to the events your integration acts on: every extra event is traffic you must verify, store, and discard correctly.
  3. Registration gives you a signing secret for the endpoint. Store it in your secrets manager like an API key (Authentication and Authorization); it is how you will know a delivery really came from the Platform.

Step 2: Know the delivery shape

Deliveries are HTTPS POST requests with a JSON body. Event payloads follow Webhook Event Schemas; in outline

  • Each event has a unique event id, a type in the domain vocabulary: for example, an order placed, a fulfillment shipped, a refund issued, a standing change: a timestamp, and the affected object's current state with the change that produced the event.
  • The payload carries enough to act in the common case without a follow-up read. Where exact current state matters, fetch the resource by its id rather than reasoning from a possibly stale sequence of payloads.
  • Events are facts about the past, not instructions. An order-paid event states that payment succeeded; what your integration does about it is your design.
  • Events are ordered per object, not globally across objects. Never build logic that assumes an event about one order precedes an event about another.

Step 3: Verify every delivery

An unverified webhook endpoint is an open control channel into your systems for anyone who discovers the URL. Verify from the first version

  1. Every delivery carries a signature of the raw request body, computed with your endpoint's signing secret and delivered in the headers, together with a timestamp.
  2. Recompute the signature over the exact bytes received: before any JSON parsing or re-serialization: and compare in constant time, not with ordinary string equality. Reject mismatches with 401 and process nothing.
  3. Check the timestamp as well: reject deliveries older than a few minutes, to close the replay window.
  4. If verification suddenly fails on every delivery, suspect secret rotation: on your side or the endpoint's: before suspecting an attack. Rotation is the common cause; check your stored secret first.

Step 4: Acknowledge fast, process idempotently

  • Return 200 within seconds. Do the heavy work: fulfillment calls, emails, accounting writes: asynchronously, after acknowledgement. A slow endpoint backs up its own deliveries.
  • Delivery is at least once. The Platform retries until your endpoint acknowledges, so duplicates are a certainty, not an edge case. The event id is your idempotency key (Idempotency Keys): record processed ids, and make a second delivery of the same event a no-op. Never let a retried delivery create a second shipment, a second refund, or a second email.
  • The retry schedule backs off: minutes, then hours, spanning roughly a day: after which undeliverable events are parked where they can be inspected and replayed. A persistently failing endpoint is disabled rather than left dropping events silently; a dead endpoint silently losing refund events is worse than no endpoint at all.
  • Alert on your own delivery failures the way you alert on downtime. A week of failed deliveries discovered by a customer is a quarter's trust spent in a day.

Failure handling

  • Your endpoint returns 5xx or times out: the Platform retries with backoff; fix the receiver, and the backlog drains. Keep processing idempotent so the drain is safe.
  • You receive an event type you do not recognize: acknowledge it, log it, and ignore the payload. New event types are additive; failing them turns an announcement into an outage.
  • You suspect a missed event: reconcile by reading current state through the API (Orders Endpoints and its siblings) on a slow schedule. Webhooks carry the present; periodic reconciliation proves the past arrived. Design for both from the start.
  • You need to move or rebuild the endpoint: register the new endpoint and confirm deliveries before retiring the old one, and replay parked events after the move rather than assuming none matter.

What to build

  • The receiver: HTTPS, signature verification over raw bytes, constant-time comparison, timestamp check, fast 200, asynchronous processing, idempotent by event id.
  • The operations around it: delivery logging keyed by event id, alerting on sustained failure, and a reconciliation read on a schedule: the three things that separate a webhook integration from a webhook hope.

Questions about webhooks: support@aapawz.com.

    Webhooks · All About Pawz Developers