Idempotency and error handling
Idempotency
Every operation that creates a charge (POST /v1/payments, POST /v1/payment_links/{id}/pay) requires the Idempotency-Key header:
Idempotency-Key: 6e4b6f0a-a5f0-4b9a-9b8b-1a2b3c4d5e6f- Must be at least 8 characters. A v4 UUID works well.
- Use a different key per real charge attempt, and the same key when retrying the same request (for example, after a network timeout).
- If the header is missing, the request is rejected with
400 idempotency_key_requiredbefore anything is attempted.
Without this, a retry from your side after a timeout could create two charges for the same customer attempt — Paytami's idempotency mechanism prevents exactly that.
Error shape
Every public API error has the same shape:
{
"error": {
"code": "amount_below_minimum",
"message": "Minimum amount is 1000"
}
}Always use error.code for program logic — error.message is human-readable text and its wording can change without notice.
Error code catalog
| Code | HTTP | Meaning |
|---|---|---|
unauthorized | 401 | The api_key is missing, invalid, revoked, or expired. |
validation_error | 400 | The request body or query parameters don't match the expected shape. |
idempotency_key_required | 400 | Missing Idempotency-Key header, or shorter than 8 characters. |
idempotency_key_reused | 409 | A different charge already exists, created with that same idempotency key. |
amount_below_minimum | 400 | The amount is below the allowed minimum for that currency or link. |
amount_above_maximum | 400 | The amount exceeds the allowed maximum for that currency or link. |
amount_required | 400 | The payment link is variable-amount and no amount was provided. |
currency_not_supported | 400 | The currency isn't enabled for your merchant. |
method_not_supported | 400 | The payment method isn't available for that currency or merchant. |
unknown_payment | 404 | The payment id doesn't exist, or doesn't belong to the authenticated merchant. |
unknown_payment_link | 404 | The payment link doesn't exist. |
payment_not_payable | 409 | The payment no longer accepts charging (already paid, expired, or canceled). |
payment_link_not_payable | 409 | The link no longer accepts payment (expired, exhausted, or inactive). |
payment_not_refundable | 400 | The payment isn't in a state that allows a refund. |
refund_amount_exceeds_remaining | 400 | The refund amount exceeds what's left available on the charge. |
rate_limited | 429 | Too many attempts on a payment link in a short time. |
processor_unavailable | 503 | Processing isn't available right now — retry later. |
internal_error | 500 | Unexpected error on Paytami's side. |
TIP
This catalog is closed and owned by Paytami. If you see a code not in this table, report it — it isn't a case you should handle as if it were part of the contract.
Payment states
status on a Payment response is always one of these values:
| State | Meaning |
|---|---|
created | The charge was created and is waiting for the customer to complete payment. |
processing | The customer is completing payment (e.g. a bank transfer in progress). |
authorized | The payment method authorized the charge, pending capture. |
captured | The money was captured from the customer. |
pending_settlement | Pending settlement to Paytami. |
settled_to_paytami | Paytami has received the funds. |
available_to_merchant | Funds are available to your merchant. |
partially_refunded | Part of the original amount was refunded. |
refunded | The full amount was refunded. |
chargeback | The customer disputed the charge with their bank/issuer. |
failed | The payment attempt failed. |
canceled | The charge was canceled before completing. |
expired | The charge expired before the customer completed it. |
For "can I redirect the customer to pay this?" purposes, only created, processing, and authorized accept payment — any other state means the charge already resolved, one way or another.

