Guides

Idempotency

Network timeouts should never create duplicate invoices. Every POST that creates a resource requires an Idempotency-Key header, making retries safe by construction.

Semantics

  • The Idempotency-Key header is required on every business-resource create POST (invoices, customers, products, expenses, suppliers, accounts, transactions). Requests without it fail with 400 invalid_request. Webhook management endpoints do not use idempotency keys.
  • Keys are free-form strings up to 255 characters, scoped to your company. Use a UUID v4 per logical operation.
  • Keys and their responses are stored for 24 hours.
  • Repeating a request with a key already used for the same endpoint returns the original stored response — same status and body — with the header X-Idempotency-Replayed: true. No second resource is created.
  • Reusing a key for a different endpoint fails with 400 invalid_request.

Example

curl -X POST https://app.talero.dk/api/v1/customers \
  -H "X-API-Key: $TALERO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 018f6c1e-4a5b-7c6d-8e9f-0a1b2c3d4e5f" \
  -d '{ "name": "Nordisk Handel ApS", "email": "[email protected]" }'

First request:

HTTP/1.1 201 Created

{ "data": { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "Nordisk Handel ApS", ... } }

The identical request retried (for example after a timeout):

HTTP/1.1 201 Created
X-Idempotency-Replayed: true

{ "data": { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "Nordisk Handel ApS", ... } }

Recommended practice

  • Generate the key before sending the request and persist it alongside the pending operation, so a crashed process retries with the same key.
  • Derive one key per logical operation, not per HTTP attempt. Retries of the same operation must reuse the key; a genuinely new operation must get a new key.
  • Treat X-Idempotency-Replayed: true as confirmation that an earlier attempt already succeeded.
  • After 24 hours a key expires and the same key would create a new resource — do not rely on idempotency for retries spaced further apart than that.