Idempotency
The API supports idempotency so requests can be safely retried without executing the same operation twice. Useful when a call is interrupted in transit and you don't get a response — for example, a request to create a payable that drops on a network error can be retried with the same key, guaranteeing that only one record is created.
How to use it
Send the X-Idempotency-Key: <key> header on any POST, PUT, or PATCH request. The key is free-form, generated on your side. We recommend UUID v4 or any random string with enough entropy to avoid collisions.
curl -i \
-H "Authorization: Bearer $KOBANA_TOKEN" \
-H 'Content-Type: application/json' \
-H 'X-Idempotency-Key: 8c0f5d6e-3f8b-4cb5-9a47-d8f5b15e9b21' \
-H 'User-Agent: Meu Sistema (contato@example.com)' \
-d '{
"account_id": "00000000-0000-0000-0000-000000000001",
"description": "Aluguel Janeiro/2026",
"amount": "3500.00",
"due_date": "2026-01-10"
}' \
-X POST 'https://api.finance.kobana.com.br/v1/payables'
How it works
When the server receives a request carrying X-Idempotency-Key:
- Reserves the key atomically, scoped to the workspace. Two different workspaces can use the same key without conflict.
- Computes a request fingerprint — SHA-256 of
method + path + raw body. That hash is stored alongside the key. - Runs the handler. If it returns a response, the server records
status_code, body, and relevant headers tied to the key. - Marks the key as completed. Any new request with the same key within 24 hours receives the original response verbatim — same
status_code, same body, same headers — plus anX-Idempotency-Replayed: trueheader to indicate that it is a replay.
The layer records the result regardless of whether it succeeded or failed. Retries with the same key return the same result, including 5xx errors — to genuinely try again after a server error, generate a new key.
Limits
- Maximum key length: 255 characters.
- Retention: keys expire automatically 24 hours after creation.
- Scope: per workspace. A key used in one workspace does not interfere with another.
- Accepted characters: any printable UTF-8 string.
Conflicts
If the same key is reused with a different request (any change in method, path, or body), the API responds 409 conflict with details.reason = "idempotency_key_reused".
{
"error": {
"code": "conflict",
"message": "X-Idempotency-Key was already used with different request parameters. Reuse the original parameters or generate a new key.",
"details": { "reason": "idempotency_key_reused" }
}
}
Accepted methods
| Method | Accepts X-Idempotency-Key? |
|---|---|
POST | ✅ Yes |
PATCH | ✅ Yes |
GET | ❌ No (already idempotent by definition) |
DELETE | ❌ No (already idempotent by definition) |
Best practices
- One key per logical operation. Don't reuse the same key to create two different resources — you will get
409 conflict. - Persist the key alongside the operation state on your side, so a retry after a crash or restart uses the same key.
- Pair it with exponential backoff on
5xxor timeout responses. - Clean up the key after 24 hours. There is no benefit to keeping it on your side beyond that.