Getting started
Idempotency
Use the Idempotency-Key header to retry send and batch requests safely without delivering duplicate emails.
A network timeout leaves you unsure whether a send request succeeded. If you retry blindly, the recipient may get the email twice. An idempotency key makes the retry safe: Sooner recognizes the repeated request and returns the original result instead of sending again.
How it works
Add an Idempotency-Key header to POST /emails or POST /emails/batch.
curl -X POST https://api.sooner.dev/emails \
-H "Authorization: Bearer $SOONER_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: welcome-user-123" \
-d '{
"from": "Acme <hello@mail.yourcompany.com>",
"to": ["user@example.com"],
"subject": "Welcome",
"html": "<p>Thanks for signing up</p>"
}'{ "id": "01jcz8w3f2x9k4m7n6p5q2r1s0" }Send the same request again with the same key and you get the same id back, and no second email is sent. For a batch, you get the same list of IDs.
Rules
| Rule | Detail |
|---|---|
| Where it applies | POST /emails and POST /emails/batch. Other endpoints ignore the header. |
| Key format | 1 to 256 characters. Anything else returns 400 invalid_idempotency_key. |
| Lifetime | 24 hours. After that the key is forgotten and can be reused. |
| Scope | Per team. Two teams can use the same key string without interfering. |
| Same key, same body | Returns the original IDs. The retry does not use any quota. |
| Same key, different body | Returns 409 invalid_idempotent_request. |
Sooner compares the exact request body text, so a change in whitespace or in the order of fields counts as a different body. Build the body once and reuse the same string when you retry.
What is recorded
A key is only recorded once the request has passed validation and the quota check. If a request is rejected with a 422, a 429 or an error on our side, the key is released, and you can retry with the same key after you fix the problem.
If two identical requests with the same key arrive at the same time, both receive the same IDs and the email is sent once.
Choosing a key
Use a value that identifies the business event, so that the same event always produces the same key and different events never share one:
welcome-user-123invoice-8841-receiptpassword-reset-followed by the reset token ID
Avoid random values generated inside the retry loop, because each retry would get a new key and defeat the protection. Generate the key once, before the first attempt.
With the Node SDK
import { Resend } from "resend";
const resend = new Resend(process.env.SOONER_API_KEY, { baseUrl: "https://api.sooner.dev" });
const { data, error } = await resend.emails.send(
{
from: "Acme <hello@mail.yourcompany.com>",
to: ["user@example.com"],
subject: "Welcome",
html: "<p>Thanks for signing up</p>",
},
{ idempotencyKey: "welcome-user-123" },
);With Python
import os
import requests
res = requests.post(
"https://api.sooner.dev/emails",
headers={
"Authorization": f"Bearer {os.environ['SOONER_API_KEY']}",
"Idempotency-Key": "welcome-user-123",
},
json={
"from": "Acme <hello@mail.yourcompany.com>",
"to": ["user@example.com"],
"subject": "Welcome",
"html": "<p>Thanks for signing up</p>",
},
timeout=15,
)
print(res.status_code, res.json())