Before continuing, make sure you’ve completed the SDK setup and requirements.
Overview
Network issues, timeouts, and client crashes can cause API requests to fail without a clear response. When this happens, you may not know if the email was actually sent. Retrying the request risks sending the same email twice. Idempotency keys solve this problem. By including anIdempotency-Key header in your request, you tell the API to process the request only once. If you retry with the same key, the API returns the original response instead of sending the email again.
How it works
- You generate a unique key and include it in the
Idempotency-Keyheader. - The API processes the request and stores the response associated with that key.
- If you send the same request again with the same key, the API returns the stored response without reprocessing.
- Keys expire after 24 hours. After that, the same key can be reused.
Send an email with an idempotency key
With the SDK
With the REST API
Bulk emails
For bulk sending, the idempotency key applies to the entire bulk request, not to individual emails within it. If you retry a bulk request with the same key, the full bulk response (including per-email statuses) is returned from cache.Key format
| Property | Value |
|---|---|
| Minimum length | 8 characters |
| Maximum length | 255 characters |
| Recommended format | UUID v4 |
| Case sensitive | Yes |
order-12345.
Choosing a key strategy
There are three approaches depending on your use case.Random keys
Use a random UUID when you need retry safety for a single operation. Generate the key before the first attempt and reuse it across retries.Deterministic keys
Derive the key from a business identifier when you need to prevent duplicates across independent processes. For example, two different servers processing the same order will generate the same key and avoid sending duplicate emails.Content-based keys
Hash the email content (or a subset of it) to derive a key when you do not have a stable business identifier but want to prevent sending the same content twice.Error handling
The API returns specific error codes for idempotency-related issues.Invalid key
Returned when the key is empty, too short, or too long.Key already in progress
Returned when a request with the same key is still being processed. Wait a moment and retry.Payload mismatch
Returned when you reuse a key with a different request body. The server computes a fingerprint of each request and compares it on retries. If the request body differs from the original, the request is rejected instead of silently ignored. Each key is bound to the exact request body that was sent with it. Use a new key for different requests.Behavior on errors
How the API handles idempotency depends on the type of error from the original request:- Client errors (4xx): The error response is cached. Retrying with the same key returns the same error. You need to fix the issue and use a new key.
- Server errors (5xx): The error response is not cached. The key is cleared and you can safely retry with the same key.
- Successful request with lost response: If the first attempt succeeded but the response was lost (network timeout, client crash), retrying with the same key returns the stored result with the
Idempotent-Replayed: trueheader.
Detecting replayed responses
When the API returns a cached response, it includes theIdempotent-Replayed: true header. The response body and status code are identical to the original response.
You can use this header to distinguish a replayed response from a fresh one in your logs or monitoring.
Best practices
- Generate a new unique key for each distinct email you want to send
- Store the key alongside the operation in your system so you can retry with the same key if needed
- Use deterministic keys (based on business identifiers) when the same operation can be triggered from multiple code paths
Advanced
SDK retry behavior
The Nuntly SDK automatically retries failed requests up to 2 times with exponential backoff. It retries on connection errors, timeouts, and server errors (5xx). You can configure this behavior per client or per request:Payload fingerprinting
The server computes a fingerprint of each request and compares it when the same idempotency key is reused. If the request differs from the original, the server rejects it with a409 error (idempotency_key_payload_mismatch) rather than silently ignoring the difference.
This prevents a subtle bug: accidentally reusing a key meant for a different email.
Concurrent requests
If two requests with the same key arrive simultaneously, the first to reach the server starts processing. The second receives a409 error (idempotency_key_in_progress).
The processing window is very short, and if the original request stalls, the server automatically clears the lock after a timeout.
Practical patterns
Queue workers
Most message queues guarantee at-least-once delivery, meaning your worker can receive the same message more than once. This typically happens when the acknowledgment is lost after processing. By using the message ID as the idempotency key, duplicate deliveries from the queue do not result in duplicate emails.Scheduled jobs
Cron jobs and scheduled tasks can fire multiple times due to deployment restarts, rolling updates, or clock drift across servers. When two instances of the same job run concurrently, both attempt to send the same email. By combining the job name with the schedule slot, each execution window maps to a single idempotency key.Webhook-triggered emails
External services like payment providers often retry webhook deliveries when they do not receive a timely response. If your handler sends an email on each webhook call, retried webhooks cause duplicate sends. Using the webhook event ID as the idempotency key ensures the email is sent only once per event, regardless of how many times the webhook is delivered.Send your first email
Get started with the Nuntly API
Bulk email sending
Send multiple emails in a single request
Error handling
Learn about API error responses
API keys
Create and manage your API keys
