Docs

Integrating

Webhooks

Signing, verification, the retry schedule, replay, and what happens to a dead letter.

An endpoint subscribes to event types and receives the envelope every event on the spine carries: id, type, occurred_at, account_id and data. The types are in the event catalogue.

Verify the signature before you parse the body

Each delivery carries a timestamp and an HMAC over timestamp.body using your endpoint's signing secret. Compare with a constant-time comparison and reject a timestamp outside your tolerance window — without the timestamp check a captured delivery can be replayed at you forever.

Read the raw body. A framework that parses JSON and re-serialises it changes bytes, and a signature over re-serialised JSON verifies at random.

Retries

A delivery that does not answer 2xx is retried on a fixed schedule, in minutes:

1, 5, 15, 60, 180, 360, 720, 1440, 2880, 4320

That is 10 attempts in total, spread over several days. Delays exist only between attempts; the last failure exhausts the schedule rather than scheduling another one.

Answer fast, work later

Return 2xx as soon as you have stored the event. Doing the work inline means a slow consumer looks like a failing one, and a failing one gets retried — which makes it slower.

Duplicates are expected

At-least-once delivery means the same id can arrive twice: a retry after your 2xx was lost, or a replay you asked for. Deduplicate on the event id.

Dead letters

After the 10th failure the delivery is dead-lettered rather than dropped. The console shows every attempt with its response code and timing, and a dead letter can be replayed once the endpoint is fixed. An endpoint that fails persistently is disabled and the account is notified, so a URL that stopped existing does not quietly become a hole in your event history.

Local development

Point an endpoint at a tunnel, or run the Node SDK CLI from this repository (the package is private and not on the public registry yet):

agentisend webhooks listen --secret whsec_… --forward-to http://localhost:3000/webhooks

The signature headers are forwarded unchanged, byte for byte, so local verification uses the same secret as production.