Errors
Every error has the same shape. Branch on code, show message to people.
{
"error": {
"type": "invalid_request",
"code": "amount_below_minimum",
"message": "amount must be at least 10000.00 IDR",
"param": "amount.value",
"details": [],
"requestId": "…"
}
}
typesays what kind of problem it is, one per HTTP status family below.codeis a stable string. New codes can appear, so keep a default branch.messageis English and safe to show, but not meant to be matched on.paramnames the request field at fault. When several rules break,detailshas one item per broken rule.requestIdis also sent in theX-Request-IDheader. Quote it to support.
| type | HTTP | Example codes | Retry? |
|---|---|---|---|
invalid_request | 400 | invalid_body, unknown_field, field_required, amount_below_minimum | No, fix the request |
authentication | 401 | api_key_invalid | No |
permission | 403 | permission_denied, mode_mismatch | No |
not_found | 404 | payment_not_found | No |
conflict | 409 | duplicate_reference, invalid_state_transition, attempt_in_progress, idempotency_key_in_progress | Only *_in_progress, with the same key |
idempotency_error | 422 | idempotency_key_reused | No, use a new key |
rate_limit | 429 | rate_limited | Yes, after Retry-After |
provider_unavailable | 503 | provider_unavailable | Yes, with the same key |
api_error | 500 | internal_error | Yes, with the same key |
When a request times out or answers 5xx you do not know the outcome. Retry with the same Idempotency-Key, or read the object, before you do anything else.
Declined is not an error
A payer whose bank refuses a payment does not cause an API error. The attempt ends with status failed and a failure.code of declined or processing_error. The payment itself stays pending and can be paid by a new attempt until it expires.