Error Codes
Semua error dari Gerbang Pay dikembalikan dalam format JSON yang konsisten.
Format Error Response
json
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Deskripsi error yang dapat dibaca manusia"
}
}Field code adalah string konstan yang dapat Anda gunakan untuk handle error secara programatik. Field message bersifat deskriptif dan dapat berubah — jangan gunakan untuk kondisional di kode Anda.
Tabel Error Codes
| HTTP Status | Error Code | Deskripsi | Kapan Terjadi |
|---|---|---|---|
400 | BAD_REQUEST | Request tidak valid | Amount ≤ 0, currency bukan 3 karakter, format email salah |
400 | PAYMENT_METHOD_UNAVAILABLE | Metode pembayaran tidak tersedia | Method belum dikonfigurasi di routing rule tenant, atau tidak didukung provider |
401 | UNAUTHORIZED | Autentikasi gagal | API key tidak valid, JWT expired atau tidak valid, header Authorization tidak ada |
403 | FORBIDDEN | Tidak punya akses | Tenant bukan role Client saat create payment, atau akses resource tenant lain |
404 | NOT_FOUND | Resource tidak ditemukan | Payment ID tidak ada atau milik tenant berbeda |
409 | CONFLICT | Konflik data | Duplikasi data atau pelanggaran business rule |
409 | IDEMPOTENCY_CONFLICT | Idempotency key konflik | X-Idempotency-Key yang sama dikirim dengan payload berbeda |
409 | INVALID_STATE_TRANSITION | Transisi status tidak valid | Mencoba cancel payment yang sudah paid atau expired |
429 | RATE_LIMIT_EXCEEDED | Rate limit terlampaui | Terlalu banyak request dalam jangka waktu singkat |
500 | INTERNAL_ERROR | Error internal server | Kegagalan internal yang tidak terduga. Bersifat transient — aman untuk di-retry dengan exponential backoff |
502 | PROVIDER_ERROR | Error dari provider eksternal | Winpay atau Midtrans mengembalikan error |
503 | CIRCUIT_BREAKER_OPEN | Circuit breaker aktif | Provider bermasalah berulang kali dalam waktu singkat — tunggu beberapa menit sebelum retry |
504 | PROVIDER_TIMEOUT | Provider timeout | Winpay atau Midtrans tidak merespons dalam batas waktu |
504 | REQUEST_TIMEOUT | Request timeout global | Request melampaui batas waktu server |
💡 Catatan tentang error
5xx: Error dengan HTTP status500,502,503, dan504bersifat transient (sementara). Implementasikan mekanisme retry dengan exponential backoff di sisi klien Anda untuk kasus ini.
400 Bad Request — Amount Invalid
json
{
"success": false,
"error": {
"code": "BAD_REQUEST",
"message": "bad request: Amount must be greater than zero"
}
}401 Unauthorized — API Key Tidak Valid
json
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "unauthorized: Invalid API Key"
}
}403 Forbidden — Role Bukan Client
json
{
"success": false,
"error": {
"code": "FORBIDDEN",
"message": "forbidden: Only client tenants are authorized to process payments"
}
}404 Not Found — Payment Tidak Ditemukan
json
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "not found: payment with id 550e8400-e29b-41d4-a716-446655440000"
}
}409 Idempotency Conflict
json
{
"success": false,
"error": {
"code": "IDEMPOTENCY_CONFLICT",
"message": "idempotency conflict: Same key submitted with different payload"
}
}409 Invalid State Transition
json
{
"success": false,
"error": {
"code": "INVALID_STATE_TRANSITION",
"message": "invalid state transition: from paid to cancelled"
}
}400 Payment Method Unavailable
json
{
"success": false,
"error": {
"code": "PAYMENT_METHOD_UNAVAILABLE",
"message": "payment method unavailable: No routing rule configured for e_wallet"
}
}429 Rate Limit Exceeded
json
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Please slow down and retry."
}
}502 Provider Error
json
{
"success": false,
"error": {
"code": "PROVIDER_ERROR",
"message": "provider error [winpay]: Code: 400 | Status: Bad Request | Body: ..."
}
}503 Circuit Breaker Open
json
{
"success": false,
"error": {
"code": "CIRCUIT_BREAKER_OPEN",
"message": "circuit breaker open for provider: winpay"
}
}State Machine Payment
Payment memiliki status yang mengikuti state machine ketat. Transisi yang diizinkan:
pending → paid
pending → failed
pending → expired
pending → cancelled
pending → challenged
challenged → paid
challenged → failed
paid → paid (duplikat callback, diabaikan)
paid → refunding
paid → partially_refunded
partially_refunded → partially_refunded
partially_refunded → refunding
refunding → refundedMencoba transisi di luar yang diizinkan akan menghasilkan error INVALID_STATE_TRANSITION (HTTP 409).
Tips Penanganan Error
- Selalu cek field
codeuntuk logika retry/branching, bukan fieldmessage - Error
5xxumumnya bersifat sementara — implementasikan retry dengan exponential backoff - Error
PROVIDER_ERROR(502) berarti provider eksternal bermasalah — coba beberapa saat lagi - Error
CIRCUIT_BREAKER_OPEN(503) — provider sedang dalam mode recovery, tunggu beberapa menit - Error
IDEMPOTENCY_CONFLICT(409) — jangan retry dengan key yang sama jika payload berbeda, gunakan key baru - Error
PAYMENT_METHOD_UNAVAILABLE(400) — pastikan routing rule sudah dikonfigurasi di dashboard untuk method yang digunakan