Idempotency
Retry POST requests safely with the Idempotency-Key header, without creating duplicate payments or refunds.
Networks fail. If a request to create a payment or refund times out, you can't tell whether Teyra Pay received it. Send an Idempotency-Key header, and you can retry the exact same request safely: Teyra Pay performs it at most once.
curl https://api.teyra.co/v1/payments \
-H "Authorization: Bearer $TEYRA_SECRET_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042-attempt-1" \
-d '{"amount": 12500, "currency": "KWD", "return_url": "https://shop.example.com/thanks"}'How it works
Every POST /v1/* request accepts the header. The key is any string of 1 to 255 characters; an empty or longer key fails with 422 validation_error.
| You send | Teyra Pay returns |
|---|---|
| A new key | Processes the request and stores the response with the key. |
| The same key and the same request (path and body) | The stored response (same status, same object) with the header Idempotent-Replayed: true. Nothing is created twice. |
| The same key and a different request | 409 idempotency_conflict. |
| The same key while the first request is still running | 409 conflict. Retry shortly with the same key. |
Keys are scoped to your account and mode, and are remembered for 24 hours. Responses with a 409, 429 or 5xx status are not stored, so a retry with the same key runs the request again. Other 4xx responses, such as 422 validation_error, are stored like successes.
Choosing keys
- Derive the key from your identifiers so it's stable across retries:
order-1042-attempt-1,refund-order-1042-item-3, or a UUID you store with the order before calling the API. - Use a new key for a genuinely new operation, for example when the customer tries to pay again after a failed payment:
order-1042-attempt-2. - Don't reuse a key for a different request. A changed body with the same key is rejected.
When to retry
| Situation | Retry with the same key? |
|---|---|
| Timeout or connection error | Yes |
429 rate_limited | Yes, after a delay |
500 internal_error, 502 gateway_error | Yes, after a delay |
4xx validation or auth errors | No. Fix the request first; a fixed request needs a new key because its body changed. |
Use exponential backoff, for example 1 s, 2 s, 4 s, 8 s, with a little random jitter.
GET and DELETE requests are naturally idempotent and don't need the header.