Referensi API

API merchant RAGH Reader dipakai server Anda untuk membuat tagihan dan payout, membaca statusnya, dan mengelola webhook. Halaman ini memuat semua endpoint, field, batas validasi, dan kode error.

Spesifikasi mesin (OpenAPI 3.1) tersedia di /docs/openapi.yaml. File itu bisa diimpor ke Postman, Insomnia, atau generator klien.

Dasar

Base URL https://payment-reader.ragh.co.id
Prefix endpoint /api/v1
Format JSON UTF-8. Kirim Content-Type: application/json
Uang Integer rupiah, tanpa desimal. Rp 200.123 ditulis 200123
Waktu ISO-8601 dengan zona WIB, misalnya 2026-09-28T14:05:00+07:00
Versi API 2026-09-28 (juga tercantum di setiap webhook sebagai api_version)

Autentikasi

Setiap request membawa API key di header Authorization:

Authorization: Bearer rk_live_AbCdEf0123456789AbCdEf0123456789AbCdEf01

Kunci yang salah bentuk, tidak dikenal, atau sudah dicabut ditolak dengan 401 invalid_api_key.

Kunci uji dan kunci live

Prefix Mode Keterangan
rk_test_ Uji Hanya membuat dan membaca data uji (test: true). Tidak pernah cocok dengan transfer sungguhan. Tidak ditagih. Bisa memakai simulasi
rk_live_ Live Data sungguhan. Butuh verifikasi identitas (KYC)

Setiap endpoint hanya melihat data dengan mode yang sama dengan kuncinya. Tagihan uji tidak bisa dibaca dengan kunci live, dan sebaliknya. Rinciannya di Konsep: mode uji.

Scope

Setiap kunci punya daftar scope. Request ke endpoint di luar scope kunci ditolak dengan 403 insufficient_scope.

Scope Endpoint
payments:read GET /payments, GET /payments/{id}
payments:write POST /payments, POST /payments/{id}/extend, POST /payments/{id}/cancel, POST /payments/{id}/mark-paid
payouts:read GET /payouts, GET /payouts/{id}
payouts:write POST /payouts, POST /payouts/{id}/extend, POST /payouts/{id}/cancel, POST /payouts/{id}/mark-sent
mutations:read GET /mutations
webhooks:manage GET /webhook-events, POST /webhook-events/{id}/resend
(tanpa scope khusus) GET /bank-accounts, POST /test/simulate (khusus kunci uji)

Berikan scope seminimal mungkin. Contoh: server toko cukup payments:read dan payments:write.

Allowlist IP

Kunci bisa dibatasi ke daftar IP atau rentang CIDR (IPv4 dan IPv6), misalnya 203.0.113.10, 198.51.100.0/24. Request dari IP lain ditolak dengan 403 ip_not_allowed.

Kunci live dengan scope payouts:write wajib memakai allowlist IP. Kunci itu bisa membuat instruksi "transfer ke rekening X". Kalau bocor tanpa batasan, penyerang bisa menyisipkan instruksi transfer ke rekeningnya sendiri. Pakai kunci terpisah khusus payout, dan batasi ke IP server yang membuat payout. Aturan ini juga diperiksa di setiap request: kunci live payouts:write tanpa allowlist ditolak dengan 403 ip_allowlist_required.

Batas kecepatan

Paling banyak 300 request per menit per API key. Kelebihannya ditolak dengan 429 rate_limited. Tunggu sekitar satu menit, lalu coba lagi.

Jangan memakai polling cepat untuk menunggu status tagihan. Pakai webhook, dan pakai GET hanya untuk rekonsiliasi atau cadangan.

Format error

Semua error API memakai bentuk yang sama:

{
  "error": {
    "code": "validation_failed",
    "message": "Ada isian yang tidak valid.",
    "fields": {
      "amount": ["The amount field must be at least 1000."]
    }
  }
}

Daftar kode error

