Idempotency
Learn how to use the Idempotency-Key header to safely retry requests without creating duplicate orders.
The lemon.markets Brokerage API supports an Idempotency-Key header that lets you safely retry write operations without risk of creating duplicates. The header follows the IETF draft standard for idempotency keys — the same pattern used by Stripe, Adyen, and other payment APIs. The mechanism is designed to extend to other write operations over time and is currently supported on the following endpoints:
POST /v1/accounts/{account_id}/orders
Why Idempotency Matters
Network failures, timeouts, and unexpected disconnections are unavoidable in distributed systems. When a client sends a request but does not receive a response, it has no way to know whether the server processed the request or not. In a brokerage context, blindly retrying an order placement could result in a duplicate order. The Idempotency-Key header solves this by allowing the server to recognise a retry and return the original response instead of creating a new resource.
How It Works
To use idempotency, include the Idempotency-Key header with a unique string value in your request. UUIDs are recommended, but any string up to 100 characters works.
When the server receives a request with an Idempotency-Key:
- First request succeeds (
201 Created): The response is cached against the key. - Replay (a second request) with the same key and same payload: The server returns the cached response without creating a duplicate resource.
- Replay (a second request) with the same key but a different payload or different endpoint: The server returns a
422 Unprocessable Contenterror. - Key exceeds 100 characters: The server returns a
422 Unprocessable Contenterror. - First request fails validation (e.g.
400,422): No idempotency record is created and the key remains unused — you can retry with a corrected payload using the same key. - Keys expire after 24 hours. After expiry, the cached response is no longer returned and the key can theoretically be reused.
The header is entirely optional. When omitted, the endpoint preserves its existing behaviour, ensuring full backward compatibility.
Generating an Idempotency Key
A quick way to generate a suitable key on the command line:
uuidgen | tr '[:upper:]' '[:lower:]'Any unique string up to 100 characters works. Most languages have a built-in UUID library (e.g. uuid.uuid4() in Python, crypto.randomUUID() in Node.js).
Placing an Order with an Idempotency Key
Include the Idempotency-Key header when creating an order:
curl --request POST \
--url https://sandbox.api.lemon.markets/v1/accounts/cusa_c2c3f89ec0524b6e818ce00c16e4897f/orders \
--header 'authorization: Bearer <your-api-key>' \
--header 'content-type: application/json' \
--header 'accept: application/json' \
--header 'Idempotency-Key: 4a3c7f2e-9b1d-4e5a-8f6c-0d2e3a4b5c6d' \
--data '
{
"side": "buy",
"type": "market",
"instrument": "US0378331005",
"amount": "100.00"
}
'A successful response looks like this:
{
"id": "ord_a1b2c3d4e5f647a8b9c0d1e2f3a4b5c6",
"side": "buy",
"type": "market",
"instrument": "US0378331005",
"amount": "100.00",
"quantity": null,
"fee": "0.00",
"fees": {
"base_amount": "0.00"
},
"currency": "EUR",
"history": [
{
"status": "created",
"timestamp": "2026-04-23T10:15:30.123456+00:00"
}
]
}If the client did not receive this response (e.g. due to a timeout), it can safely replay the exact same request. The server recognises the Idempotency-Key, skips order creation, and returns the cached response with the same ord_ identifier — no duplicate order is created.
For more details, see our API reference: Create Order.
Error Scenarios
Replaying an idempotency key with a different payload returns a 422:
curl --request POST \
--url https://sandbox.api.lemon.markets/v1/accounts/cusa_c2c3f89ec0524b6e818ce00c16e4897f/orders \
--header 'authorization: Bearer <your-api-key>' \
--header 'content-type: application/json' \
--header 'accept: application/json' \
--header 'Idempotency-Key: 4a3c7f2e-9b1d-4e5a-8f6c-0d2e3a4b5c6d' \
--data '
{
"side": "buy",
"type": "market",
"instrument": "DE0007236101",
"amount": "250.00"
}
'{
"message": "Unprocessable Content"
}NOTE: If the original request failed validation (e.g. an invalid ISIN), the key is not consumed. You can correct the payload and retry with the same key.
Key Behaviour Reference
| Scenario | Outcome |
|---|---|
| First request with a new key | Request processed normally; 201 response cached against the key |
| Replay with the same key and same payload | Cached 201 response returned; no duplicate created |
| Replay with the same key but different payload | 422 Unprocessable Content |
| Replay with the same key but different endpoint | 422 Unprocessable Content |
| Key exceeds 100 characters | 422 Unprocessable Content |
| Original request failed validation | Key remains unused; retry with corrected payload |
| Key older than 24 hours | Cached response expired; key available for reuse |
Further Reading
For the full parameter specification, see our API reference: Create Order.
Updated 20 days ago