API Transaction: inquiry dan payment.
Panduan ini mengikuti implementasi webhook aplikasi: pencarian invoice berdasarkan VA dan kode bank, pembayaran bertahap, respons JWT, serta pencatatan history.
Seluruh nilai dan credential dalam contoh adalah data ilustrasi.
Format respons JWT
Body respons GET dan POST langsung berupa header.payload.signature, setara echo $token, tanpa pembungkus JSON atau tanda kutip. Content-Type respons adalah text/plain; charset=UTF-8. Verifikasi signature dengan secret key dan algoritma integrasi yang sama, lalu decode payload untuk membaca hasil transaksi. Contoh JSON respons di bawah merupakan isi payload setelah decode, bukan body HTTP.
Respons error juga ditandatangani; status HTTP dan X-Correlation-ID tetap dipertahankan. Pada mode penuh, signing memakai credential yang digunakan untuk verifikasi request. Pada mode decode, credential dengan signature cocok diprioritaskan, kemudian credential dengan username/password cocok, kemudian credential bank yang dipilih. Jika credential atau secret integrasi tidak tersedia, konfigurasi JWT server dipakai. Request tidak valid tidak dapat membuktikan secret pengirim.
1. Endpoint dan payload JWT
Kirim POST ke https://webhook.sitikhodijahgroup.com/webhook/transaction, atau tambahkan kode bank pada path: /webhook/transaction/BCA. Untuk POST, header Content-Type: application/json wajib. GET juga didukung melalui /webhook/transaction/BCA/{token} tanpa body dan tanpa header Content-Type.
POST /webhook/transaction/BCA
Content-Type: application/json
X-Correlation-ID: contoh-request-001
{
"token": "HEADER.PAYLOAD.SIGNATURE"
}Body berisi token JWT, bukan payload transaksi mentah. Tanda tangani payload dengan secret dan algoritme credential integrasi.
Contoh payload INQUIRY sebelum ditandatangani
{
"METHOD": "INQUIRY",
"VANO": "8800123456",
"FIDBANK": "BCA",
"USERNAME": "USER_CONTOH",
"PASSWORD": "PASSWORD_CONTOH",
"CHANNELID": "1",
"TRXDATE": "20260909120000",
"PYMTDATE": "20260909120000",
"PAYMENT": 0,
"REFNO": "INQ-001"
}
| Klaim | Format dan fungsi |
|---|---|
| METHOD | INQUIRY atau PAYMENT. |
| VANO / FIDBANK | String. Dicocokkan dengan invoices.virtual_account dan invoices.bank_code. Maksimum 64 / 50 karakter pada validasi pembayaran. |
| USERNAME / PASSWORD | Credential integrasi, bukan akun login administrator. Lihat perbedaan pemeriksaan pada bagian mode. |
| REFNO | String atau angka; angka dikonversi ke string sebelum validasi. Maksimal 100 karakter setelah konversi. Referensi unik transaksi. Gunakan referensi berbeda untuk inquiry dan setiap pembayaran baru. |
| PAYMENT | Nominal pembayaran kali ini, bilangan bulat minimal 1 untuk PAYMENT. Gunakan 0 untuk INQUIRY. |
| CHANNELID | String atau bilangan bulat (dikonversi ke string), maksimal 30 karakter; wajib pada mode verifikasi penuh. |
| TRXDATE / PYMTDATE | Format YmdHis; wajib pada mode verifikasi penuh. paid_at memakai waktu server saat pelunasan diproses. |
X-Correlation-ID opsional dan dikembalikan pada respons. Jika tidak dikirim, server membuat ID sendiri. Gunakan nilai tanggal aktual saat membuat payload baru.
2. Alur INQUIRY
- Server membaca token dan menjalankan pemeriksaan sesuai mode pemrosesan.
- Cari invoice dengan
virtual_account = VANO AND bank_code = FIDBANK. - Jika tidak ada, kembalikan HTTP 200 dengan pesan tagihan tidak ditemukan.
- Jika ada dan REFNO valid, kembalikan rincian invoice serta simpan history INQUIRY.
Berhasil · HTTP 200
{
"ERR": "00",
"METHOD": "INQUIRY",
"METHOD_CODE": "01",
"CUSTNAME": "PASIEN CONTOH",
"DESCRIPTION": "Tagihan RS Siti Khodijah Group",
"DESCRIPTION2": "Transaction completed successfully",
"BILL": "550000",
"CCY": "360"
}CUSTNAME, deskripsi, dan currency berasal dari invoice. BILL inquiry adalah max(0, bill_amount - payment_amount), berbentuk string. Inquiry tidak mengubah status pembayaran. Pencarian inquiry saat ini tidak memfilter status invoice.
3. Alur PAYMENT dan pembayaran bertahap
- Periksa username/password sebelum memproses pembayaran.
- Validasi VANO, FIDBANK, REFNO, dan PAYMENT. Nominal harus bilangan bulat positif.
- Cari invoice berdasarkan VA dan kode bank. Jika tidak ada, respons HTTP 200.
- Periksa REFNO agar request ulang tidak menambah pembayaran dua kali. Invoice yang sudah lunas atau dibatalkan menolak pembayaran baru.
- Tambahkan nominal ke
payment_amount, lalu simpan reference no terakhir. Pembaruan invoice dan history dilakukan dalam satu transaksi database.
payment_amount baru = payment_amount lama + PAYMENT
sisa tagihan = max(0, bill_amount - payment_amount baru)
Jika sisa > 0: status = "open", paid_at = null
Jika sisa = 0: status = "paid", paid_at = waktu server sekarang
Untuk pembayaran pertama sebesar Rp200.000, gunakan payload contoh sebelumnya dengan METHOD: "PAYMENT", PAYMENT: 200000, dan REFNO: "PAY-001".
Berhasil, pembayaran sebagian · HTTP 200
{
"ERR": "00",
"METHOD": "PAYMENT",
"METHOD_CODE": "02",
"CUSTNAME": "PASIEN CONTOH",
"DESCRIPTION": "Tagihan RS Siti Khodijah Group",
"DESCRIPTION2": "Transaction completed successfully",
"BILL": "350000",
"CCY": "360"
}| Transaksi | PAYMENT | Total dibayar | BILL respons | Status |
|---|---|---|---|---|
| PAY-001 | 200000 | 200000 | 350000 | open |
| PAY-002 | 350000 | 550000 | 0 | paid |
Respons pelunasan memakai format yang sama, dengan "BILL": "0". Jika pembayaran melebihi sisa tagihan, implementasi saat ini tetap mencatat nominal penuh, menandai lunas, dan membatasi BILL respons pada 0.
4. REFNO dan pengiriman ulang
webhook_transactions.refno unik untuk seluruh transaksi. Retry PAYMENT dengan REFNO, method, VA, kode bank, dan nominal yang sama mengembalikan respons tersimpan, tanpa menambah payment_amount. Respons retry PAYMENT memuat X-Idempotent-Replay: true.
REFNO yang digunakan untuk transaksi berbeda ditolak dengan 99. Pakai REFNO baru untuk cicilan berikutnya. Respons retry adalah snapshot transaksi awal, sehingga BILL-nya tidak dihitung ulang setelah pembayaran lain.
Setiap pengiriman ulang tetap membuat baris baru di token log, sedangkan history transaksi tidak diduplikasi.
5. Respons gagal
Standar ERR untuk INQUIRY dan PAYMENT
| ERR | Confirm | Pesan standar |
|---|---|---|
00 | Approve | Transaction completed successfully |
12 | Declined | Invalid transaction |
13 | Declined | Invalid amount |
15 | Declined | Bill ID not found |
16 | Declined | Invalid full amount |
30 | Declined | Format Error |
88 | Declined | The bills already paid |
99 | Suspect | Suspect Transaction |
ERR selalu berupa string dua digit. Confirm adalah pemetaan arti kode, bukan field tambahan pada JSON. MESSAGE respons gagal mengikuti pesan standar. Kode 16 tersedia untuk ketidaksesuaian pembayaran penuh; belum dipicu karena pembayaran bertahap masih diizinkan. Konflik REFNO memakai 99.
Invoice tidak ditemukan · HTTP 200
{
"ERR": "15",
"MESSAGE": "Bill ID not found"
}Untuk tagihan tidak ditemukan, HTTP 200 membawa ERR "15" (Declined). Tentukan keberhasilan transaksi dari ERR "00", bukan status HTTP saja.
Contoh credential salah · HTTP 401
{
"ERR": "12",
"MESSAGE": "Invalid transaction"
}| HTTP | Kode / kondisi | Tindak lanjut |
|---|---|---|
| 400 | 30 / 13 | Periksa token, format JWT, klaim wajib, REFNO, dan nominal. Rincian validasi dapat muncul di errors. |
| 400 | 12 | Gunakan HTTPS jika diwajibkan pada lingkungan production. |
| 401 | 12 | Periksa credential aktif; pada mode penuh, periksa signature dan validitas token. |
| 415 | 30 | Kirim Content-Type application/json. |
| 422 | 99 | Jangan gunakan REFNO lama untuk transaksi baru. |
| 422 | 88 / 12 | Invoice lunas / dibatalkan tidak menerima pembayaran baru. |
| 422 | 12 | Pada mode penuh, samakan bank pada URL dengan FIDBANK dan gunakan method yang didukung. |
6. History transaksi dan token log
| Tabel | Isi dan waktu pencatatan |
|---|---|
| webhook_transactions | History sukses: refno, method, bank, vano, amount, JSON response, dan timestamps. amount INQUIRY = BILL invoice; amount PAYMENT = nominal pembayaran kali ini. |
| webhook_token_logs | Satu baris setiap request, termasuk retry, token rusak, token kosong, dan invoice tidak ditemukan. Menyimpan token, bank dari URL (dapat kosong), status, dan timestamps. |
berhasil: respons transaksi ERR 00, atau respons inspeksi dengan verifikasi token dan credential berhasil.gagal: validasi gagal, credential salah, konflik REFNO, dan kegagalan lainnya.token tidak ditemukan: token tidak tersedia atau kosong.tagihan tidak ditemukan: pasangan VA dan kode bank tidak ditemukan.
Status log lama sebelum kolom status ditambahkan dapat bernilai kosong. Total uang masuk dari history harus menjumlahkan PAYMENT saja; amount inquiry bukan uang yang diterima.
7. Perbedaan mode pemrosesan
Perilaku validasi mengikuti konfigurasi server WEBHOOK_DECODE_ONLY. Tabel berikut menjelaskan implementasi saat ini; status konfigurasi dan secret server tidak ditampilkan pada halaman publik.
| Perilaku | Mode decode (true) | Mode penuh (false) |
|---|---|---|
| Signature JWT | Diperiksa untuk informasi verifikasi, tetapi tidak menjadi syarat pemrosesan inquiry/payment. | Token harus lolos decode/verifikasi JWT. |
| Credential INQUIRY | Dihitung untuk inspeksi, tetapi tidak memblokir respons inquiry. | Username/password diperiksa dan harus sesuai. |
| Credential PAYMENT | Harus cocok dengan username/password pada satu credential aktif. | Harus cocok dengan credential yang dipilih, atau konfigurasi fallback jika tidak tersedia. |
| Klaim transaksi | Inquiry memerlukan pasangan VA/bank dan REFNO; PAYMENT memvalidasi VA/bank, REFNO, dan nominal positif. | Tambahan CHANNELID, TRXDATE, PYMTDATE dan seluruh klaim wajib diperiksa. |
| Bank pada URL | Pencarian invoice menggunakan FIDBANK payload. | Jika bank ada pada URL, harus sesuai FIDBANK. |
| Method lainnya | Mengembalikan hasil inspeksi JWT. | Ditolak dengan 12. |
Keberhasilan respons INQUIRY/PAYMENT pada mode decode tidak menyatakan bahwa signature JWT terverifikasi. Pilih mode penuh apabila verifikasi signature wajib untuk integrasi.
Siti Khodijah Group Webhook · Kembali ke beranda