HTTP code Arti dan tindakan
401 invalid_api_key Header Authorization tidak ada, bentuk kunci salah, kunci tidak dikenal, kunci sudah dicabut, atau aplikasinya nonaktif
402 balance_low Saldo Kredit Layanan di bawah batas minus. Tagihan dan payout baru ditolak, yang sudah ada tetap diproses. Top-up dulu
402 subscription_expired Langganan berakhir dan tidak diperpanjang. Tagihan dan payout baru ditolak sampai langganan dibeli lagi
403 ip_not_allowed IP server Anda tidak ada di allowlist kunci
403 ip_allowlist_required Kunci live dengan scope payouts:write belum punya allowlist IP. Buat kunci baru dengan allowlist
403 insufficient_scope Kunci tidak punya scope untuk endpoint ini
403 account_suspended Layanan akun ditangguhkan admin. Tagihan dan payout baru ditolak, yang sudah ada tetap diproses
403 account_terminated Layanan akun diputus. Karena semua kunci ikut dicabut saat pemutusan, yang biasanya terlihat justru 401 invalid_api_key
403 kyc_required Kunci live dipakai sebelum verifikasi identitas selesai. Kunci uji tetap bisa dipakai
403 volume_cap_reached Akun perorangan melewati batas volume Rp 50 juta per bulan. Ajukan verifikasi badan usaha
403 test_key_required POST /test/simulate dipanggil dengan kunci live
404 not_found ID tidak ada, milik aplikasi lain, atau beda mode (uji vs live)
409 order_already_paid reference_id ini sudah lunas. error.payment berisi tagihan yang lunas. Jangan tagih lagi
409 payout_already_sent reference_id ini sudah terkirim. error.payout berisi payout yang terkirim. Jangan transfer lagi
409 payout_not_enabled Belum ada rekening dengan payout aktif, atau bank_code yang diminta belum aktif payout-nya
409 unique_code_exhausted Semua 999 kode unik untuk nominal ini di rekening itu sedang terkunci. Coba lagi nanti, ubah nominal, atau perpendek masa berlaku
409 not_extendable Tagihan atau payout tidak bisa diperpanjang: sudah selesai, dibatalkan, atau masa jedanya lewat. Buat yang baru
409 not_cancellable Hanya catatan berstatus pending yang bisa dibatalkan
422 validation_failed Isian tidak valid. error.fields berisi pesan per field. Juga dipakai bila bank_code bukan rekening aktif Anda
422 no_bank_account Kunci live dipakai sebelum ada rekening terverifikasi. Tambahkan rekening dari app RAGH Reader
429 rate_limited Lebih dari 300 request per menit
429 resend_cooldown Event yang sama sudah dikirim ulang manual kurang dari 60 detik lalu
lain http_<status> Error HTTP umum, misalnya http_405 untuk metode yang salah

Error 5xx dari server kami tidak selalu memakai format di atas. Aman untuk mengulang POST /payments dan POST /payouts dengan reference_id yang sama (lihat Aturan pemanggilan ulang).

ID dan format data

Awalan Objek Contoh
pay_ Tagihan pay_01j8zq5v3m7c2k9x4h6t1r0bna
po_ Payout po_01j8zr1c2d3e4f5g6h7j8k9m0n
mut_ Mutasi mut_01j8zqb7r2s3t4v5w6x7y8z9a0
evt_ Event webhook evt_01j8zqa2b3c4d5e6f7g8h9j0km

ID berupa awalan + 26 karakter huruf kecil dan angka. Perlakukan ID sebagai string utuh dengan panjang maksimal 40 karakter.

Nomor transaksi (tx_number) berbentuk <PREFIX>-<YYMMDD>-<urutan>, misalnya TKO-260928-0042. Lihat Konsep.

Ringkasan endpoint

Metode Path Scope
POST /api/v1/payments payments:write
GET /api/v1/payments?reference_id=… payments:read
GET /api/v1/payments/{id} payments:read
POST /api/v1/payments/{id}/extend payments:write
POST /api/v1/payments/{id}/cancel payments:write
POST /api/v1/payments/{id}/mark-paid payments:write
POST /api/v1/payouts payouts:write
GET /api/v1/payouts?reference_id=… payouts:read
GET /api/v1/payouts/{id} payouts:read
POST /api/v1/payouts/{id}/extend payouts:write
POST /api/v1/payouts/{id}/cancel payouts:write
POST /api/v1/payouts/{id}/mark-sent payouts:write
GET /api/v1/mutations mutations:read
GET /api/v1/bank-accounts —
GET /api/v1/webhook-events webhooks:manage
POST /api/v1/webhook-events/{id}/resend webhooks:manage
POST /api/v1/test/simulate — (kunci uji saja)

Tagihan

POST /api/v1/payments

