Webhooks overview

HMAC-signed, timestamp-bound webhooks fire on every state change, with retries and backoff — so you never poll.

Instead of polling, subscribe to webhooks. Hannu delivers a signed event on every state change, with retries and a full resource snapshot — so your handler never has to fetch to find out what happened.

Delivery shape

Every delivery is a JSON body with the event name and the full resource:

JSON
{
  "id": "evt_3b9",
  "type": "task.approved",
  "data": { "id": "task_8f21", "state": "approved" }
}
  • id — a stable event id; use it to make your handler idempotent.
  • type — the event name (see the event catalogue).
  • data — the full resource snapshot at the time of the event.

Guarantees

  • Signed, always. Deliveries carry an HMAC signature over the timestamp and body. A delivery is never sent unsigned. See Signature verification.
  • Retried with backoff. Failed deliveries retry on a schedule (1, 5, 30, 120, 600 minutes), then dead-letter and raise an internal alert.
  • Idempotent on your side. Because retries can duplicate, dedupe on id.
Return 2xx fast

Acknowledge with a 2xx as soon as you've stored the event, then process asynchronously. Slow handlers trigger retries.

Managing subscriptions

Webhook endpoints and their signing secrets are managed in the dashboard today — there's no public API for subscription CRUD yet. Create an endpoint there, copy its whsec_… secret, and verify every delivery against it.

Next