Menambahkan pembayaran online terlihat sederhana saat demo: panggil API, tampilkan halaman pembayaran, selesai. Masalahnya baru muncul di production. Pelanggan sudah bayar tapi pesanannya tetap belum lunas, satu pesanan tercatat lunas dua kali, notifikasi datang sebelum pesanan tersimpan, atau tim finance tidak bisa mencocokkan laporan payment gateway dengan data pesanan di sistem. Kebanyakan masalah ini terjadi karena pembayaran diperlakukan sebagai satu request saja. Padahal pembayaran adalah proses dengan beberapa tahap yang bisa datang terlambat, dua kali, atau tidak berurutan.
Pilih Metode Pembayaran yang Dipakai Pelanggan Anda
| Metode | Cocok untuk | Catatan |
|---|---|---|
| Virtual account | Tagihan B2B dan nominal besar yang dibayar lewat transfer bank | Setiap pesanan punya nomor rekening sendiri, jadi pembayaran tercocokkan otomatis |
| QRIS | Retail dan nominal kecil, bisa dibayar dari aplikasi bank atau e-wallet apa pun | Satu QR standar bisa dipakai di banyak aplikasi |
| E-wallet seperti GoPay, OVO, DANA, atau ShopeePay | Aplikasi konsumen dan checkout di HP | Biasanya membuka aplikasi e-wallet untuk konfirmasi |
| Kartu kredit dan debit | Pelanggan internasional dan langganan berkala | Data kartu sebaiknya tetap di payment gateway, dengan 3D Secure untuk verifikasi |
| Gerai retail | Pelanggan yang lebih suka bayar tunai di minimarket | Pembayaran bisa terjadi berjam-jam kemudian, jadi masa berlakunya perlu diatur |
Biaya transaksi berbeda untuk setiap metode dan setiap payment gateway, dan bisa berubah, jadi bandingkan daftar harga terbaru untuk metode yang ingin Anda sediakan. Menyediakan semua metode belum tentu lebih baik. Beberapa metode yang memang dipakai pelanggan membuat checkout lebih sederhana dan rekonsiliasi lebih mudah.
Halaman Checkout Bawaan atau API Langsung
Payment gateway biasanya menyediakan halaman atau popup pembayaran bawaan, seperti Midtrans Snap atau Xendit Invoice, dan API langsung untuk membangun layar pembayaran sendiri. Pilihan bawaan lebih cepat dibangun, alur setiap metode sudah ditangani, dan data kartu tidak lewat server Anda, sehingga cakupan PCI DSS jauh lebih kecil. API langsung memberi kontrol penuh atas tampilan dan alurnya, tapi layar yang harus dibuat lebih banyak, kasus pinggirnya lebih banyak, dan testing-nya lebih berat. Untuk kebanyakan aplikasi bisnis, mulai dengan checkout bawaan, lalu pindahkan metode tertentu ke API langsung hanya kalau ada alasan yang jelas.
Webhook adalah Sumber Status Pembayaran
Setelah membayar, pelanggan diarahkan kembali ke website Anda. Redirect ini hanya untuk pengalaman pengguna. Pelanggan bisa menutup browser sebelum redirect terjadi, dan URL-nya bisa dibuka siapa saja, jadi redirect tidak boleh dipakai untuk menandai pesanan lunas. Status pembayaran datang dari notifikasi server ke server, yaitu webhook, yang diterima dan diverifikasi oleh backend Anda.
- Verifikasi setiap notifikasi. Midtrans menyertakan signature key yang dibuat dari order ID, status code, gross amount, dan server key Anda. Hitung ulang lalu bandingkan. Xendit mengirim callback verification token di header request yang perlu dicocokkan dengan token di dashboard.
- Supaya lebih pasti, panggil API status transaksi dengan ID transaksinya sebelum memperbarui pesanan.
- Pastikan nominal dan mata uang di notifikasi sama dengan pesanan di database.
- Balas notifikasi secepatnya dengan status sukses, lalu pindahkan pekerjaan lambat seperti kirim email atau membuat pengiriman ke background job.
- Simpan log setiap notifikasi yang masuk, termasuk isi aslinya, supaya sengketa dan bug bisa ditelusuri belakangan.
Tangani Notifikasi Ganda dan yang Datang Tidak Berurutan
Payment gateway akan mengirim ulang notifikasi kalau server Anda tidak membalas tepat waktu, dan satu pembayaran bisa menghasilkan beberapa notifikasi seiring statusnya berubah. Handler notifikasi harus idempotent: memproses notifikasi yang sama dua kali tidak boleh membuat pesanan dikirim dua kali atau saldo bertambah dua kali. Simpan ID transaksi gateway dengan unique constraint, perbarui pesanan di dalam database transaction, dan hanya izinkan perubahan status yang valid. Pesanan yang sudah lunas tidak boleh kembali ke status menunggu hanya karena notifikasi lama datang terlambat.
Rancang Status Pesanan dengan Teliti
| Status pesanan | Artinya | Status berikutnya yang boleh |
|---|---|---|
| Menunggu pembayaran | Pembayaran sudah dibuat dan ditampilkan ke pelanggan | Lunas, kedaluwarsa, atau dibatalkan |
| Lunas | Pembayaran sudah terverifikasi dari payment gateway | Diproses, refund, atau refund sebagian |
| Kedaluwarsa | Waktu pembayaran habis tanpa ada pembayaran | Percobaan pembayaran baru bisa dibuat |
| Dibatalkan | Dibatalkan pelanggan atau sistem sebelum dibayar | Tidak ada |
| Refund | Uang sudah dikembalikan ke pelanggan | Tidak ada lagi |
Simpan status transaksi dari payment gateway di tabel terpisah, lalu terjemahkan ke status pesanan Anda di satu tempat saja. Atur masa berlaku yang sesuai untuk setiap metode, dan lepaskan stok yang sudah dipesan kalau pembayarannya kedaluwarsa. Untuk pembayaran kartu, tangani juga status review fraud, saat payment gateway menahan pembayaran untuk dicek sebelum dinyatakan final.
Tes Menyeluruh di Sandbox
- 1Pakai key sandbox dan simulasikan setiap metode pembayaran yang Anda sediakan, termasuk sukses, gagal, dan kedaluwarsa.
- 2Kirim notifikasi yang sama dua kali dan pastikan pesanan hanya diproses sekali.
- 3Kirim notifikasi dengan signature atau token yang salah dan pastikan ditolak.
- 4Buat endpoint webhook gagal sementara, lalu pastikan pesanan tetap diperbarui dengan benar saat payment gateway mengirim ulang.
- 5Tes refund dan refund sebagian, lalu cek apa yang dilihat pelanggan dan tim finance.
- 6Simpan key sandbox dan production di environment variable yang terpisah, dan jangan pernah commit keduanya ke Git.
Rekonsiliasi Setiap Hari
Walaupun integrasinya sudah benar, selisih tetap bisa terjadi: webhook yang gagal berjam-jam, refund manual dari dashboard, atau dana settlement yang masuk lebih lambat dari perkiraan. Job harian yang membandingkan laporan transaksi payment gateway dengan data pesanan akan menangkap selisih ini sebelum pelanggan komplain. Laporkan transaksi yang sudah dibayar tapi pesanannya belum lunas, pesanan lunas tanpa transaksi yang settle, dan selisih nominal. Tim finance juga butuh laporan settlement yang menunjukkan nominal kotor, potongan biaya, dan jumlah bersih yang ditransfer ke rekening.
Buat satu layar admin yang menampilkan seluruh riwayat notifikasi untuk satu pesanan. Kalau ada pelanggan yang bilang sudah bayar tapi status pesanannya masih menunggu, tim support bisa menjawab dalam semenit tanpa harus minta developer mencari di log.
Poin penting
- Sediakan metode pembayaran yang memang dipakai pelanggan, dan bandingkan biaya terbaru untuk setiap metode.
- Mulai dengan checkout bawaan payment gateway supaya data kartu tidak lewat server Anda dan pekerjaan integrasinya lebih ringan.
- Jadikan webhook yang sudah diverifikasi sebagai satu-satunya sumber status pembayaran, jangan redirect dari browser.
- Buat penanganan notifikasi yang idempotent, cek nominalnya, dan hanya izinkan perubahan status pesanan yang valid.
- Tes notifikasi ganda, signature salah, pengiriman ulang, dan refund di sandbox, lalu lakukan rekonsiliasi setiap hari.


