Idempotency
Retry POST /v3/messages and /v3/messages.batch safely with an Idempotency-Key: replays return the original response for 24 hours instead of sending twice.
Networks fail after the request left your process and before the response arrived. Without protection, the natural fix — retry — sends the same email twice. The Idempotency-Key header makes a retry safe: wemail recognises the key, skips the send and returns the response it produced the first time.
How it works
Send any unique string in the Idempotency-Key header on POST /v3/messages or POST /v3/messages.batch. On the first request wemail processes the send normally and stores the full response — status code, body and headers — under that key. Any later request carrying the same key within 24 hours gets that stored response back, byte for byte, and no second message is created. The API key is part of the scope: the same string used from a different API key is a different request.
POST /v3/messages
Authorization: Bearer afn_live_…
Idempotency-Key: 8c6b1fae-0f4f-4f3b-9d1d-2a39e6c2c7bd
Content-Type: application/jsonKey format and scope
A key is 1 to 255 printable ASCII characters; anything else is rejected with 400. Use a fresh UUID v4 per logical operation — one per order confirmation, one per password reset — not per HTTP attempt, and generate it before the first attempt so every retry carries the same value. Keys are not compared against the request body: a reused key returns the first response whatever the new body says, so never recycle a key for a different message. Keys expire 24 hours after first use; after that the same value is treated as new.
What a replay looks like
A replayed request returns the original id and status: "queued" even if the message has since been delivered, bounced or cancelled — the cached response is a snapshot of the first acceptance, not the live state. wemail also records a duplicate event on the original message's timeline, so in the Console Activity drawer and in the events API you can see that two identical calls produced one email, and when.
Worked example
Two identical requests, the second sent because the client timed out waiting for the first. Both carry Idempotency-Key: 8c6b1fae-…. The first creates msg_01HBYE7K9Z4PMQDR3W and returns it. The second returns the very same body — same id, same created_at — and the recipient receives exactly one email. Look the message up and its logs show queued, then duplicate (the replay), then delivered.
KEY=$(uuidgen)
for attempt in 1 2 3; do
curl -sS --max-time 10 https://api.wemail.io/v3/messages \
-H "Authorization: Bearer $WEMAIL_API_KEY" \
-H "Idempotency-Key: $KEY" \
-H "Content-Type: application/json" \
-d @message.json && break
sleep $((attempt * 2))
doneBatch, scheduling and SMTP
On POST /v3/messages.batch the key covers the whole batch: a replay returns the original batch response with every message id, and none of the recipients is sent to twice. Scheduled sends (send_at) behave the same way — the key protects the acceptance, and cancelling the scheduled message does not free the key. The header is HTTP-only: the SMTP relay has no idempotency layer, so a client that re-submits over SMTP after a dropped connection may send twice. Idempotency keys are also independent of rate limits; a replayed request still counts as one request.
When you do not need it
Read requests (GET) are naturally idempotent. Fire-and-forget notifications where an occasional duplicate is acceptable can skip the header, but anything transactional — receipts, one-time codes, invoices — should always carry one.