Idempotency
Retry requests safely: an Idempotency-Key makes sure the same email is never sent twice.
Networks fail. If your server sends a request and the connection drops before the response arrives, you cannot tell whether the email was accepted. Send an Idempotency-Key header and you can retry without risk: Cresca returns the first result instead of sending again.
curl -X POST 'https://api.cresca.xyz/api/v1/emails' \
-H 'Authorization: Bearer cr_live_xxxxxxxxx' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: order-confirmation/order-1042' \
-d '{
"from": "Acme <orders@acme.com>",
"to": "user@example.com",
"subject": "Your order #1042 is confirmed",
"html": "<p>Thanks for your order.</p>"
}'Rules
| Situation | Result |
|---|---|
| Same key, same body, within 24 hours | The original response, with the header idempotent-replayed: true. Nothing is sent again. |
| Same key, different body | 409 invalid_idempotent_request |
| Same key while the first request is still running | 409 concurrent_idempotent_requests. Retry shortly. |
| The first request failed (any error) | The key is released, so the retry is processed normally. |
| More than 24 hours later | The key has expired and the request is treated as new. |
Keys are 1 to 256 characters and are scoped to your account. A key outside that length gets 400 invalid_idempotency_key. Keys work on POST /emails and POST /emails/batch; for a batch, one key covers the whole request.
Choosing keys
Derive the key from the event that caused the email, not from the time or a fresh random value, so every retry produces the same key. A good pattern is <event>/<id>:
welcome/user-123password-reset/reset-request-9f2cinvoice/inv-2026-0042
A new password-reset request is a new event: give it a new id, so a person who asks twice gets two emails.
When to retry
Retry on network errors, timeouts, 429 and 5xx responses, with exponential backoff (for example 1s, 2s, 4s, 8s) plus a little random jitter. Do not retry other 4xx responses: fix the request first. See Errors.