Idempotent Requests
What is Idempotency?
In the context of an API, idempotency is the concept that making the same API request multiple times produces the same result as making it just once. If an idempotent POST request to create a resource is sent five times, it only creates the resource on the first call. The next four calls do nothing but return the result of that first successful call.
This is a critical feature for building robust, fault-tolerant systems. Network errors, timeouts, and client-side retries are inevitable. Without idempotency, these events could lead to unwanted duplicate resources, like creating multiple identical inboxes or webhooks.
How AgentMail Handles Idempotency
AgentMail supports idempotency for all create operations via an optional client_id parameter.
When you provide a client_id with a create request, AgentMail checks if a request with that same client_id has already been successfully completed.
- If it’s the first time we’ve seen this
client_id, we process the request as normal, create the resource, and store the resulting resourceidagainst yourclient_id. - If we have seen this
client_idbefore, we do not re-process the request. Instead, we immediately return a200 OKresponse with the data from the original, successfully completed request.
This allows you to safely retry requests without the risk of creating duplicate data.
Best Practices for client_id
To use idempotency effectively, the client_id you generate must be unique and deterministic.
- Deterministic: The same logical resource on your end should always generate the same
client_id. For example, aclient_idfor a user’s primary inbox could beinbox-for-user-{{USER_ID}}. - Unique: Do not reuse a
client_idfor creating different resources. Aclient_idused to create an inbox should not be used to create a webhook. - No
@symbol: Theclient_idvalue cannot contain the@symbol. If you want to use an email address as an identifier, replace@with another character (e.g.,user_at_example.cominstead ofuser@example.com).
A common and highly effective pattern is to generate a UUID (like a UUID v4) on your client side for a resource you are about to create, save that UUID in your own database, and then use it as the client_id in the API call. This gives you a reliable key to use for any retries.
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.
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_idandthread_idand 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-Keyheader is rejected with a400rather 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.
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–256 characters from A-Z a-z 0-9 - . _ ~.
