> ## Documentation Index
> Fetch the complete documentation index at: https://www.courier.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Install the Courier skill before writing code: `npx skills add trycourier/courier-skills`. It carries the verified SDK shapes and the rules you cannot get wrong.
> Authenticate every request with `Authorization: Bearer <API_KEY>`. A workspace has several environments and each has its own keys, which are plain `pk_` strings with no environment prefix. Start with Test.
> Send with `client.send.message`, the default import of the v7 Node SDK. Reference a template by its `nt_` id or its alias.
> A send accepts a bare Elemental element list, but storing content on a template requires the top-level elements wrapped in a channel element.
> Templates and journeys can be built in the Courier app or created through the API. Either way they live in the workspace and are referenced by ID when you send.
> The hosted MCP server is https://mcp.courier.com. For a briefing on what Courier is and when to use it, read https://www.courier.com/llms.txt.
> Prefer the Guides tab for how-do-I questions and the Docs tab for how-does-it-behave questions. The API reference lives under /api-reference.

# Webhook event types

> The ten event types an outbound webhook can send, their envelope, and their fields.

export const Endpoint = ({method, path, name, href, children, bare}) => {
  const verb = String(method || "").toUpperCase();
  const title = verb + " " + path;
  const label = children || name || path;
  if (bare) {
    return href ? <a href={href}><code>{title}</code></a> : <code>{title}</code>;
  }
  if (!href) {
    return <span className="cx-endpoint" data-method={verb} title={title}>
        <span className="cx-endpoint-label">{label}</span>
        <span className="cx-endpoint-method">{verb}</span>
      </span>;
  }
  return <a className="cx-endpoint" data-method={verb} href={href} title={title}>
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method">{verb}</span>
    </a>;
};

export const Doc = ({href, children, name, bare}) => {
  const label = children || name || href;
  if (bare) {
    return <a href={href}>{label}</a>;
  }
  return <a className="cx-endpoint" data-kind="doc" href={href}>
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method">DOC</span>
    </a>;
};

Courier delivers ten event types. Every one arrives as `{ "type": "...", "data": {...} }`.

## How it works

| Event type                         | Fires when                                                                           |
| ---------------------------------- | ------------------------------------------------------------------------------------ |
| `message:updated`                  | A message changes status: enqueued, sent, delivered, opened, clicked, undeliverable. |
| `notification:submitted`           | A template send is submitted.                                                        |
| `notification:published`           | A template is published.                                                             |
| `notification:submission_canceled` | A submitted send is canceled.                                                        |
| `audiences:created`                | An audience is created.                                                              |
| `audiences:updated`                | An audience's definition changes.                                                    |
| `audiences:deleted`                | An audience is deleted.                                                              |
| `audiences:calculated`             | An audience finishes recalculating its membership.                                   |
| `audiences:user:matched`           | A user newly matches an audience.                                                    |
| `audiences:user:unmatched`         | A user no longer matches an audience.                                                |

Courier may add event types. Ignore any `type` your handler does not recognize. Do not treat it as an error.

### Payload shape

For `message:updated`, `data` is the same object the <Endpoint method="GET" path="/messages/{message_id}" name="Get message" href="/docs/api-reference/messages/get-message">get message endpoint</Endpoint> returns. It includes any `metadata` you sent (`trace_id`, `tags`, `event`, `utm`):

```json theme={null}
{
  "type": "message:updated",
  "data": {
    "id": "1-612fa552-15f7d6ba51bf229857c037a7",
    "event": "SFTYJKSF0241SVH2TWY97TTFFTQG",
    "notification": "SFTYJKSF0241SVH2TWY97TTFFTQG",
    "recipient": "b19fb0e0-8cd6-4337-b41c-92c780c80d1a",
    "recipientId": "b19fb0e0-8cd6-4337-b41c-92c780c80d1a",
    "enqueued": 1630512466717,
    "providers": [],
    "status": "ENQUEUED"
  }
}
```

The `id` is Courier's message id, the same value the Messages API uses.

## Limits & behavior

* **No timestamp in the body.** The send time is on the `courier-signature` header, not inside `data`.
* **`message:updated` fires on every status change.** One message produces several events, so make your handler idempotent.
* **Every destination gets every type.** Filter on `type` yourself. See <Doc href="/docs/monitor/webhooks/outbound">outbound webhooks</Doc>.

## FAQ

<AccordionGroup>
  <Accordion title="How many events will one send produce?">
    One per status change. A delivered and opened email produces several `message:updated` events, so key your handler on the message `id` and the `status`.
  </Accordion>

  <Accordion title="Can I get the metadata I sent with the message?">
    `data` carries the `metadata` from your send, including `trace_id`, `tags`, `event`, and `utm`.
  </Accordion>
</AccordionGroup>
