# Webhooks overview

> The email.received event — its payload, headers, and how to respond.

When mail arrives for an address (or catch-all) routed to an
[endpoint](/concepts/endpoints), Inboundr POSTs a signed **`email.received`**
event to the endpoint's URL.

## Request headers

| Header | Value |
| --- | --- |
| `Content-Type` | `application/json` |
| `User-Agent` | `inboundr-webhooks/1.0` |
| `X-Inboundr-Event` | `email.received` |
| `X-Inboundr-Delivery-Id` | Unique id for this delivery. |
| `X-Inboundr-Signature` | `t=<unix>,v1=<hmac-sha256>` — [verify it](/webhooks/verifying-signatures). |

<Note>
  These headers were originally spelled `X-Inbound-*`. Every delivery currently
  carries **both** spellings with identical values, so existing handlers keep
  working. New handlers should read `X-Inboundr-*`; the older names will be
  withdrawn once no endpoint depends on them.
</Note>

Any [custom headers](/concepts/endpoints) you configured on the endpoint are
also included.

## Payload

```json
{
  "event": "email.received",
  "email": {
    "id": "em_abc123",
    "threadId": "thr_xyz789",
    "messageId": "<CAEabc...@mail.gmail.com>",
    "from": "customer@example.com",
    "to": ["support@yourdomain.com"],
    "cc": [],
    "subject": "Can you help?",
    "text": "Hi there…",
    "html": "<p>Hi there…</p>",
    "attachments": [
      { "filename": "invoice.pdf", "contentType": "application/pdf", "size": 48210 }
    ],
    "verdicts": { "spam": "PASS", "spf": "PASS", "dkim": "PASS" },
    "receivedAt": "2026-07-20T10:30:00.000Z"
  }
}
```

<ResponseField name="event" type="string">
  Always `email.received`.
</ResponseField>
<ResponseField name="email.id" type="string">
  The stored email id (`em_…`). Use it with the
  [emails API](/api-reference/emails/get) to fetch attachments or full context.
</ResponseField>
<ResponseField name="email.threadId" type="string">
  Conversation id. Fetch the rest of the thread via
  [`GET /v1/threads/{id}`](/api-reference/threads/get).
</ResponseField>
<ResponseField name="email.attachments" type="array">
  Attachment metadata only (filename, contentType, size). Download content via
  the [attachments endpoint](/api-reference/attachments/download).
</ResponseField>
<ResponseField name="email.verdicts" type="object">
  `spam`, `spf`, and `dkim` authentication results.
</ResponseField>

## Responding

Return any `2xx` status to acknowledge receipt. Anything else — including a
`3xx` redirect or a timeout — is treated as a failed attempt and
[retried](/webhooks/retries).

<Tip>
  Acknowledge fast. Do heavy processing asynchronously and return `200`
  immediately so you stay within the endpoint's timeout (default 10s).
</Tip>
