Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions fern/definition/api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ idempotency-headers:
docs: >-
Unique key that makes a send idempotent. A retry carrying the same key
returns the original message instead of sending a second email; reusing a
key with a different request different message content, a different
sending inbox, or a different send endpoint returns a 409 conflict.
key with a different request (different message content, a different
sending inbox, or a different send endpoint) returns a 409 conflict.
Keys expire 24 hours after the send completes.
8 changes: 4 additions & 4 deletions fern/pages/best-practices/idempotency.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ A common and highly effective pattern is to generate a UUID (like a `UUID v4`) o

## Idempotent Sends

Sends `messages.send`, replies, forwards, and `drafts.send` are idempotent too, but through a different mechanism. A send is **irreversible** (an email actually goes out), so instead of the body `client_id` used for resource creation, you pass an **`Idempotency-Key` HTTP header**.
Sends (`messages.send`, replies, forwards, and `drafts.send`) are idempotent too, but through a different mechanism. A send is **irreversible** (an email actually goes out), so instead of the body `client_id` used for resource creation, you pass an **`Idempotency-Key` HTTP header**.

When a send carries an `Idempotency-Key`:

- **The first time** we see the key, we send the email, record the result against the key, and return the message.
- **A retry with the same key** returns the original `message_id` and `thread_id` and sends **no second email**.
- **The same key with a different request** different message content, a different sending inbox, or a different send endpoint returns `409 Conflict`, so an accidental key reuse surfaces loudly instead of silently replaying the wrong result.
- **An explicitly empty `Idempotency-Key` header** is rejected with a `400` rather than silently treated as absent if you meant to use idempotency, a broken key fails loudly instead of quietly losing protection.
- **The same key with a different request** (different message content, a different sending inbox, or a different send endpoint) returns `409 Conflict`, so an accidental key reuse surfaces loudly instead of silently replaying the wrong result.
- **An explicitly empty `Idempotency-Key` header** is rejected with a `400` rather than silently treated as absent: if you meant to use idempotency, a broken key fails loudly instead of quietly losing protection.
- Keys are scoped to your organization and **expire 24 hours** after the send completes, after which the key can be reused.

```bash title="cURL"
Expand Down Expand Up @@ -89,4 +89,4 @@ const message = await client.inboxes.messages.send(
);
```

Choose a key that is **unique per logical send**either a random `UUID v4` you generate once and reuse across retries of that one send, or a deterministic key derived from your own data (e.g. `order-{{ORDER_ID}}-receipt`). The character rules match `client_id`: 1256 characters from `A-Z a-z 0-9 - . _ ~`.
Choose a key that is **unique per logical send**: either a random `UUID v4` you generate once and reuse across retries of that one send, or a deterministic key derived from your own data (e.g. `order-{{ORDER_ID}}-receipt`). The character rules match `client_id`: 1 to 256 characters from `A-Z a-z 0-9 - . _ ~`.
Loading