Network blips, client timeouts, and middleware retries can cause the same request to reach Sendmux more than once. TheDocumentation Index
Fetch the complete documentation index at: https://docs.sendmux.ai/llms.txt
Use this file to discover all available pages before exploring further.
Idempotency-Key request header lets you mark a request so a retry under the same key returns the original response instead of re-running the operation.
How it works
Send the header on the original request
Add
Idempotency-Key: <your-key> to any mutating request. Sendmux records the key, the response, and a fingerprint of the request body.Retry under the same key
If the same key arrives again within 24 hours with the same body, Sendmux returns the cached response verbatim — same status, same headers, same body. The operation does not run twice.
Sending the header
Coverage
The header is honoured on every mutating endpoint:| API | Endpoint | Effect of replay |
|---|---|---|
| Sending API | POST /emails/send | Returns the original message_id and status. |
| Sending API | POST /emails/send/batch | Returns the original per-message results array. |
| Management API | POST /domains | Returns the original 201 + Location header. |
| Management API | POST /mailboxes | Returns the original 201 + Location header. |
| Management API | POST /mailboxes/{public_id}/keys | Returns the original 201 + Location header (and the secret field). |
| Management API | POST /webhooks | Returns the original 201 + Location header (and the secret field). |
| Management API | POST /webhooks/{public_id}/rotate-secret | Returns the original new secret — the secret is not rotated again. |
| Management API | POST /webhooks/{public_id}/test | Returns the original event_id — no second test event is published. |
GET endpoints don’t accept the header (they have no side effects); PATCH, PUT, and DELETE use If-Match for optimistic concurrency instead.
Replay vs conflict
| Situation | HTTP status | Body |
|---|---|---|
| Same key, same body, original request finished | The original status (200, 201, 422, …) | The original response body, byte-identical. |
| Same key, original request still being processed | 409 | { ok: false, error: { code: "idempotency_conflict", message: "This request is already being processed." } } |
| Same key, different body | 409 | { ok: false, error: { code: "idempotency_conflict", message: "Idempotency-Key was reused with a different request body." } } |
409 idempotency_conflict while the original is in flight is transient — wait briefly and retry under the same key to receive the completed response.
Key format
- Length: 1–255 characters. Whitespace is trimmed; an empty or oversize key is silently ignored.
- Charset: opaque to Sendmux. URL-safe identifiers travel cleanly through proxies and logs (
a-zA-Z0-9_-), but no character class is rejected server-side. - Stability: the key must be deterministic per logical operation. Random UUIDs minted at retry time defeat the purpose — they make every retry look like a brand-new request. Derive the key from the action you’re performing:
order-confirmation-{order_id},welcome-{user_id},invoice-{invoice_id}-{period}.
Scope
Cached entries are scoped to (team, endpoint, key):- Two teams may use the same key without colliding.
- The same key reused across two different endpoints (e.g.
POST /emails/sendandPOST /webhooks) does not collide — each endpoint maintains its own namespace. - Keys expire 24 hours after first use. After expiry the same key can be reused and a fresh request is processed.
Batch sends
POST /emails/send/batch honours one Idempotency-Key header for the whole batch. Replay returns the original results array verbatim — the batch is not re-processed and individual messages are not re-sent.
If you need per-message idempotency inside a batch, split the batch into individual POST /emails/send calls each with their own Idempotency-Key.
Limitations
- Best-effort. If our cache layer is briefly unavailable, the request is processed without idempotency protection (fail-open) rather than rejected. Critical retries should still be safe to send.
- Body field is rejected. Earlier versions accepted
idempotency_keyinside the JSON body. That form now returns422 validation_error— migrate to theIdempotency-KeyHTTP header.