Idempotency keys
POST /prospects, POST /suppressions and POST /hooks accept an optional Idempotency-Key header. With a key, you can retry a request after a timeout and be sure it runs once.
curl -X POST "https://app.anymail.watch/api/v1/prospects" \
-H "Authorization: Bearer $ANYMAIL_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 5f1c0e1a-2b7d-4a4e-9c1a-0f1e2d3c4b5a" \
-d '{"email":"ada@example.com"}'
The key is a string of 1 to 255 characters. A UUID v4 is a good choice.
What happens#
| Situation | Result |
|---|---|
| First request with the key | It runs as usual. The status and JSON body are stored for the workspace for 24 hours. |
| Same key, same method, same path with query, same body byte for byte | The stored status and body return without running the request. The response has Idempotent-Replayed: true. |
| Same key, a different request | 422 with {"error":"Idempotency-Key was already used with a different request."} |
| Same key while the first request is still running | 409 with {"error":"A request with this Idempotency-Key is still being processed."}. Retry shortly. |
| Empty key, or longer than 255 characters | 400 with {"error":"Idempotency-Key must be between 1 and 255 characters."} |
Details that matter#
- The API stores
2xxand4xxresponses. A409duplicate is stored too, so a replay returns what the first call returned. - The API does not store
5xxresponses. After a server fault, a retry with the same key runs again. - The key belongs to the workspace. Two tokens of one workspace share one key space.
- The API compares the body as raw bytes. The same JSON with the keys in another order is a different request and returns
422. Resend an identical payload. - A replay uses a request of your rate limit.
- Without the header, nothing changes. A repeated
POST /prospectswithout a key returns409withcode: "duplicate".
Endpoints that ignore the header#
PATCH /prospects/{id} and DELETE /hooks/{id} ignore the header, because repeating them gives the same result. The same applies to POST /campaigns/{id}/pause, POST /campaigns/{id}/resume, PATCH /replies/{id} and DELETE /suppressions/{id}. A repeated POST /campaigns/{id}/prospects returns already-enrolled for each person who is already enrolled.