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

# Introduction

> Programmatic access to your Sendmux email infrastructure.

The Sendmux Management API gives you programmatic access to your email workspace: manage sending accounts, domains, mailboxes, API keys, and webhook subscriptions; check mailbox address availability before you create a mailbox; read metrics and delivery logs; track billing balance and history.

## Base URL

All API requests should be made to:

```
https://app.sendmux.ai/api/v1
```

## Authentication

Authenticate using an API key from the Sendmux app. Pass it as a Bearer token in the `Authorization` header.

```bash theme={null}
curl https://app.sendmux.ai/api/v1/providers \
  -H "Authorization: Bearer smx_root_your_key_here"
```

API keys are scoped to a team and carry specific permissions. Create and manage keys under **Settings > API Keys** in the Sendmux app. Each team starts with **100 active credentials** across manual API keys and connected apps; manual keys include root keys, send-only keys, and mailbox-scoped keys. See [Team limits](/guides/team-limits).

### Permissions

Each endpoint requires a specific permission. Keys with wildcard permissions (e.g. `domain.*`) satisfy any permission in that namespace, and the built-in `root:full` role includes every wildcard.

| Endpoint group   | Required permission(s)                                                                                                                                                                                                                           |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Sending accounts | `provider.read` for reads; `provider.create` for custom SMTP account creation and sending-account limit requests; `provider.update` for edits, activation, connection tests, and shared Amazon SES limit requests; `provider.delete` for delete. |
| Email metrics    | `analytics.read`                                                                                                                                                                                                                                 |
| Email logs       | `logs.read`                                                                                                                                                                                                                                      |
| Billing          | `billing.read`                                                                                                                                                                                                                                   |
| Domains          | `domain.read` for reads; `domain.create`, `domain.verify`, `domain.delete` for the matching mutations.                                                                                                                                           |
| Mailboxes        | `mailbox.admin.read` for reads; `mailbox.admin.create` for create; `mailbox.admin.delete` for delete; `mailbox.admin.manage` for update, filter management, and per-mailbox API-key management.                                                  |
| Webhooks         | `webhook.read` for reads; `webhook.create`, `webhook.update`, `webhook.delete` for the matching mutations; `webhook.manage` for rotate-secret and test.                                                                                          |

<Tip>
  Use the `root:readonly` role for monitoring integrations. It covers every
  `*.read` permission. `root:webhook_admin` is a narrower preset for keys that
  should only manage webhook subscriptions. `root:provider_admin` is a narrower
  preset for keys that manage sending accounts, routing, domains, and logs.
</Tip>

## Response format

All responses use a consistent JSON envelope.

### Success

```json theme={null}
{
  "ok": true,
  "data": { ... },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

### Paginated success

List endpoints include a `pagination` object alongside `data`.

```json theme={null}
{
  "ok": true,
  "data": [ ... ],
  "pagination": {
    "has_more": true,
    "next_cursor": "dlog_xxxxxxxx"
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

### Error

```json theme={null}
{
  "ok": false,
  "error": {
    "code": "invalid_parameter",
    "message": "The 'from_date' parameter must be a valid ISO 8601 date.",
    "param": "from_date",
    "doc_url": "https://sendmux.ai/docs/api/errors#invalid_parameter",
    "retryable": false
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

The `retryable` flag distinguishes transient failures (back off and retry) from permanent ones (fix the request). See the [errors reference](/api/errors) for the full envelope shape, the accumulated `errors[]` array on validation failures, and the `Retry-After` header semantics for `429`/`503`.

## Errors

| HTTP status | Error code                 | Default `retryable` | Description                                                          |
| ----------- | -------------------------- | ------------------- | -------------------------------------------------------------------- |
| 400         | `invalid_parameter`        | false               | Bad query parameter format or syntactic body validation failure.     |
| 400         | `missing_parameter`        | false               | Required parameter missing.                                          |
| 401         | `authentication_required`  | false               | No or invalid API key.                                               |
| 403         | `insufficient_permissions` | false               | Key lacks required permission.                                       |
| 404         | `not_found`                | false               | Resource does not exist or belongs to a different team.              |
| 409         | `conflict`                 | false               | Resource state forbids the operation (e.g. `If-Match` mismatch).     |
| 409         | `limit_exceeded`           | false               | Team resource limit reached for a create request.                    |
| 409         | `idempotency_conflict`     | false               | `Idempotency-Key` reused with a different body or while in-flight.   |
| 413         | `payload_too_large`        | false               | Request body exceeds the server-side size limit.                     |
| 422         | `validation_error`         | false               | Body parsed but violates a semantic rule.                            |
| 429         | `rate_limit_exceeded`      | true                | Rate limit hit. `Retry-After` header included.                       |
| 500         | `internal_error`           | true                | Unexpected server error.                                             |
| 503         | `service_unavailable`      | true                | Downstream component briefly unavailable. May include `Retry-After`. |

## Rate limits

Each Management API key is rate-limited to **600 requests per 60 seconds**.

Sending API keys are limited separately to **1,800 requests per 60 seconds** on the Sending API. See the [Sending API introduction](/sending-api/introduction#rate-limits).

Every response carries the current rate-limit state plus a request identifier:

```
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 594
X-RateLimit-Reset: 1679313700
X-Request-Id: req_clxxxxxxxxxxxxxxxxxxxxxxxxx
```

`X-Request-Id` matches `meta.request_id` in the JSON envelope. Include it when contacting support.

When the limit is exceeded, the API returns a `429` status with a `Retry-After` header indicating how many seconds to wait before retrying.

## Conditional requests

Every `GET` that returns a single resource emits a weak `ETag`. Send it back on the next request to avoid transferring unchanged data, and use `If-Match` on writes that document the header for optimistic concurrency control.

* **`If-None-Match`** on a `GET`: if the resource is unchanged, the API responds `304 Not Modified` with no body. Reuse your cached copy.
* **`If-Match`** on a `PATCH`, `PUT`, or supported `DELETE`: if the resource changed since you fetched it, the API responds `409 conflict` so you do not overwrite a concurrent update. Re-fetch, reapply your change, and retry.

Conditional requests are supported across mailbox, domain, webhook, and log resource `GET`s, and on the [Sending API](/sending-api/introduction#conditional-requests).

## Sending account management

Use the Management API's **Sending accounts** group to manage accounts used by the Sending API. Custom SMTP accounts support full create, read, update, delete, activation, deactivation, usage, and connection-test flows.

Connected account setup still starts in the Sendmux app. After connection, the API can read, activate, deactivate, delete, and update safe account metadata.

The shared Amazon SES account is protected. You can read it, activate or deactivate it, and request a daily limit increase. You cannot edit its credentials, quotas, routing weight, sender defaults, or delete it through the API.

## Conventions

* **snake\_case** fields in all JSON responses
* **UTC ISO 8601 timestamps** in RFC 3339 format: `2026-03-19T10:30:00Z`
* **Public IDs only**. Private numeric IDs are never exposed.
* **`Cache-Control: no-store`** on all responses
* **JSON only**. Use `Content-Type: application/json`.

## OpenAPI specification

The full OpenAPI 3.1 specification is available at:

```
https://app.sendmux.ai/api/v1/openapi.json
```

Use it with any OpenAPI-compatible tool to generate client libraries or explore the API.

You can also import the [Management API Postman collection](/guides/postman-collection#choose-a-collection) by URL.
