Idempotency
Learn how to safely retry mutations using the Idempotency-Key header to prevent duplicate side effects
When network failures or timeouts occur, retrying a mutation can accidentally create duplicate side effects — for example, creating the same item twice. The Idempotency-Key header lets you safely retry mutations without worrying about duplicates.
How it works
Send a unique Idempotency-Key header with any mutation request. The API uses this key to deduplicate retries:
- First request: Executes normally and caches the response for 30 minutes.
- Retry with same key: Returns the cached response with an
Idempotency-Replayed: trueheader — no duplicate side effect occurs. - Concurrent duplicate: Returns
409 Conflictwith aRetry-Afterheader indicating when to retry.
Best practiceAlways include an
Idempotency-Keyheader when retrying mutations in production, especially for operations likecreate_item,create_board, or any mutation that creates or modifies resources.
Using the Idempotency-Key header
Idempotency-Key headerInclude a unique string value (e.g., a UUID) in the Idempotency-Key request header:
fetch("https://api.monday.com/v2", {
method: "post",
headers: {
"Content-Type": "application/json",
"Authorization": "{API_TOKEN}",
"API-Version": "2025-07",
"Idempotency-Key": "YOUR_UNIQUE_IDEMPOTENCY_KEY"
},
body: JSON.stringify({
query: `mutation { create_item(board_id: 123456, item_name: "New item") { id } }`
})
});curl -X POST 'https://api.monday.com/v2' \
-H "Authorization: {API_TOKEN}" \
-H "Content-Type:application/json" \
-H "API-Version:2025-07" \
-H "Idempotency-Key:YOUR_UNIQUE_IDEMPOTENCY_KEY" \
--data-raw '{"query":"mutation { create_item(board_id: 123456, item_name: \"New item\") { id } }"}'Response headers
| Header | Description |
|---|---|
Idempotency-Replayed | Set to true when the response is served from cache (i.e., this is a replayed retry, not a fresh execution). |
Rules and constraints
| Rule | Detail |
|---|---|
| Mutations only | The header is ignored on queries (reads are inherently idempotent). |
| POST only | Only applies to POST requests. |
| Cache duration | Cached responses expire after 30 minutes. After expiration, the same key will execute fresh. |
| Key format | Any non-empty string. We recommend UUIDs. |
| Per-user budget | Each user+app combination has a memory budget for cached responses. If the budget is exceeded, new responses will execute but won't be cached for replay. |
| Max response size | Responses larger than 1 MB are not cached. |
Error responses
409 — Concurrent duplicate
If a request with the same idempotency key is already being processed, the API returns:
{
"errors": [
{
"message": "A request with this idempotency key is currently being processed",
"extensions": {
"code": "IDEMPOTENCY_CONFLICT"
}
}
]
}The response includes a Retry-After header. Wait the indicated time and retry — the cached response will then be available.
When to use idempotency keys
| Scenario | Use idempotency key? |
|---|---|
| Retrying after a network timeout | ✅ Yes |
| Retrying after a 5xx server error | ✅ Yes |
| Retrying after a rate limit (429) | ❌ No — the original request wasn't processed, so no duplicate risk. |
| Automated/webhook-triggered mutations | ✅ Yes — derive the key from the triggering event ID. |
| Batch imports | ✅ Yes — use a per-record key to allow safe resume after partial failure. |
Generating idempotency keys
Good keys are:
- Unique per intended operation — a UUID generated at the first attempt, reused on retries.
- Deterministic for the same intent — if retrying, send the same key; don't generate a new one.
Examples:
uuid()— generated once when the user clicks "Create", reused on retries.${webhookEventId}-create-item— for webhook-driven automations.${importBatchId}-row-${rowIndex}— for batch imports.
WarningDo not generate a new key on every retry attempt. The key must remain the same across retries for deduplication to work. Store the key alongside the request so retries use the same value.
