Skip to main content

Retries and idempotency

A network can fail after Kosoor has saved your request but before you read the answer. Retrying then must not create a second customer or invoice. Every POST and PATCH therefore carries an Idempotency-Key header, and a retry sends the same key.

curl https://api.kosoor.com.sa/v1/customers \
-H "Authorization: Bearer ksr_live_..." \
-H "Idempotency-Key: 9b2c4c0e-6a51-4c0b-8a43-3c2f2f1a7d10" \
-H "Content-Type: application/json" \
-d '{"type":"person","firstName":"Sara","phone":"+966501234567"}'

The key​

  • 1 to 255 printable ASCII characters, matched case-sensitively. A UUID per logical operation works well.
  • Keys belong to your API key: another key may use the same value without colliding.
  • Kosoor keeps a key for 30 days.

What a retry gets​

You sendKosoor answers
the same key with the same method, path and body, after a successthe stored reply, with Idempotent-Replayed: true; nothing runs again
the same key with a different request422 idempotency_key_reused
the same key while the first request is still running409 idempotency_in_progress with Retry-After: 1
the same key after a failurethe request runs again: only successful replies are stored
no key400 missing_idempotency_key

A request that died mid-way holds its key for 5 minutes; after that a retry with the same key runs it.

When to retry​

Retry with the same key on a timeout, a dropped connection, 409 idempotency_in_progress and any 5xx. Do not retry a 4xx unchanged: it will answer the same way. Fix the request and send it under a new key. Three refusals depend on time instead, and are retried later with the same key, since no 4xx reply is stored: 409 invoice_not_cleared, once ZATCA has cleared the invoice; 409 invoice_busy, after a few seconds; and 422 loyalty_refund_blocked, once, a few minutes later. If it is refused again, the merchant issues the credit note from the dashboard, where a supervisor may override.