Idempotent requests
A request can fail after Sursa has already done the work: the connection drops, or your process restarts before the
response arrives. If you send the same POST again, you could create a second card or a second webhook. An
idempotency key prevents that.
Send an Idempotency-Key header with every POST and PATCH. If Sursa has already seen a request with this key, it
does not run the operation again: it returns the response it saved the first time.
curl -X POST https://api.sursa.com/v1/cards/text \
-H "Authorization: Bearer $SURSA_API_KEY" \
-H "Idempotency-Key: 6f1d2c9e-7b0a-4c43-9a51-0d6c1c1f8e21" \
-H "Content-Type: application/json" \
-d '{"title": "Refund policy", "body_markdown": "Refunds are processed within 14 days."}'A repeated request gets the same status and body as the first one, with an extra header:
HTTP/1.1 200 OK
Idempotency-Replayed: true
X-Request-Id: 01JB7R…
The repeated request has its own X-Request-Id.
Choosing a key
- Use a new random value, such as a UUID v4, for each logical operation: "create this card", "register this webhook". Use the same value for every retry of that operation, and never for a different one.
- A good key is derived from your own data when you have one, for example
sync-2026-10-24-record-1042. Then even a restarted job that lost its memory sends the same key again. - The key is 1 to 255 printable ASCII characters. Anything else returns
400with the codeapi.idempotency_key_invalid.
What Sursa does with the key
| Situation | Response |
|---|---|
| First request with this key | The operation runs as usual. |
Same key, same request, the first one finished with 2xx or 4xx | The saved response, with Idempotency-Replayed: true. The operation does not run again. |
| Same key, the first request is still running | 409 api.idempotency_in_progress with Retry-After: 1. Wait and retry. |
Same key, a different method, path, Content-Type or body | 409 api.idempotency_mismatch. The key is already taken by another request. |
The first request finished with 5xx or 429 | The key is released: the next request with it runs the operation again. |
- A key is valid for 24 hours. After that, the same key starts a new operation.
- Keys are separate per organization and per caller: two different API keys can use the same value without affecting each other.
- An error response with
4xxis saved too. A request that failed validation fails the same way when it is repeated with the same key; fix it and send it with a new key.
Which requests need it
| Method | Idempotency-Key |
|---|---|
POST, PATCH | Send it. Every endpoint that saves its response for a repeat lists the header in the API reference. |
GET, PUT, DELETE | Not needed: these methods are safe to repeat by their meaning. The header is accepted and has no effect. |
POST that only reads, such as search, the financial reports and POST /v1/catalog/resolve | Accepted, but nothing is saved: the request simply runs again. |
Some operations are safe to repeat even without the header:
PUT /v1/cards-by-external-id/{external_id}creates or replaces the card with your ID; a repeat with the same content changes nothing.- Documents of a custom source are keyed by your
external_id; sending the same document again returnsunchanged. - A streamed answer of
POST /v1/chatuses therequest_idfield of the body instead of the header. See Build a Q&A bot.
Retrying safely
Combine the key with the retry rules from Errors: create the key once, before the first attempt, and send it with every attempt of the same operation.