What is an idempotency key? How it stops duplicate messages
Editorial team · updated · facts checked
An idempotency key is a unique string your code sends with a POST request, usually in an Idempotency-Key header, so the server can recognize a retry of the same request. If the first attempt already went through, the server returns the stored result instead of acting again: one email, one text, one charge.
An idempotent API call has the same effect however often it is repeated. A message send isn't: after a timeout your code can't tell whether the provider accepted it, and RFC 9110 says a client "SHOULD NOT automatically retry a request with a non-idempotent method" unless it can tell the retry is safe. The key is how it tells. Bird's WhatsApp guide adds that duplicates are billed.
How a server uses an idempotency key
The server keeps each key with the first result for a published window. The IETF draft sets out four cases:
- New key: process the request and store the response.
- Same key and body, already finished: replay the stored response. Bird marks replays
Idempotency-Replay: true, TelnyxIdempotent-Replayed: true. - Same key, first request still running:
409 Conflict; retry later. - Same key, different body: an error,
422in the draft and at Telnyx,409at Resend and Bird. Bird compares the raw body, JSON whitespace included.
Stripe, which the draft credits as an inspiration, stores the first result "regardless of whether it succeeds or fails", 500 errors included. Bird and Telnyx keep no server errors, so a retry runs again. Bird also warns that "an operation can take effect before its response is retained". A key makes duplicates rare, not impossible.
The Idempotency-Key HTTP header (IETF draft)
Idempotency-Key is not an HTTP standard. The IETF HTTPAPI working group's draft reached revision -07 on 15 October 2025; on 24 September 2026 the datatracker listed it as an "Expired Internet-Draft", expired on 18 April 2026. There is no RFC, and IANA's HTTP Field Name Registry, updated 28 August 2026, has no entry for it.
The draft text recommends a UUID "or a similar random identifier", says a key "MUST NOT be reused with another request with a different request payload" and asks servers to publish their expiry policy.
Which email, SMS and WhatsApp APIs support idempotency keys
Of the 27 providers in our dataset, four document a key on a send call:
| Provider | Covers | Key goes in | Kept for | Same key, new body | Checked |
|---|---|---|---|---|---|
| Bird | Supported write calls; docs name email and WhatsApp | Idempotency-Key header; SDKs add one | About 3 hours | 409 E01005 | 24 Sep 2026 |
| Brevo | Transactional email only | idempotencyKey (UUID) in the JSON headers object | 30 minutes | Any reuse: duplicate_parameter, no replay | 24 Sep 2026 |
| Resend | Email API and SMTP | Idempotency-Key header; Resend-Idempotency-Key over SMTP | 24 hours | 409 invalid_idempotent_request | 24 Sep 2026 |
| Telnyx | Email only, not SMS | Idempotency-Key header | Up to 24 hours | 422, code 10027 | 24 Sep 2026 |
On Brevo, any retry within 30 minutes returns duplicate_parameter, not the first response: you learn the key was used, not whether the email went out.
Seven show no key in the send call's reference or OpenAPI spec (checked 24 September 2026): Amazon SES (SendEmail), AWS End User Messaging (SendTextMessage), ClickSend, Infobip, Mailgun, Mailjet and Sinch. ClickSend's THROTTLED status only stops an "Identical message body recently sent to the same recipient". The other 16 have no recorded answer and are left out. On the same day we found no idempotency parameter in Twilio's Messages resource or SendGrid's Mail Send reference, and Postmark's support center says it "does not currently support an idempotency key feature."
Retrying a send with an idempotency key
Tie the key to the message, not the HTTP attempt: build it once from stable IDs, such as receipt/<order id> (the <event-type>/<entity-id> format Resend and Bird suggest). Guessable keys like these rely on per-account scoping, which Bird documents; the draft warns that unscoped, low-entropy keys can leak other clients' cached responses. A fresh UUID per attempt protects nothing. Keep personal data out of keys, as Stripe and Telnyx advise. Illustrative Node.js against Resend, where receiptEmail() returns the from, to, subject and html fields:
async function sendReceipt(order, attempt = 1) {
const res = await fetch("https://api.resend.com/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RESEND_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": `receipt/${order.id}`, // same key and body on every attempt
},
body: JSON.stringify(receiptEmail(order)),
signal: AbortSignal.timeout(10_000),
}).catch(() => null); // timeout: the email may already be accepted
if (res?.ok) return res.json(); // a replay returns the original email ID
const retry = !res || res.status >= 500 || [409, 429].includes(res.status); // 409: still running
if (!retry || attempt === 4) throw new Error(`Unconfirmed: ${res?.status ?? "timeout"}`);
await new Promise((r) => setTimeout(r, 1000 * 2 ** attempt));
return sendReceipt(order, attempt + 1);
}
When the API has no idempotency key
Deduplicate on your side before calling. Insert a row keyed on the event (receipt/<order id>) under a unique constraint, with the status sending; if the insert fails, the send is under way or done. After the provider accepts, save its message ID and mark the row sent. A retry that finds sending has an unknown outcome: check the provider's logs before resending, as Telnyx's retry guide advises for timed-out sends. The row outlasts short key windows too; our transactional email guide applies it to receipts.
SMTP has no request ID, and RFC 5321 warns that a timeout after the message data "would typically result in delivery of multiple copies of the message". Our email API vs SMTP relay comparison found a deduplication header at one of eight relays, Resend's. Incoming webhooks need the same event-ID check; see the vibe coding security checklist.
Related guides
- Email API vs SMTP relay
- Transactional email guide
- Amazon SES alternatives, with idempotency-key support per provider
- Vibe coding security checklist
About this guide
The PingMyUsers editorial team wrote this entry for developers and AI coding agents adding retries to message sends. Sensaria AG in Switzerland operates the directory; providers don't pay for placement, and none reviewed this page. Report errors, with a source, to contact@sensaria.ch.
Methodology
On 24 September 2026 we read the IETF datatracker record and draft -07, RFC 9110, RFC 5321, IANA's registry, Stripe's reference, and the send or idempotency docs of the 11 providers above plus Twilio, SendGrid and Postmark. We did not send messages or open accounts. Section order follows 62 AI-search queries. Provider scores follow our methodology.
Last updated
24 September 2026: first version. Next re-check: March 2027, or sooner if the draft or a listed provider's rules change.
Frequently asked questions
Is Idempotency-Key an official HTTP header?
No. The IETF draft expired on 18 April 2026 without becoming an RFC, and IANA's registry has no entry. Providers set their own rules.
How long do idempotency keys last?
30 minutes at Brevo, about 3 hours at Bird, 24 hours at Resend and up to 24 hours at Telnyx. After that, the key starts a new request.
Should an idempotency key be a UUID?
Either a UUID created once per message or a key built from your own IDs, like receipt/1234, which survives restarts. Reuse it on every retry.
Does Twilio support idempotency keys for SMS?
Not on the Messages resource as of 24 September 2026; the only Idempotency-Key we found in its docs covers Conversations Orchestrator configuration calls. Twilio webhooks carry I-Twilio-Idempotency-Token for spotting retries.
Which HTTP methods are idempotent?
RFC 9110 lists PUT, DELETE and the safe methods GET, HEAD, OPTIONS and TRACE. POST and PATCH are not, and message sends are POST.
Sources
- IETF Datatracker — draft-ietf-httpapi-idempotency-key-header (Expired Internet-Draft) — checked 24 September 2026
- IETF Datatracker — draft history (WG last call, expiry dates) — checked 24 September 2026
- The Idempotency-Key HTTP Header Field, draft-ietf-httpapi-idempotency-key-header-07 (15 October 2025) — checked 24 September 2026
- IANA — Hypertext Transfer Protocol (HTTP) Field Name Registry (last updated 28 August 2026) — checked 24 September 2026
- RFC 9110 — HTTP Semantics, section 9.2.2 Idempotent Methods — checked 24 September 2026
- RFC 5321 — Simple Mail Transfer Protocol, section 4.5.3.2.6 DATA Termination — checked 24 September 2026
- Stripe — Idempotent requests (API reference) — checked 24 September 2026
- Resend — Idempotency Keys — checked 24 September 2026
- Brevo — Idempotency for batch emails — checked 24 September 2026
- Bird — Idempotency-Key header (API reference) — checked 24 September 2026
- Bird — Idempotency (guide) — checked 24 September 2026
- Bird — Sending WhatsApp messages — checked 24 September 2026
- Telnyx — Sending Email with the Telnyx API (Idempotency) — checked 24 September 2026
- Telnyx — API retries and reliability — checked 24 September 2026
- Telnyx — Send a message (API reference) — checked 24 September 2026
- Amazon SES — SendEmail (API v2 reference) — checked 24 September 2026
- AWS End User Messaging — SendTextMessage (SMS and Voice v2 API reference) — checked 24 September 2026
- AWS End User Messaging — RequestPhoneNumber (ClientToken) — checked 24 September 2026
- ClickSend — REST API reference, introduction (status codes) — checked 24 September 2026
- Infobip — OpenAPI specification 3.237.0 (all public endpoints) — checked 24 September 2026
- Mailgun — API OpenAPI description (send) — checked 24 September 2026
- Mailjet — Email API OpenAPI description (Send API v3.1) — checked 24 September 2026
- Sinch — Conversation API OpenAPI specification (request_id) — checked 24 September 2026
- Twilio — Messages resource (Programmable Messaging API) — checked 24 September 2026
- Twilio — Webhooks connection overrides (I-Twilio-Idempotency-Token) — checked 24 September 2026
- Twilio — Conversations Orchestrator async operations (Idempotency-Key on configuration operations) — checked 24 September 2026
- Twilio SendGrid — Mail Send API reference — checked 24 September 2026
- Postmark Support Center — What is an Idempotency Key? (updated 30 September 2025) — checked 24 September 2026