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

All 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": []
}