Membuat tagihan (uang masuk). Balasan 201 untuk tagihan baru, atau 200 bila tagihan yang sudah ada dipakai lagi (reused: true).

Body:

Field Tipe Wajib Batas Keterangan
reference_id string Ya maks 128 ID order di sistem Anda. Satu order = satu reference_id, sehingga memanggil ulang selalu aman (lihat di bawah)
amount integer Ya 1.000 – 250.000.000 Nominal dasar, sebelum kode unik
bank_code string Tidak maks 16 Rekening tujuan: BCA, MANDIRI, BRI, BNI, GOPAY, SHOPEEPAY. Kunci uji juga menerima UJI. Tanpa field ini, dipilih rekening utama yang terpantau
expires_in_minutes integer Tidak 15 – 10.080 Masa berlaku. Bawaan 1.440 (24 jam)
description string Tidak maks 255 Keterangan tagihan
customer object Tidak Data pelanggan untuk analitik "top pelanggan"
customer.ref string Tidak maks 128 ID pelanggan di sistem Anda
customer.name string Tidak maks 190 Nama pelanggan
customer.contact string Tidak maks 190 Email atau nomor HP
tags array of string Tidak maks 20 item, masing-masing maks 64 Misalnya produk:kursus-a, kanal:instagram, untuk analitik "top sumber"
return_url string (URL) Tidak maks 255, hanya http:// atau https:// Alamat tujuan pembeli setelah membayar
metadata object Tidak JSON maks 4 KB Data bebas milik Anda. Dikembalikan apa adanya di API dan webhook

Mode uji atau live ditentukan oleh kunci, bukan oleh field di body.

Pemilihan rekening bila bank_code tidak dikirim:

  1. rekening utama, bila terpantau;
  2. rekening lain yang terpantau;
  3. rekening utama, meskipun tidak terpantau (tagihan dibuat dengan confirmation_delayed: true).

Bila bank_code dikirim tetapi rekening itu tidak aktif atau belum terverifikasi, balasannya 422 validation_failed dengan error.fields.bank_code.

Contoh request:

curl -X POST https://payment-reader.ragh.co.id/api/v1/payments \
  -H "Authorization: Bearer rk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "reference_id": "ORDER-123",
    "amount": 200000,
    "bank_code": "BCA",
    "expires_in_minutes": 1440,
    "description": "Kursus A",
    "customer": { "ref": "CUST-9", "name": "Budi", "contact": "081234567890" },
    "tags": ["produk:kursus-a", "kanal:instagram"],
    "return_url": "https://toko.contoh.id/order/123",
    "metadata": { "cart_id": "C-77" }
  }'

Contoh balasan 201:

{
  "id": "pay_01j8zq5v3m7c2k9x4h6t1r0bna",
  "tx_number": "TKO-260928-0042",
  "reference_id": "ORDER-123",
  "amount": 200000,
  "unique_code": 123,
  "total_amount": 200123,
  "bank": {
    "code": "BCA",
    "name": "BCA",
    "account_number": "1234567890",
    "account_holder": "PT CONTOH JAYA"
  },
  "status": "pending",
  "confirmation_delayed": false,
  "late": false,
  "paid_after_cancel": false,
  "match_type": null,
  "test": false,
  "description": "Kursus A",
  "customer": { "ref": "CUST-9", "name": "Budi", "contact": "081234567890" },
  "tags": ["produk:kursus-a", "kanal:instagram"],
  "metadata": { "cart_id": "C-77" },
  "expires_at": "2026-09-29T10:15:00+07:00",
  "paid_at": null,
  "expired_at": null,
  "cancelled_at": null,
  "created_at": "2026-09-28T10:15:00+07:00",
  "payment_url": "https://payment-reader.ragh.co.id/pay/pay_01j8zq5v3m7c2k9x4h6t1r0bna",
  "reused": false
}

Tampilkan ke pembeli: total_amount (bukan amount), bank, dan batas waktu. Atau cukup arahkan pembeli ke payment_url.

Error yang mungkin: 402 balance_low, 402 subscription_expired, 403 account_suspended, 403 account_terminated, 403 kyc_required, 403 volume_cap_reached, 409 order_already_paid, 409 unique_code_exhausted, 422 validation_failed, 422 no_bank_account.

Aturan pemanggilan ulang

