Idempotency Support
Overview
To ensure safe retry behavior and prevent duplicate processing, our API now supports idempotent POST operations using the X-Idempotency-Key
request header.
This feature is particularly useful in distributed or unreliable network environments where retries may occur due to timeouts or failures. It guarantees that a given operation is executed at most once, even if the request is sent multiple times.
How to Use
1. Set the X-Idempotency-Key
Header
X-Idempotency-Key
HeaderAll POST
endpoints support idempotency.
To activate this feature, include the following HTTP header in your request:
X-Idempotency-Key: <your-unique-key>
- The key must be a unique, client-generated string (UUIDs are a good fit).
- The key must be retained and reused in any retry attempts of the same operation.
- The key is expected to be unique per operation.
2. Key Is Scoped Per API Service Account
An idempotency key is only considered a match if:
- It is provided by the same authenticated API service account (e.g., machine identity).
- The endpoint (
POST
+ path) is the same.
What to Expect
Matching Requests
If a previously used idempotency key is sent again:
- The system will compare the request payload (body hash) with the original request.
- If the payload matches exactly, the original stored response will be returned (including HTTP status and body), without executing business logic again.
- If the payload does not match, a
400 Bad Request
will be returned indicating a hash mismatch. This is to prevent accidental reuse of keys for different operations.
Response Headers
Each response from an idempotent POST
request includes the following header:
X-Idempotency-Status: processed | replayed
processed
: The request was executed for the first time.replayed
: The response was replayed from storage based on a matching idempotency key.
Examples
First Request
POST /v1/{instance-id}/clients
X-Idempotency-Key: a1b2c3d4e5f6g7h8
Content-Type: application/json
Request Body:
{
"workflow": {
"code": "direct"
},
"data": {
"client": {
"identity": {
"type": "individual",
"givenName": "John",
"familyName": "Doe",
"country": "GB"
}
}
},
"connect": {},
"metadata": {}
}
Response:
201 Created
X-Idempotency-Status: processed
{
"workflow": {
"code": "direct",
"createUser": null
},
"data": {
"client": {
"id": "a116f50a-895d-472e-8cc1-31361ccccf56",
"clientNumber": "25822466",
"fullName": "John Doe",
"status": "active",
"identity": {
"type": "individual",
"country": "GB",
"identifications": [],
"givenName": "John",
"familyName": "Doe",
"birthDate": null
}
}
},
"connect": {},
"metadata": {}
}
Retry Request with Same Key and Same Body
POST /v1/{instance-id}/clients
X-Idempotency-Key: a1b2c3d4e5f6g7h8
Content-Type: application/json
Request Body:
{
"workflow": {
"code": "direct"
},
"data": {
"client": {
"identity": {
"type": "individual",
"givenName": "John",
"familyName": "Doe",
"country": "GB"
}
}
},
"connect": {},
"metadata": {}
}
Response:
201 Created
X-Idempotency-Status: replayed
{
"workflow": {
"code": "direct",
"createUser": null
},
"data": {
"client": {
"id": "a116f50a-895d-472e-8cc1-31361ccccf56",
"clientNumber": "25822466",
"fullName": "John Doe",
"status": "active",
"identity": {
"type": "individual",
"country": "GB",
"identifications": [],
"givenName": "John",
"familyName": "Doe",
"birthDate": null
}
}
},
"connect": {},
"metadata": {}
}
Retry Request with Same Key and Different Body
POST /v1/{instance-id}/clients
X-Idempotency-Key: a1b2c3d4e5f6g7h8
Content-Type: application/json
Request Body:
{
"workflow": {
"code": "direct"
},
"data": {
"client": {
"identity": {
"type": "individual",
"givenName": "John",
"familyName": "Doe",
"country": "GB"
}
}
},
"connect": {},
"metadata": {}
}
Response:
400 Bad Request
{
"timestamp": "2025-04-25T09:37:07.506972",
"code": "exatern.boot.infrastructure.functional.idempotency_request_body_mismatch",
"message": "Idempotency key matched with a previous request with a different body. Please check the body of the request and try again.",
"messageParameters": []
}
Updated 2 days ago