# Endpoints

> An endpoint is a webhook destination. Route addresses or a domain's catch-all to it to receive mail in real time.

An **endpoint** is a webhook destination — a URL Inboundr POSTs to whenever mail
arrives for an address (or catch-all) routed to it. Endpoints own the delivery
settings: the signing secret, custom headers, timeout, and retry budget.

## Creating an endpoint

```bash
curl https://inboundr.net/api/v1/endpoints \
  -H "Authorization: Bearer $INBOUNDR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production handler",
    "url": "https://api.example.com/hooks/inbound",
    "headers": { "X-Team": "growth" },
    "timeoutSeconds": 10,
    "maxAttempts": 5
  }'
```

The response includes a `secret` (prefixed `whsec_`) **shown only once** — store
it to [verify signatures](/webhooks/verifying-signatures).

## Settings

<ParamField body="url" type="string" required>
  The HTTPS (or HTTP) URL to deliver to. Must resolve to a public host — private
  and internal addresses are rejected by an SSRF guard.
</ParamField>

<ParamField body="headers" type="object">
  Up to 10 custom headers sent with every delivery (e.g. an `Authorization`
  header for your own auth). Reserved headers like `Content-Type` and the
  `X-Inboundr-*` set (and the legacy `X-Inbound-*` spellings) can't be overridden.
</ParamField>

<ParamField body="timeoutSeconds" type="number" default="10">
  Per-request timeout, 1–30 seconds. A slow response counts as a failed attempt.
</ParamField>

<ParamField body="maxAttempts" type="number" default="5">
  Total delivery attempts (first + retries), 1–10, before a delivery is marked
  dead.
</ParamField>

## Slack and Discord

Besides a webhook, an endpoint can post a formatted notification straight to a
Slack or Discord channel — pass `"type": "slack"` or `"type": "discord"` when
creating it, with `url` set to that channel's incoming-webhook URL (from
Slack: workspace settings → Incoming Webhooks; from Discord: channel settings
→ Integrations → Webhooks). Delivery, retries, and `timeoutSeconds`/
`maxAttempts` work exactly like a webhook — the only difference is the body:
a Slack/Discord message instead of raw JSON, and no signing (neither platform
verifies one).

## Delivery, signing, and retries

Every delivery is signed with the endpoint's secret and carries these headers:

| Header | Description |
| --- | --- |
| `X-Inboundr-Event` | Always `email.received`. |
| `X-Inboundr-Delivery-Id` | Unique id for this delivery attempt chain. |
| `X-Inboundr-Signature` | `t=<unix>,v1=<hmac-sha256>` — verify with your secret. |

The legacy `X-Inbound-*` spellings are sent alongside these with identical
values, and will be withdrawn once no endpoint depends on them.

Failed deliveries retry with exponential backoff (1m → 5m → 30m → 2h) until they
succeed or exhaust `maxAttempts`, after which they're marked **dead** and
surfaced in the console. See [Retries & delivery](/webhooks/retries).

<Warning>
  Redirects are **not** followed — a `3xx` response is recorded as a failed
  attempt. Point the endpoint at the final URL.
</Warning>

<CardGroup cols={2}>
  <Card title="Verify signatures" icon="shield-check" href="/webhooks/verifying-signatures">
    Validate the HMAC signature on every delivery.
  </Card>
  <Card title="Endpoints API" icon="webhook" href="/api-reference/endpoints/list">
    Create and list endpoints.
  </Card>
</CardGroup>
