Use an idempotency key to make Dairo creates safe to retry, so a repeated request returns the original result instead of a duplicate.
Networks drop, requests time out, and agents re-run steps, so the same POST sometimes
fires twice. An idempotency key makes that safe: a retry with the same key returns the
original result instead of creating a duplicate.
Send an idempotency key
Pass an Idempotency-Key header, with a unique value per logical operation, on the
operations listed under Where it applies. A UUID is a good default.
Retrying that exact request with the same key returns the original message instead of sending a second one.
The key can be up to 128 characters; a longer value is rejected with 400. A blank or
whitespace-only header is treated as absent.
Header and body agree
Some creates also accept an idempotencyKey in the JSON body. Dairo reconciles the header
and the body field before running the request:
| You send | Result |
|---|---|
| Header only | The value is used. |
| Body field only | The value is used. |
| Both, equal | Accepted. |
| Both, different non-empty values | 400 with code idempotency_key_mismatch. |
Set the key either way. A disagreement is always surfaced as an error, never resolved silently.
Where it applies
The key is honored on the operations where a duplicate would be costly or irreversible:
| Endpoint | What a retry de-duplicates |
|---|---|
POST /v1/messages | sending (or scheduling) the same message twice |
POST /v1/audiences/{id}/send | broadcasting to an audience twice |
POST /v1/letters, POST /v1/letters/batches | printing and posting the same physical letters twice |
POST /v1/letters/{id}/cancel | canceling twice |
POST /v1/phone/calls | ringing the same person twice |
POST /v1/erasure-jobs | enqueuing the same erasure job twice |
POST /v1/inboxes/{id}/verification-waits | registering the same wait twice |
Other creates do not use the key. Some of them are safe to retry anyway because the
resource is identified by what you send: creating an inbox or a domain that already
exists returns it, and adding audience members upserts them by address. Creating a
webhook for a URL you already registered, a bucket with a name in use, or a template
with a slug already in use, returns 409. Creating an API key, an audience, an agent
passport, or a share link mints a new one on every call, so create those once and store
the result.
GET requests are always idempotent and need no key. DELETE and PATCH are naturally
idempotent (deleting or setting the same state twice has the same effect), so they do not
take an Idempotency-Key.
Reuse the key, keep the payload
A key identifies one specific operation, not a slot you can overwrite. On a message send,
reusing a key with a different subject or to returns the original send unchanged, plus
a warning (reason: "idempotency_key_reused_with_different_params"); your new content is
not sent. To send genuinely different content, use a fresh key.
Two habits keep this predictable:
- Generate the key before the first attempt and reuse it across every retry of the same operation. A fresh key per attempt defeats the purpose, since each new key is a new operation.
- Use a stable, unique value. A UUID is the simplest safe choice. If you key off your
own data, make the value unique per intended operation, for example
order-4815-welcome-email.
The SDKs retry transient failures for you; passing an idempotency key makes those retries duplicate-safe end to end.