Idempotent Requests

Learn how to use idempotency keys to build safe and reliable API integrations.

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 resource id against your client_id.
  • If we have seen this client_id before, we do not re-process the request. Instead, we immediately return a 200 OK response with the data from the original, successfully completed request.

This allows you to safely retry requests without the risk of creating duplicate data.

1# The first time this code is run, it creates a new inbox.
2inbox = client.inboxes.create(
3 username="idempotent-test",
4 client_id="user-123-inbox-primary"
5)
6print(f"Created inbox: {inbox.id}")
7
8# If you run this exact same code again, it will NOT create a second
9# inbox. It will return the same inbox object from the first call.
10inbox_again = client.inboxes.create(
11 username="idempotent-test",
12 client_id="user-123-inbox-primary"
13)
14print(f"Retrieved same inbox: {inbox_again.id}")
15# The inbox.id will be identical in both calls.

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, a client_id for a user’s primary inbox could be inbox-for-user-{{USER_ID}}.
  • Unique: Do not reuse a client_id for creating different resources. A client_id used to create an inbox should not be used to create a webhook.

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.