Skip to content
Idempotency
.md

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:

EndpointRoute
Create AudiencePOST /api/v2/analyses/audiences/create
Estimate Audience SizePOST /api/v2/analyses/audiences/estimate
Create Lookalike AudiencePOST /api/v2/analyses/audiences/create-lookalike
Create CohortPOST /api/v2/analyses/cohorts/create
Create ActivationPOST /api/v2/analyses/activations/create
Create ProjectPOST /api/v2/analyses/projects/create
Create SchedulePOST /api/v2/analyses/schedules/create
Create Submission by UploadPOST /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.
Calling from an AI agent over 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.

Related