Payment Webhook & Callback
Setelah pelanggan berhasil atau gagal menyelesaikan pembayaran di halaman Payment Gateway, Gateway (seperti Duitku atau Xendit) akan memanggil endpoint Webhook Frog Cloud secara asinkronus di background. Webhook ini bertugas memverifikasi keabsahan data, lalu memperbarui status Invoice dan menambahkan saldo ke dompet pelanggan.
1. Endpoint Webhook
Endpoint ini bersifat publik dan menerima HTTP POST request langsung dari server Payment Gateway. Endpoint ini masuk ke dalam daftar pengecualian whitelist (tanpa otentikasi JWT).
POST /api/webhook/duitku/callback
Content-Type: application/x-www-form-urlencoded
POST /api/webhook/xendit/callback
Content-Type: application/json
2. Alur Webhook Duitku
Duitku mengirimkan payload callback dalam format application/x-www-form-urlencoded.
Parameter Form yang Diterima
| Parameter | Tipe Data | Deskripsi |
|---|---|---|
merchantOrderId | String | ID eksternal unik (UUID) dari Invoice Topup. |
amount | String | Nominal yang berhasil dibayarkan. |
resultCode | String | Kode status (misal 00 untuk Success, 01 untuk Failed). |
signature | String | String HMAC SHA-256 untuk memverifikasi request. |
Validasi HMAC SHA-256
Demi keamanan berlapis, Backend memverifikasi bahwa request benar-benar berasal dari Duitku menggunakan algoritma HMAC SHA-256. Formula string yang dienkripsi adalah gabungan dari parameter berikut:
stringToSign = merchantCode + amount + merchantOrderId
Signature kemudian dihasilkan menggunakan apiKey yang hanya diketahui oleh sistem internal Frog Cloud dan Duitku:
signature = HMAC_SHA256(stringToSign, apiKey)
Jika signature tidak cocok dengan yang dikirim di request body, sistem akan menolak request dengan status 401 Unauthorized.
3. Redirect Pembayaran (User Callback)
Selain server-to-server webhook callback, setelah pelanggan membayar, halaman Payment Gateway juga akan me-redirect browser pengguna kembali ke sistem kita.
GET /api/payment/redirect/{gateway}?status={status}
Endpoint ini didesain untuk menangkap pengguna yang selesai bertransaksi (baik success, failed, atau pending). Sama seperti webhook, route ini berada di daftar pengecualian JWT agar pengguna yang session-nya mungkin terhapus tidak diblok.
4. Alur Pembaruan Saldo (Balance Repository)
Setelah verifikasi Webhook berhasil dan status resultCode dikonfirmasi Success (misalnya 00), Invoice Topup ditandai sebagai Paid (entity.PaymentStatusSuccess).
Langkah selanjutnya, Backend memasukkan Job asinkronus TopupCallbackSuccessTask ke dalam antrean billing-high. Worker akan mengeksekusi ini dengan mekanisme Database Locking (mencegah Race Condition) untuk:
- Update Current Balance: Menambah nominal pembayaran ke kolom
current_balancepada tabelcustomer_wallets. - Update Actual Balance: Menambah nominal pembayaran ke kolom
actual_balancedan mencatatnya dalam Balance Log tipeBalanceLogAdd.
Jika record dompet pengguna belum pernah ada (terutama untuk pelanggan yang baru pertama kali topup), sistem akan otomatis menginisialisasi baris baru di tabel customer_wallets.