Memanggil POST /api/v1/payments berulang kali dengan reference_id yang sama selalu aman. Ulangi saja bila koneksi putus atau server Anda tidak yakin apakah request sebelumnya berhasil.

reference_id unik per aplikasi dan per mode (uji/live). Hasilnya bergantung pada tagihan yang sudah ada:

Keadaan tagihan lama dengan reference_id sama Hasil HTTP
Ada yang sudah lunas Ditolak order_already_paid. error.payment berisi tagihan yang lunas 409
Pending, amount sama Tagihan yang sama dikembalikan, reused: true 200
Kedaluwarsa, masih dalam masa jeda, amount sama Tagihan yang sama dibuka lagi: status pending, batas waktu baru, kode dan total tetap, reused: true 200
Pending atau kedaluwarsa-dalam-jeda, amount berbeda Tagihan lama dibatalkan (totalnya tetap terkunci 48 jam), lalu tagihan baru dibuat 201
Tidak ada, sudah dibatalkan, atau masa jedanya sudah lewat Tagihan baru dibuat 201

Aturan yang sama berlaku untuk payout, dengan payout_already_sent sebagai pengganti order_already_paid.

Bila satu tagihan untuk sebuah reference_id lunas, tagihan lain yang masih pending untuk reference_id yang sama otomatis dibatalkan.

Saat tagihan lama dipakai lagi (reused: true), field lain di body (bank_code, description, dan seterusnya) diabaikan. Satu-satunya pengecualian: expires_in_minutes dipakai sebagai batas baru saat tagihan kedaluwarsa dibuka lagi.

GET /api/v1/payments/{id}

Membaca satu tagihan. Balasannya objek tagihan seperti di atas, tanpa field reused.

curl https://payment-reader.ragh.co.id/api/v1/payments/pay_01j8zq5v3m7c2k9x4h6t1r0bna \
  -H "Authorization: Bearer rk_live_…"

Tagihan milik aplikasi lain atau beda mode menghasilkan 404 not_found.

GET /api/v1/payments?reference_id=…

Semua tagihan untuk satu reference_id, terbaru dulu, paling banyak 50. Berguna untuk melihat riwayat satu order (misalnya tagihan lama yang dibatalkan karena nominal berubah).

Query Wajib Batas
reference_id Ya maks 128
{
  "data": [
    { "id": "pay_01j8zq5v3m7c2k9x4h6t1r0bna", "reference_id": "ORDER-123", "status": "paid", "…": "…" },
    { "id": "pay_01j8zp0a1b2c3d4e5f6g7h8j9k", "reference_id": "ORDER-123", "status": "cancelled", "…": "…" }
  ]
}

POST /api/v1/payments/{id}/extend

Memperpanjang tagihan yang sama. Kode unik dan total tetap. Ini cara yang benar untuk "bayar lagi" (lihat Konsep).

Field Wajib Batas Keterangan
expires_in_minutes Tidak 15 – 10.080 Batas baru dihitung dari sekarang. Bawaan 1.440

POST /api/v1/payments/{id}/cancel

Membatalkan tagihan pending. Body kosong.

POST /api/v1/payments/{id}/mark-paid

Menandai lunas dari sistem Anda, misalnya admin sudah melihat uangnya di mutasi bank sendiri. Body kosong. Sama dengan tombol Tandai lunas di dashboard:

Objek tagihan

Field Tipe Keterangan
id string ID tagihan (pay_…)
tx_number string Nomor transaksi berprefix
reference_id string | null ID order Anda
amount integer Nominal dasar
unique_code integer Kode unik 1–999
total_amount integer amount + unique_code. Yang harus ditransfer
bank object Rekening tujuan: code, name, account_number, account_holder
status string pending, paid, expired, cancelled
confirmation_delayed boolean true selama rekening tidak terpantau. Batas bayar ditahan
late boolean Lunas setelah kedaluwarsa, dalam masa jeda
paid_after_cancel boolean Lunas setelah dibatalkan
match_type string | null auto, manual, manual_unverified, atau null bila belum lunas
test boolean Data mode uji
description string | null
customer object | null ref, name, contact
tags array Selalu array, bisa kosong
metadata object Selalu objek, bisa kosong
expires_at string Batas bayar awal. Bisa lewat sementara status masih pending karena penahanan
paid_at string | null
expired_at string | null
cancelled_at string | null
created_at string
payment_url string Halaman bayar siap pakai

