Guides
Idempotency and retries
How each API handles a request sent twice, and how to retry safely.
Each API protects against a request sent twice in its own way, described here as it behaves today.
Dynamic Audience API
The Dynamic Audience API reads no Idempotency-Key header. Instead:
- A request that sends the same addresses to the same campaign within 15 minutes returns the stored response instead of running again, even when names or custom fields changed, unless that response mailed nobody.
- An address mailed for a campaign is not mailed again for that campaign for 30 days, or for the campaign's re-send protection window when that is on and longer (90 days by default). It comes back as
duplicate_recent.
504) or a dropped connection may come after some recipients were mailed. Send the same payload again: no one is mailed twice. Within 15 minutes of a request that finished, you get its stored response; otherwise recipients already mailed come back as duplicate_recent. If a request times out, wait 20 minutes, then send it again. Recipients it already mailed come back as duplicates; the rest are mailed once.Integrations push API
Begin a sync, Complete a sync, and Push records each need an Idempotency-Key header. A ?validate=1 dry run does not.
- Use a new key for each request, up to 200 characters, for example
2026-10-03-records-2. Never use one key for a whole day or a whole run. - A key is bound to its endpoint and its body. A retry with the same key and the same body replays the stored response, so a timeout is always safe to retry.
- The same key with a different body or on a different endpoint returns
409 idempotency_key_reused. - A retry while the first attempt is still running returns
409 in_progress. Wait a few seconds and retry with the same key. - A missing key returns
400 missing_idempotency_key.
curl https://www.postaged.com/api/integrations/push/v1/sync \
-H "Authorization: Bearer $POSTAGED_API_KEY" \
-H "Idempotency-Key: 2026-10-03-begin-1" \
-H "Content-Type: application/json" \
-d '{
"mode": "full"
}'const response = await fetch("https://www.postaged.com/api/integrations/push/v1/sync", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POSTAGED_API_KEY}`,
"Idempotency-Key": "2026-10-03-begin-1",
"Content-Type": "application/json",
},
body: JSON.stringify({
mode: "full",
}),
});
const result = await response.json();
console.log(result);import os
import requests
response = requests.post(
"https://www.postaged.com/api/integrations/push/v1/sync",
headers={
"Authorization": f"Bearer {os.environ['POSTAGED_API_KEY']}",
"Idempotency-Key": "2026-10-03-begin-1",
},
json={
"mode": "full",
},
timeout=300,
)
print(response.json())missing_idempotency_key400
{
"error": {
"code": "missing_idempotency_key",
"message": "Send an Idempotency-Key header so a retry cannot open a second sync."
}
}idempotency_key_reused409
{
"error": {
"code": "idempotency_key_reused",
"message": "That Idempotency-Key was used for a different request. Use a new key."
}
}in_progress409
{
"error": {
"code": "in_progress",
"message": "That request is still being processed."
}
}Webhooks
A delivery can arrive more than once: a retry, or a delivery you send again with Redeliver, carries the same webhook-id header. Keep the ids you've processed and skip one you've already seen. See Webhooks.