Errors
Every error returns a consistent JSON envelope and a matching HTTP status. Stack traces are never leaked.
Error envelope
{
"error": "invalid_request",
"message": "amount must be a positive decimal string",
"request_id": "req_7s1jH9nRqYRvLW1U4K6x"
}Always log request_id — quote it in support requests to trace the exact call.
Error codes
| HTTP | error | Meaning |
|---|---|---|
| 400 | invalid_request | Malformed or invalid parameters. |
| 401 | unauthorized | Missing, invalid, or revoked API key. |
| 402 | quota_exceeded | Plan quota reached — upgrade or wait for the next period. |
| 403 | forbidden | Authenticated but not allowed (role/ABAC). |
| 404 | payment_not_found | The resource doesn’t exist or isn’t in your scope. |
| 409 | idempotency_conflict | An Idempotency-Key was reused with a different payload. |
| 429 | rate_limit_exceeded | Too many requests — back off and retry. |
| 5xx | internal_error | Something went wrong on our side. Safe to retry idempotently. |
| 502 | provider_error | The upstream Bakong provider returned an error. |
Handling errors well
- Retry
429and5xxwith exponential backoff; always send anIdempotency-Keyon creates so retries are safe. - Treat
4xx(except 429) as terminal — fix the request, don’t retry. - Surface
messageto your developers, not end users; show a generic message to customers.