# Idempotency


Creating a resource is the one kind of request you never want to run twice by
accident. A dropped connection or a timed-out retry could otherwise leave you
with two identical audiences, or a second activation delivering to a partner.
The optional `Idempotency-Key` header makes a create **safe to retry**: the
platform recognises the repeat and replays the original outcome instead of
doing the work again.

## Which endpoints honor it

Eight endpoints - the resource creates and Estimate Audience Size - read the
`Idempotency-Key` header:

| Endpoint | Route |
| --- | --- |
| Create Audience | `POST /api/v2/analyses/audiences/create` |
| Estimate Audience Size | `POST /api/v2/analyses/audiences/estimate` |
| Create Lookalike Audience | `POST /api/v2/analyses/audiences/create-lookalike` |
| Create Cohort | `POST /api/v2/analyses/cohorts/create` |
| Create Activation | `POST /api/v2/analyses/activations/create` |
| Create Project | `POST /api/v2/analyses/projects/create` |
| Create Schedule | `POST /api/v2/analyses/schedules/create` |
| Create Submission by Upload | `POST /api/v2/my-data/pois/submissions/create-by-upload` |

The header is **ignored everywhere else**. Cancel Lookalike, the schedule
activate/deactivate writes, and the delete endpoints do not participate -
sending the header does not make a cancel, a status toggle or a delete
idempotent.

## How a key behaves

The key is **optional** and **caller-generated**: you supply any unique string
(a UUID v4 is typical) in the `Idempotency-Key` header. Omit it and the create
runs normally, with no replay protection.

When you do send a key:

- **First request** - runs normally. If it succeeds (a `2xx` response), that
  response is stored against the key.
- **Same key, same body, within the TTL** - the stored response is replayed
  **verbatim**, carrying an extra `Idempotency-Replayed: true` header. No second
  resource is created.
- **Same key, different body** - rejected with `409 Conflict`. A key is a
  promise that the request is the same one; changing the body breaks that
  promise.
- **Same key while the first request is still in flight** - a concurrent
  duplicate also returns `409 Conflict` rather than starting a second run.

The stored response lives for **24 hours**. After that TTL expires, the same key
is free to start a fresh create.

### Only successful responses are cached

Only `2xx` responses are stored. If the first attempt fails with a `429` (rate
limited) or a `5xx`, nothing is cached, so a retry with the same key genuinely
**re-executes** the create - which is exactly what you want, because the
resource was never made. Retry those safely.

## Replay is scoped to you

A stored response is scoped to the **token, the company, and the exact route**
that produced it. Keys never collide across different tokens, different
companies, or different endpoints: the same string used by two callers, or on
two different create routes, is two independent keys. You will only ever replay
a response your own token created on that same route.

## Using it well

- **Generate a fresh key per logical operation** - one UUID for "create this
  audience", a different one for the next audience.
- **Reuse that same key on every retry** of that one operation - on a timeout, a
  dropped connection, or a `429`/`5xx`, resend with the key you already
  generated. You either get the original result back (if the first attempt
  actually succeeded) or a clean re-execution (if it did not).
- **Do not reuse a key for a genuinely new create** - a new operation carrying an
  old key either replays the old result or, if the body differs, returns `409`.

{{< callout type="info" >}}
Calling from an AI agent over [MCP](/mcp)? The create tools take an
`idempotency_key` argument that maps to this exact header, with identical
semantics - pass a fresh value per logical create and reuse it on retries. See
[Automate with an AI Agent](/guides/automate-with-an-ai-agent).
{{< /callout >}}

## Related

- [The Async Model](/concepts/async-model) - create returns fast, then you poll.
- [Errors](/concepts/errors) - the error envelope, including `409` and `429`.
- [Polling and Rate Limits](/guides/polling-and-rate-limits) - retrying on a
  `429` with `Retry-After`, and idempotent retries in practice.