Payout

Payout mencatat transfer keluar yang akan Anda lakukan sendiri. Reader membuktikannya dari notifikasi uang keluar. Payout aktif per rekening setelah transfer uji keluar di app RAGH Reader (lihat Pasang RAGH Reader).

POST /api/v1/payouts

Body:

Field Tipe Wajib Batas Keterangan
reference_id string Ya maks 128 ID pencairan di sistem Anda. Aturannya sama dengan tagihan
amount integer Ya 1.000 – 250.000.000 Nominal hak penerima, sebelum kode unik
bank_code string Tidak maks 16 Rekening sumber. Harus rekening dengan payout aktif. Tanpa field ini, dipilih rekening utama yang terpantau
recipient object Ya Penerima
recipient.bank_code string Ya maks 16 Bank penerima, misalnya BCA
recipient.account_number string Ya maks 64 Nomor rekening penerima
recipient.account_name string Ya maks 190 Nama pemilik rekening penerima
expires_in_minutes integer Tidak 15 – 10.080 Bawaan 1.440
description string Tidak maks 255
tags array of string Tidak maks 20 item, masing-masing maks 64
metadata object Tidak JSON maks 4 KB

Contoh request:

curl -X POST https://payment-reader.ragh.co.id/api/v1/payouts \
  -H "Authorization: Bearer rk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "reference_id": "WD-456",
    "amount": 150000,
    "recipient": {
      "bank_code": "BCA",
      "account_number": "9876543210",
      "account_name": "BUDI SANTOSO"
    },
    "description": "Pencairan komisi September"
  }'

Contoh balasan 201:

{
  "id": "po_01j8zr1c2d3e4f5g6h7j8k9m0n",
  "tx_number": "TKO-260928-0043",
  "reference_id": "WD-456",
  "amount": 150000,
  "unique_code": 123,
  "total_amount": 150123,
  "source_bank": {
    "code": "MANDIRI",
    "name": "Livin' by Mandiri",
    "account_number": "1230000123456",
    "account_holder": "PT CONTOH JAYA"
  },
  "recipient": {
    "bank_code": "BCA",
    "account_number": "9876543210",
    "account_name": "BUDI SANTOSO"
  },
  "status": "pending",
  "confirmation_delayed": false,
  "late": false,
  "sent_after_cancel": false,
  "recipient_check": null,
  "match_type": null,
  "test": false,
  "description": "Pencairan komisi September",
  "tags": [],
  "metadata": {},
  "instruction": "Transfer tepat Rp 150.123 ke BCA 9876543210 a.n. BUDI SANTOSO",
  "expires_at": "2026-09-29T10:20:00+07:00",
  "sent_at": null,
  "expired_at": null,
  "cancelled_at": null,
  "reversed_at": null,
  "created_at": "2026-09-28T10:20:00+07:00",
  "reused": false
}

Tampilkan instruction ke admin yang mentransfer. Admin harus:

  1. mentransfer tepat total_amount dari rekening source_bank;
  2. memakai app bank di HP yang dibaca Reader;
  3. melakukan satu transfer per payout (bukan transfer massal).

Error yang mungkin: 402 balance_low, 402 subscription_expired, 403 account_suspended, 403 account_terminated, 403 kyc_required, 409 payout_already_sent, 409 payout_not_enabled, 409 unique_code_exhausted, 422 validation_failed.

GET /api/v1/payouts/{id}

Membaca satu payout. Balasannya objek payout tanpa reused.

GET /api/v1/payouts?reference_id=…

Semua payout untuk satu reference_id, terbaru dulu, paling banyak 50. Balasan: { "data": [ … ] }.

POST /api/v1/payouts/{id}/extend

Sama dengan perpanjangan tagihan. Body opsional expires_in_minutes (15 – 10.080). Kode dan total tetap. Selain pending atau expired dalam masa jeda: 409 not_extendable.

POST /api/v1/payouts/{id}/cancel

Membatalkan payout pending. Totalnya tetap terkunci 48 jam. Bila transfer tetap terjadi dalam masa itu, payout menjadi sent dengan late: true dan sent_after_cancel: true, lalu masuk perlu tindakan. Selain pending: 409 not_cancellable.

POST /api/v1/payouts/{id}/mark-sent

