Skip to main content
Webhooks are Reader’s push channel for clients that aren’t connected when a job finishes. Subscribe an HTTPS endpoint, pick events, and Reader POSTs you a payload the moment they happen.

Creating a webhook

  • url: your HTTPS endpoint
  • name: a label you’ll see in the dashboard
  • events: which events to deliver (see below)
  • secret: optional but strongly recommended. Used to sign every payload. See verification.
  • headers: optional custom headers Reader will include on every delivery (auth tokens, etc.)
The response includes the webhook’s id and echoes the secret back once. Store it now; you won’t see it again. You can create up to 10 webhooks per workspace.

Supported events

Most callers subscribe to job.completed and job.failed. Subscribe to job.page only when you need streaming-style incremental delivery; it can be very chatty on large batches. The session.* events are useful for monitoring browser session usage and costs.

Headers Reader sends

Every delivery includes:
Plus any custom headers you configured on the webhook.

Verifying signatures

Reader signs the delivery with HMAC-SHA256 over a payload of ${timestamp}.${body}, matching Stripe’s pattern. You verify that:
  1. The timestamp is recent (within 5 minutes). This blocks replay attacks.
  2. The HMAC of ${timestamp}.${rawBody} matches the signature Reader sent. This proves integrity and authenticity.
Always use rawBody. If you parse the JSON before hashing, the re-serialized form will almost certainly differ from the bytes Reader signed, and verification will fail. Most web frameworks expose raw body access as an option on the JSON middleware. See Verifying webhooks for Express, FastAPI, and Next.js patterns.

Delivery and retries

  • Timeout: Reader waits up to 10 seconds for your endpoint to respond.
  • Success: any 2xx status.
  • Retries: on non-2xx or timeout, Reader retries with exponential backoff (1s, 4s, 16s), then gives up after 3 total attempts.
  • Dead letters: failed deliveries show up in the webhook’s deliveryStats and are visible in the dashboard.
Make your endpoint idempotent. Reader may deliver the same event twice if your endpoint is slow to respond and Reader retries after a delivery that actually succeeded. Key off X-Reader-Delivery to dedupe.

Disabling and updating

  • PATCH /v1/webhooks/{id}: update URL, events, or toggle active: false
  • DELETE /v1/webhooks/{id}: remove it entirely
Disabled webhooks stop receiving deliveries immediately; you can re-enable them later without losing the secret.

Next