Produk · Untuk developer
Virtual Account API: satu integrasi untuk delapan bank, nomor terbit saat dibuat
Virtual Account adalah nomor rekening yang diterbitkan untuk satu tagihan. Pembeli membukanya di aplikasi banknya, mentransfer nominal yang sudah tertera, dan pembayarannya cocok dengan tagihan itu tanpa ada yang membaca mutasi. Kasera Pay menerbitkan nomor itu untuk delapan bank lewat satu API, dan mengonfirmasi pelunasannya lewat webhook bertanda tangan. Halaman ini menjelaskan bentuk integrasinya, apa yang berbeda dari mendaftar langsung ke bank, dan apa yang perlu disiapkan.
Delapan bank, satu bentuk permintaan
Setiap bank dikenali dari kode metodenya. Bentuk permintaan, bentuk respons, dan alur konfirmasinya sama untuk kedelapannya; yang berubah hanya kodenya.
| Bank | Kode metode | Bentuk payment |
|---|---|---|
| BCA Virtual Account | va_bca | payment_code |
| BRI Virtual Account | va_bri | payment_code |
| BNI Virtual Account | va_bni | payment_code |
| Mandiri Virtual Account | va_mandiri | payment_code |
| Permata Virtual Account | va_permata | payment_code |
| CIMB Niaga Virtual Account | va_cimb | payment_code |
| Danamon Virtual Account | va_danamon | payment_code |
| Maybank Virtual Account | va_maybank | payment_code |
Daftar di atas adalah yang terdokumentasi hari ini, bukan daftar yang berlaku permanen. Metode bisa diaktifkan, dihentikan, atau diubah tarifnya tanpa rilis di sisi integrator, jadi daftar yang benar untuk sebuah akun dibaca dari GET /v1/payment_methods, lengkap dengan rentang nominal, kebutuhan data pembeli, dan tarif tiap metode. Jangan menuliskan kode bank maupun tarifnya permanen di kode. Rinciannya ada di dokumentasi metode pembayaran.
Nomornya terbit saat permintaan dibuat
Satu panggilan POST /v1/transactions membuat permintaan pembayaran dan mengembalikan nomornya di payment.payment_code. Nominal ditulis dalam rupiah utuh, dan customer.name wajib untuk metode va_ karena nama itu yang tampil di aplikasi bank pembeli.
curl https://pay.kasera.id/v1/transactions \
-H "Authorization: Bearer kp_test_..." \
-H "Idempotency-Key: invoice-2026-001" \
-H "Content-Type: application/json" \
-d '{
"amount": 750000,
"description": "Pelunasan pesanan INV-2026-001",
"external_id": "INV-2026-001",
"payment_methods": ["va_bca"],
"customer": { "name": "Budi Santoso" },
"return_url": "https://toko.example/selesai"
}'Respons 201:
{
"id": "payreq_9b2f...",
"status": "pending",
"amount": 750000,
"checkout_url": "https://pay.kasera.id/p/xK3f...",
"payment_method": "va_bca",
"payment": {
"type": "payment_code",
"payment_code": "8808 1234 5678 9012",
"display_name": "BCA Virtual Account"
},
"expires_at": "2026-09-16T13:00:00+07:00"
}Header Idempotency-Key adalah satu-satunya hal yang mencegah permintaan yang terkirim dua kali menjadi dua tagihan. Nilainya dibuat sebelum percobaan pertama dan dipakai ulang pada setiap retry.
Hosted checkout atau tampilkan nomornya sendiri
Responsnya membawa keduanya sekaligus. checkout_url mengarah ke halaman pembayaran yang dihosting Kasera Pay, lengkap dengan nomor, tombol salin, instruksi per bank, dan hitung mundur; tidak ada yang perlu dibangun. Untuk menampilkannya di dalam layar sendiri, yang dipakai adalah payment.payment_code ditambah blok instructions yang dikembalikan bersamanya, sehingga langkah membayarnya tidak perlu ditulis ulang per bank. Keduanya memakai endpoint create yang sama. Referensi lengkapnya ada di dokumentasi Virtual Account lewat Direct API.
Pelunasan dikonfirmasi webhook, bukan kepulangan pembeli
Transfer Virtual Account terjadi di aplikasi bank pembeli, jauh dari halaman mana pun yang dikendalikan penjual, jadi tidak ada kepulangan ke return_url yang bisa dipakai sebagai tanda lunas. Saat pembayaran terkonfirmasi, Kasera Pay mengirim event payment.paid dengan tanda tangan bertimestamp di header Kasera-Signature-V1 dan id event di Kasera-Event-Id untuk dedupe. Verifikasinya, aturan timestamp lima menit, dan masa tenggang rotasi secret ada di dokumentasi webhook. Kalau kepastian dibutuhkan di luar alur webhook, GET /v1/transactions/:id dipanggil dari server sendiri.
Dibandingkan mendaftar langsung ke bank
Bank menerbitkan Virtual Account sebagai produk tersendiri, dengan perjanjian dan spesifikasi teknisnya masing-masing. Menerima delapan bank lewat jalur itu berarti delapan proses pengajuan, delapan spesifikasi yang bentuknya berbeda, dan delapan sumber mutasi yang harus dicocokkan. Lewat satu API, yang berbeda antar bank tinggal kode metodenya, dan rekonsiliasinya satu aliran. Yang hilang adalah hubungan langsung dengan bank dan negosiasi tarif per bank. Pembahasan trade-off itu secara utuh, termasuk kapan integrasi langsung lebih masuk akal, ada di perbandingan agregator dan integrasi bank langsung. Kalau yang masih dipilih adalah antara Virtual Account dan QRIS, pembandingnya ada di panduan memilih QRIS atau Virtual Account.
Mode tes sebelum mode live
Kunci dibuat di dashboard pada menu Developer. Permintaan pertama di atas memakai kunci tes berawalan kp_test_: objeknya membawa field, biaya, dan webhook yang sama seperti objek live, tanpa uang sungguhan berpindah. Pembayaran tes dituntaskan lewat endpoint simulasi, dan mode live dan mode tes adalah dua endpoint webhook terpisah dengan signing secret masing-masing. Panduannya ada di dokumentasi mode tes.
Batas dan biaya
Nominal minimum dan maksimum per permintaan, batas harian, masa berlaku, dan laju permintaan per API key berlaku sama untuk semua metode dan diterbitkan di dokumentasi batas dan laju. Tarif Virtual Account adalah nominal tetap per transaksi berhasil, berbeda bentuk dari tarif persentase QRIS, sehingga mana yang lebih murah ditentukan nominalnya. Tarif default yang berlaku diterbitkan di dokumentasi metode pembayaran, dan tarif yang berlaku untuk sebuah akun dikembalikan oleh GET /v1/payment_methods. Tidak ada biaya bulanan dan tidak ada biaya pendaftaran.
Yang perlu disiapkan
- Akun Kasera Pay dengan verifikasi identitas dan rekening tujuan. Perorangan bisa mendaftar; syaratnya ada di panduan payment gateway tanpa PT.
- Server yang memegang kunci API. Semua panggilan berasal dari server, tidak pernah dari browser.
- Satu URL webhook
httpsyang bisa diakses publik, diatur per mode di dashboard. - Nama pembeli untuk setiap tagihan, karena metode
va_memerlukannya.
Kalau yang dibutuhkan hanya menagih beberapa pembeli sehari tanpa menulis kode, tautan pembayaran dari dashboard sudah menerima Virtual Account dan tarifnya sama; lihat halaman payment link. Kalau QRIS yang lebih dulu dibutuhkan, halaman API QRIS untuk developer membahas endpoint yang sama dari sisi itu.
Pertanyaan yang sering muncul
Apakah harus membuka rekening di kedelapan bank itu?
Tidak. Nomor Virtual Account diterbitkan lewat Kasera Pay, dan saldonya dicairkan ke satu rekening bank tujuan yang sudah diverifikasi. Membangun integrasi langsung ke setiap bank berarti delapan perjanjian, delapan spesifikasi, dan delapan jadwal rekonsiliasi; di sini bentuk permintaan dan bentuk responsnya sama untuk kedelapannya, dan yang berubah hanya kode metodenya.
Kapan nomor pembayarannya muncul?
Saat permintaan pembayaran dibuat. Respons create sudah membawa payment.payment_code, jadi nomornya bisa langsung ditulis ke badan invoice, dikirim lewat chat, atau ditampilkan di halaman sendiri tanpa panggilan kedua. Itu bedanya yang paling terasa dengan alur yang mengharuskan pembeli membuka halaman pembayaran lebih dulu.
Kenapa create menolak permintaan Virtual Account tanpa nama pembeli?
Karena nama itulah yang muncul di aplikasi bank pembeli saat nomornya dimasukkan, dan tanpa itu pembeli melihat tagihan tanpa keterangan. Create yang menyebut metode va_ tanpa customer.name ditolak dengan 422 customer_required. Pada Kasera Pay Checkout halaman pembayarannya yang menanyakan; pada Direct API tidak ada halaman yang bisa bertanya, jadi nama dikirim bersama create.
Bagaimana memastikan pembayarannya benar-benar masuk?
Dari webhook payment.paid yang tanda tangannya terverifikasi, atau dari GET /v1/transactions/:id yang dipanggil dari server sendiri. Transfer Virtual Account terjadi di aplikasi bank pembeli, jauh dari halaman mana pun yang dikendalikan penjual, jadi tidak ada kepulangan pembeli yang bisa dipakai sebagai tanda lunas.
Mana yang lebih murah, Virtual Account atau QRIS?
Bergantung nominalnya, karena bentuk tarifnya berbeda: Virtual Account dikenai nominal tetap per transaksi sedangkan QRIS dikenai persentase ditambah nominal tetap. Pada nominal kecil QRIS lebih murah, dan pada nominal besar Virtual Account menjadi lebih murah. Tarif default yang berlaku diterbitkan di dokumentasi metode pembayaran, dan tarif yang berlaku untuk sebuah akun dikembalikan oleh GET /v1/payment_methods.