Menandai terkirim dari sistem Anda (cadangan bila notifikasi uang keluar tidak terbaca). Body kosong. Payout menjadi sent dengan match_type: "manual_unverified"; notifikasi uang keluar yang datang belakangan memverifikasinya (payout.verified). Sudah terkirim: 409 already_sent.

Objek payout

Field Tipe Keterangan
id string ID payout (po_…)
tx_number string Nomor transaksi berprefix
reference_id string | null
amount integer Nominal hak penerima
unique_code integer Kode unik 1–999, ditambahkan
total_amount integer Yang harus ditransfer
source_bank object Rekening sumber: code, name, account_number, account_holder
recipient object bank_code, account_number, account_name
status string pending, sent, expired, cancelled, reversed
confirmation_delayed boolean true selama rekening sumber tidak terpantau
late boolean Terkirim setelah kedaluwarsa, dalam masa jeda
sent_after_cancel boolean Terkirim setelah dibatalkan
recipient_check string | null match, mismatch, unavailable, atau null bila belum terkirim
match_type string | null auto, manual, manual_unverified
test boolean
description, tags, metadata Seperti tagihan
instruction string Kalimat instruksi transfer siap tampil
expires_at, sent_at, expired_at, cancelled_at, reversed_at, created_at string | null

Mutasi

GET /api/v1/mutations

Semua mutasi (notifikasi transaksi) yang tercatat di seluruh rekening akun Anda, terbaru dulu. Berguna untuk pembukuan dan rekonsiliasi. Mutasi ignored tidak ditampilkan.

Query Batas Keterangan
direction credit atau debit Masuk atau keluar
match_status maks 24 karakter Misalnya no_candidate
from tanggal Waktu diterima server ≥ nilai ini
to tanggal Waktu diterima server ≤ nilai ini
limit 1 – 200 Bawaan 100

Tulis from dan to dalam WIB, dengan format 2026-09-28 atau 2026-09-28 14:00:00. Tanggal tanpa jam berarti pukul 00.00, jadi untuk "sampai akhir 28 September" pakai to=2026-09-28 23:59:59.

{
  "data": [
    {
      "id": "mut_01j8zqb7r2s3t4v5w6x7y8z9a0",
      "bank": "BCA",
      "direction": "credit",
      "kind": "transfer_in",
      "amount": 200123,
      "fee_amount": null,
      "counterparty_name": "BUDI SANTOSO",
      "match_status": "matched",
      "is_match": true,
      "payment_id": "pay_01j8zq5v3m7c2k9x4h6t1r0bna",
      "payout_id": null,
      "transaction_at": "2026-09-28T10:31:00+07:00",
      "received_at": "2026-09-28T10:31:04+07:00",
      "test": false
    }
  ]
}
Field Keterangan
bank Kode bank rekening Anda (string)
direction credit (masuk) atau debit (keluar)
kind transfer_in, qris_in, transfer_out, purchase, fee, reversal, interest
fee_amount Biaya transfer bila tertulis terpisah di notifikasi
counterparty_name Nama pengirim (masuk) atau penerima (keluar) dari notifikasi. Bisa kosong atau terpotong
match_status Lihat Konsep: status mutasi
transaction_at Jam transaksi dari teks notifikasi, bila bank menyertakannya
received_at Jam server menerima notifikasi

Rekening

GET /api/v1/bank-accounts

Rekening terverifikasi milik akun Anda, beserta status pemantauan dan payout. Bisa dipanggil dengan kunci apa pun.

{
  "data": [
    {
      "code": "BCA",
      "name": "BCA",
      "account_number": "1234567890",
      "account_holder": "PT CONTOH JAYA",
      "kind": "bank",
      "is_default": true,
      "monitored": true,
      "payout_enabled": false
    }
  ]
}
Field Keterangan
kind bank atau ewallet
is_default Rekening utama untuk tagihan tanpa bank_code
monitored true bila rekening sedang terpantau
payout_enabled true bila transfer uji keluar sudah berhasil

Event webhook

GET /api/v1/webhook-events

Event webhook aplikasi ini beserta percobaan kirim terakhirnya, terbaru dulu. Kunci uji hanya melihat event uji dan kunci live hanya melihat event live; event ping terlihat di keduanya. Aturan yang sama berlaku untuk POST /webhook-events/{id}/resend.

