> ## 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.

# Courier API Reference

> Courier's REST API for sending notifications and managing profiles, preferences, templates, and brands across email, SMS, push, chat, and in-app.

The Courier API is a single REST API for everything Courier does: send messages, build journeys, manage templates and brands, and read delivery logs. Anything you can do in the dashboard, you can do through the API.

|                           |                                                   |
| ------------------------- | ------------------------------------------------- |
| **Base URL**              | `https://api.courier.com`                         |
| **Protocol**              | HTTPS only                                        |
| **Authentication**        | Bearer token (API key)                            |
| **Format**                | JSON request and response bodies                  |
| **Server SDKs**           | Node.js, Python, Ruby, Go, Java, PHP, C# / .NET   |
| **Machine-readable docs** | [llms.txt](https://www.courier.com/docs/llms.txt) |

Browse the [API reference](/docs/api-reference/send/send-a-message) for every endpoint. This page covers the conventions they all share.

* **New to Courier?** Send your first notification in two minutes with the [Quickstart](/docs/getting-started/quickstart).
* **Building with an AI coding agent like Claude Code, Codex, or Cursor?** Connect Courier over MCP or the CLI. Start with [AI onboarding](/docs/tools/ai-onboarding).
* **Prefer a GUI?** Explore every endpoint in the [Postman collection](/docs/tools/courier-postman).

## Client libraries

Official server SDKs wrap the REST API with typed methods, retries, and idempotency helpers. Use them instead of raw HTTP wherever possible.

| Language                                                               | Package                    | Install                                             |
| ---------------------------------------------------------------------- | -------------------------- | --------------------------------------------------- |
| [Node.js](https://www.npmjs.com/package/@trycourier/courier)           | `@trycourier/courier`      | `npm install @trycourier/courier`                   |
| [Python](https://pypi.org/project/trycourier/)                         | `trycourier`               | `pip install trycourier`                            |
| [Ruby](https://rubygems.org/gems/trycourier)                           | `trycourier`               | `gem install trycourier`                            |
| [Go](https://github.com/trycourier/courier-go)                         | `courier-go`               | `go get github.com/trycourier/courier-go/v4`        |
| [Java](https://central.sonatype.com/artifact/com.courier/courier-java) | `com.courier:courier-java` | `implementation("com.courier:courier-java:4.20.2")` |
| [PHP](https://packagist.org/packages/trycourier/courier)               | `trycourier/courier`       | `composer require trycourier/courier`               |
| [C# / .NET](https://www.nuget.org/packages/TryCourier)                 | `TryCourier`               | `dotnet add package TryCourier`                     |

Client-side SDKs embed prebuilt UI in your app: an [in-app notification center](/docs/platform/inbox/inbox-overview) and a [preference center](/docs/platform/preferences/preferences-overview), for [React, React Native, iOS, Android, and Flutter](/docs/sdk-libraries/sdks-overview). Any language can call the REST API directly.

## Authentication

Courier authenticates every request with a bearer token. Pass your API key in the `Authorization` header:

```bash theme={null}
Authorization: Bearer YOUR_API_KEY
```

Requests without a valid key return `401 Unauthorized`. Keys are scoped to a single [environment](/docs/platform/workspaces/environments-api-keys) (Test or Production), so a Test key never sends real notifications and a Production key is never used for experiments. Create and rotate keys in [Settings → API Keys](https://app.courier.com/settings/api-keys).

<Warning>
  Your API key is a secret. Use it only from server-side code, never in a browser, mobile app, or committed source. To authenticate a client (for Inbox or preferences), issue a short-lived [user token](/docs/api-reference/authentication/create-a-jwt) instead.
</Warning>

## Requests and responses

* All requests and responses use JSON. Send `Content-Type: application/json` on requests with a body.
* Timestamps are returned as Unix epoch milliseconds (`int64`), not ISO 8601 strings.
* Send responses return a `requestId`. Use it to [look up a message](/docs/api-reference/sent-messages/get-message) or trace delivery in Message Logs.

## Payload limits

The maximum request body size for all endpoints is **6 MB**. Requests over the limit return `413 Payload Too Large`.

Base64-encoded content (such as inline attachments) inflates size by roughly 33%, so a 6 MB payload holds about 4.5 MB of raw attachment data. For anything larger, host the file and pass a URL instead of embedding it.

## Idempotency

Safely retry requests without sending duplicates by setting an `Idempotency-Key` header. Use a unique value, such as a UUID, for each logical request, and reuse the same value when you retry:

```bash theme={null}
curl -X POST https://api.courier.com/send \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Idempotency-Key: 6f3b8c2a-9d4e-4b7a-a1c5-2e8f0d5b7a91" \
  -H "Content-Type: application/json" \
  -d '{ ... }'
```

Add the header to **any `POST` request**. Courier caches the first response for that key and replays it on retries, so the request runs only once. Keys expire after **24 hours**.

## Pagination

List endpoints use cursor-based pagination. Every response includes a `paging` object with a `more` boolean and a `cursor`:

```json theme={null}
{
  "paging": { "more": true, "cursor": "MTpFWUNFRkRRN0c1WERTRTU2" },
  "results": [ /* ... */ ]
}
```

When `paging.more` is `true`, pass `paging.cursor` back as the `cursor` query parameter to fetch the next page:

```bash theme={null}
curl "https://api.courier.com/messages?cursor=MTpFWUNFRkRRN0c1WERTRTU2" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

The data array field name depends on the endpoint: messages return `results`, while lists and audiences return `items`. Check each endpoint's schema in the [API reference](/docs/api-reference/send/send-a-message).

## Errors

Courier uses standard HTTP status codes. Codes in the `2xx` range mean success, `4xx` means a problem with the request, and `5xx` means a Courier-side error.

| Status                  | Meaning                                 | What to do                                         |
| ----------------------- | --------------------------------------- | -------------------------------------------------- |
| `400` Bad Request       | Malformed request or invalid parameters | Fix the request body or parameters                 |
| `401` Unauthorized      | Missing or invalid API key              | Check the `Authorization` header and key           |
| `403` Forbidden         | Key lacks access to the resource        | Verify environment and key scope                   |
| `404` Not Found         | Resource does not exist                 | Check the ID and path                              |
| `413` Payload Too Large | Body exceeds 6 MB                       | Reduce payload or host files externally            |
| `429` Too Many Requests | Rate limit exceeded                     | Back off and retry                                 |
| `5xx` Server Error      | Courier-side error                      | Retry with backoff; contact support if it persists |

Error responses include a JSON body with a human-readable `message` and a machine-readable `type`:

```json theme={null}
{ "message": "Example message text", "type": "invalid_request_error" }
```

### Message statuses

A `202` from `POST /send` means Courier accepted the request, not that the message was delivered. Track the outcome with the [get-message endpoint](/docs/api-reference/sent-messages/get-message), which returns one of these statuses:

`ENQUEUED`, `ROUTED`, `SENT`, `DELIVERED`, `OPENED`, `CLICKED`, `DELAYED`, `DIGESTED`, `THROTTLED`, `FILTERED`, `CANCELED`, `SIMULATED`, and three failure states:

* `UNROUTABLE`: no channel could be resolved (missing provider, or no channel data on the profile)
* `UNDELIVERABLE`: the provider rejected the recipient (invalid address or blocked domain)
* `UNMAPPED`: the referenced template could not be found

Failed messages also carry a `reason` (such as `BOUNCED`, `NO_PROVIDERS`, `OPT_IN_REQUIRED`, or `UNSUBSCRIBED`) for more context.

## Rate limits

Rate limits apply per environment and vary by endpoint. `POST /send` is not subject to the limits below; it is bounded by the 6 MB payload cap and any workspace [send limits](/docs/platform/sending/send-limits) you configure. The following limits apply to management endpoints:

| API    | Operation               | Limit                 |
| ------ | ----------------------- | --------------------- |
| Lists  | `POST` to subscriptions | 20 requests / minute  |
| Lists  | `PUT` to lists          | 20 requests / minute  |
| Events | `PUT` to events         | 20 requests / minute  |
| Brands | `PUT` to brands         | 200 requests / minute |

Exceeding a limit returns `429 Too Many Requests`. Back off and retry after a short delay.

## FAQ

<AccordionGroup>
  <Accordion title="What can you do with the Courier API?">
    Anything you can do in the Courier dashboard. Send notifications across email, SMS, push, chat, and in-app, and manage user profiles, preferences, lists, templates, brands, and tenants. Every resource has full REST API coverage.
  </Accordion>

  <Accordion title="What is the Courier API base URL?">
    All requests go to `https://api.courier.com` over HTTPS.
  </Accordion>

  <Accordion title="How do I authenticate with the Courier API?">
    Pass your API key as a bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`. Keys are scoped per environment (Test or Production) and used only in server-side code.
  </Accordion>

  <Accordion title="Which languages have official Courier SDKs?">
    Courier maintains official server SDKs for Node.js, Python, Ruby, Go, Java, PHP, and C# / .NET, plus client SDKs for React, React Native, iOS, Android, and Flutter. Any language can call the REST API directly.
  </Accordion>

  <Accordion title="What are the Courier API rate limits?">
    Management endpoints are limited per environment (for example, 20 requests/minute on Lists and Events, 200 requests/minute on Brands). Exceeding a limit returns `429 Too Many Requests`.
  </Accordion>

  <Accordion title="How do I avoid sending duplicate notifications on retry?">
    Set an `Idempotency-Key` header with a unique value. Courier replays the original response for 24 hours, so a retried request runs only once.
  </Accordion>
</AccordionGroup>

## What's next

<CardGroup cols={2}>
  <Card title="Send a message" href="/docs/api-reference/send/send-a-message" icon="paper-plane">
    Full request and response schema for the send endpoint
  </Card>

  <Card title="How sending works" href="/docs/platform/sending/sending-overview" icon="route">
    Routing, channels, fallback, and the delivery pipeline
  </Card>

  <Card title="Courier CLI" href="/docs/tools/cli" icon="terminal">
    Send and manage notifications from your terminal or CI
  </Card>

  <Card title="Manage profiles" href="/docs/api-reference/user-profiles/create-a-profile" icon="user">
    Store recipient contact info and channel tokens
  </Card>
</CardGroup>
