Real-Time APIs · Webhooks

Receiving Webhooks Reliably

Verify, persist, acknowledge fast and process asynchronously.

As a consumer: verify the signature over the raw body, check the timestamp tolerance, persist the event (deduplicated by event ID), return 2xx quickly (within a few seconds), and process asynchronously. Handle duplicates and out-of-order delivery (re-fetch the resource or compare versions). Monitor failures — providers disable endpoints that fail for days.

Receiver checklist

Step Why
Verify signature on raw body Authenticity and integrity
Check timestamp tolerance Replay protection
Persist + dedupe by event id At-least-once delivery
Respond 2xx fast Avoid provider timeouts and retries
Process async, idempotently Robustness, ordering independence
@app.post("/hooks/acme")
async def acme_webhook(request: Request, db: DB):
    body = await request.body()
    verify_standard_webhook(body, request.headers, secret=settings.acme_secret)   # raises on bad sig/timestamp
    event = json.loads(body)
    inserted = await db.execute(
        "INSERT INTO inbound_events (id, type, payload) VALUES ($1, $2, $3) ON CONFLICT (id) DO NOTHING",
        request.headers["webhook-id"], event["type"], body.decode())
    if inserted == "INSERT 0 1":
        await queue.enqueue("process_acme_event", request.headers["webhook-id"])
    return Response(status_code=204)

Common pitfalls

  • Parsing/re-serializing JSON before verification.
  • Slow synchronous processing causing retries.
  • Assuming events arrive in order.

Key points

  • Verify, persist, ack, process
  • Dedupe by event id
  • Tolerate reordering

Further reading: Stripe: Webhooks best practices

Practice questions

Why should a webhook receiver respond before processing the event?

Answer

Providers time out after a few seconds and retry; slow processing causes duplicate deliveries and possibly endpoint disabling.

How can consumers handle out-of-order webhook events?

Answer

Re-fetch the current resource state from the API, or compare a version/timestamp and ignore events older than what's stored.

Open in the app to mark lessons complete, take notes and track your progress.