Skip to content

Webhooks

Being told what happens to mail, rather than asking.

What arrives

A POST with a JSON body, and three headers:

Header
X-Mailroom-EventThe event name
X-Mailroom-Signaturet=<unix seconds>,v1=<hex>
X-Mailroom-Webhook-IdWhich endpoint this came from

The body is always the same envelope:

json
{
  "id": "whd_9f2c…",
  "object": "event",
  "type": "mail.received",
  "created_at": "2026-09-21T09:58:02.000Z",
  "data": { "email": { "…": "…" } }
}

id is also the delivery id, so a repeat — a retry after your endpoint timed out, or a replay you triggered — can be recognised and ignored.

Setting one up

Two ways, and they do the same thing:

Either way the reply carries the signing secret, shown once and never again.

What to do in a handler

  1. Read the raw body as text. Not a parsed object.
  2. Verify the signature against it.
  3. Answer 2xx quickly — do the slow part after, or on a queue.
  4. Ignore an id you have already seen.

A handler that takes ten seconds is a handler that gets retried, because the timeout is ten seconds.

Next

Released under the MIT Licence.