Query Batas Keterangan
status pending, delivered, rejected, failed
from tanggal Waktu event dibuat ≥ nilai ini (WIB)
limit 1 – 200 Bawaan 50
{
  "data": [
    {
      "id": "evt_01j8zqa2b3c4d5e6f7g8h9j0km",
      "type": "payment.paid",
      "status": "pending",
      "attempts": 3,
      "last_error_code": "INVALID_ACK",
      "next_attempt_at": "2026-09-28T10:52:05+07:00",
      "delivered_at": null,
      "created_at": "2026-09-28T10:31:05+07:00",
      "last_delivery": {
        "status_code": 200,
        "error_code": "INVALID_ACK",
        "ack_status": "invalid",
        "duration_ms": 184,
        "at": "2026-09-28T10:37:05+07:00"
      }
    }
  ]
}
status event Arti
pending Belum berhasil. Masih dalam jadwal kirim ulang, atau pengiriman sedang dijeda/dinonaktifkan
delivered Diterima sistem Anda dengan ack accepted atau duplicate
rejected Sistem Anda membalas ack rejected. Tidak dikirim ulang otomatis
failed Tidak berhasil dalam 72 jam. Masih bisa dikirim ulang manual

Arti error_code ada di Webhook: pemetaan respons.

POST /api/v1/webhook-events/{id}/resend

Mengirim ulang satu event seketika, sama dengan tombol "Kirim ulang sekarang" di dashboard.

Kirim ulang massal ("semua yang gagal dalam 30 menit terakhir") hanya tersedia di dashboard. Lihat Webhook.


Mode uji

POST /api/v1/test/simulate

Memalsukan notifikasi bank untuk tagihan atau payout uji, supaya Anda bisa menguji semua cabang webhook tanpa transfer sungguhan. Hanya bisa dengan kunci rk_test_. Kunci live: 403 test_key_required.

Field Tipe Wajib Keterangan
payment_id string Salah satu Tagihan uji yang disimulasikan (uang masuk)
payout_id string Salah satu Payout uji yang disimulasikan (uang keluar)
amount integer Tidak Nominal yang "ditransfer", minimal 1. Bawaan: total_amount
counterparty_name string Tidak Maks 190. Nama pengirim (tagihan) atau penerima (payout). Bawaan: PEMBELI SIMULASI untuk tagihan, nama penerima untuk payout
expire_first boolean Tidak Bila true dan catatannya pending, catatan dibuat kedaluwarsa dulu, sehingga hasilnya telat (late: true)

Balasan 200:

{
  "mutation": {
    "id": "mut_01j8zqb7r2s3t4v5w6x7y8z9a0",
    "bank": "UJI",
    "direction": "credit",
    "kind": "transfer_in",
    "amount": 150123,
    "fee_amount": null,
    "counterparty_name": "PEMBELI SIMULASI",
    "match_status": "matched",
    "is_match": true,
    "payment_id": "pay_01j8zq5v3m7c2k9x4h6t1r0bna",
    "payout_id": null,
    "transaction_at": null,
    "received_at": "2026-09-28T10:31:04+07:00",
    "test": true
  },
  "payment": { "id": "pay_01j8zq5v3m7c2k9x4h6t1r0bna", "status": "paid", "late": false, "test": true, "…": "…" }
}

Untuk payout, kunci kedua bernama payout, bukan payment.

Skenario yang bisa diuji:

Skenario Cara Webhook
Lunas {"payment_id": "…"} payment.paid
Lunas telat {"payment_id": "…", "expire_first": true} payment.paid dengan late: true
Lunas setelah dibatalkan Batalkan dulu, lalu simulasikan payment.paid dengan paid_after_cancel: true
Uang dobel Simulasikan dua kali untuk tagihan yang sama payment.duplicate
Transfer tanpa pasangan amount berbeda dari total mutation.unmatched, bila diaktifkan di pengaturan aplikasi
Payout terkirim {"payout_id": "…"} payout.sent dengan recipient_check: "match"
Penerima tidak cocok {"payout_id": "…", "counterparty_name": "ORANG LAIN"} payout.sent dengan recipient_check: "mismatch"
Payout dobel Simulasikan dua kali untuk payout yang sama payout.duplicate

Pengembalian dana bank (payout.reversed) belum bisa disimulasikan lewat API.


Riwayat versi

Versi Perubahan
2026-09-28 Versi pertama API merchant dan webhook