Skip to content

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 StatusError CodeDeskripsiKapan Terjadi
400BAD_REQUESTRequest tidak validAmount ≤ 0, currency bukan 3 karakter, format email salah
400PAYMENT_METHOD_UNAVAILABLEMetode pembayaran tidak tersediaMethod belum dikonfigurasi di routing rule tenant, atau tidak didukung provider
401UNAUTHORIZEDAutentikasi gagalAPI key tidak valid, JWT expired atau tidak valid, header Authorization tidak ada
403FORBIDDENTidak punya aksesTenant bukan role Client saat create payment, atau akses resource tenant lain
404NOT_FOUNDResource tidak ditemukanPayment ID tidak ada atau milik tenant berbeda
409CONFLICTKonflik dataDuplikasi data atau pelanggaran business rule
409IDEMPOTENCY_CONFLICTIdempotency key konflikX-Idempotency-Key yang sama dikirim dengan payload berbeda
409INVALID_STATE_TRANSITIONTransisi status tidak validMencoba cancel payment yang sudah paid atau expired
429RATE_LIMIT_EXCEEDEDRate limit terlampauiTerlalu banyak request dalam jangka waktu singkat
500INTERNAL_ERRORError internal serverKegagalan internal yang tidak terduga. Bersifat transient — aman untuk di-retry dengan exponential backoff
502PROVIDER_ERRORError dari provider eksternalWinpay atau Midtrans mengembalikan error
503CIRCUIT_BREAKER_OPENCircuit breaker aktifProvider bermasalah berulang kali dalam waktu singkat — tunggu beberapa menit sebelum retry
504PROVIDER_TIMEOUTProvider timeoutWinpay atau Midtrans tidak merespons dalam batas waktu
504REQUEST_TIMEOUTRequest timeout globalRequest melampaui batas waktu server

💡 Catatan tentang error 5xx: Error dengan HTTP status 500, 502, 503, dan 504 bersifat 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 → refunded

Mencoba transisi di luar yang diizinkan akan menghasilkan error INVALID_STATE_TRANSITION (HTTP 409).


Tips Penanganan Error

  1. Selalu cek field code untuk logika retry/branching, bukan field message
  2. Error 5xx umumnya bersifat sementara — implementasikan retry dengan exponential backoff
  3. Error PROVIDER_ERROR (502) berarti provider eksternal bermasalah — coba beberapa saat lagi
  4. Error CIRCUIT_BREAKER_OPEN (503) — provider sedang dalam mode recovery, tunggu beberapa menit
  5. Error IDEMPOTENCY_CONFLICT (409) — jangan retry dengan key yang sama jika payload berbeda, gunakan key baru
  6. Error PAYMENT_METHOD_UNAVAILABLE (400) — pastikan routing rule sudah dikonfigurasi di dashboard untuk method yang digunakan

Gerbang Pay API Documentation