Blog
Cara Menangani Timeout dan Retry di Integrasi Pembayaran
Bagian dari topik: Integrasi API Pembayaran untuk Developer

Dalam integrasi pembayaran, kegagalan jaringan bukan kemungkinan langka, melainkan hal yang pasti terjadi cepat atau lambat. Koneksi bisa putus tepat setelah kamu mengirim permintaan, respons bisa hilang di tengah jalan, atau server bisa lambat menjawab. Mengelola timeout retry pembayaran dengan benar adalah pembeda antara sistem yang tangguh dan sistem yang diam-diam men-charge pelanggan dua kali. Kesalahan di sini tidak cuma soal bug teknis, tapi soal uang orang.
Artikel ini membahas cara menangani respons yang lambat atau tidak datang, cara mengulang permintaan (retry) tanpa risiko dobel-charge, dan cara menghadapi status yang ambigu ketika kamu tidak yakin sebuah pembayaran berhasil atau tidak. Prinsip intinya sederhana: perlakukan setiap kegagalan sebagai "tidak tahu", bukan "gagal", lalu andalkan webhook dan pengecekan status sebagai sumber kebenaran.
Kenapa Timeout Berbahaya dalam Pembayaran
Timeout terjadi ketika kamu mengirim permintaan tapi tidak menerima respons dalam batas waktu tertentu. Masalahnya, timeout tidak berarti permintaanmu gagal. Ada beberapa kemungkinan yang sama-sama masuk akal:
- Permintaan tidak pernah sampai ke server. Aman untuk diulang.
- Permintaan sampai dan diproses, tapi responsnya yang hilang di jalan pulang. Mengulang tanpa hati-hati bisa membuat pembayaran dobel.
- Permintaan masih diproses saat batas waktu tercapai.
Karena kamu tidak bisa membedakan ketiganya hanya dari sisi klien, mengulang permintaan secara membabi buta itu berbahaya. Inilah alasan retry harus selalu dipasangkan dengan idempotensi. Tanpa itu, satu timeout bisa berujung dua tagihan ke pelanggan yang sama.
Idempotensi: Fondasi Retry yang Aman
Idempotensi berarti mengirim permintaan yang sama berkali-kali menghasilkan efek yang sama seperti mengirimnya sekali. Dalam konteks pembayaran, ini dicapai dengan menyertakan penanda unik yang konsisten, seperti reference_id atau order_id milikmu, pada setiap pesanan.
Kuncinya: satu pesanan = satu penanda tetap. Ketika terjadi timeout dan kamu mengulang permintaan, kirim ulang dengan penanda yang sama persis, bukan penanda baru. Dengan begitu, sistem bisa mengenali bahwa ini pesanan yang sama dan tidak membuat pembayaran kedua.
Prinsip yang perlu kamu pegang:
- Buat penanda unik sebelum mengirim permintaan pertama, simpan di database-mu.
- Saat retry, gunakan kembali penanda yang sudah tersimpan itu.
- Jangan pernah membuat penanda baru untuk pesanan yang sama hanya karena percobaan sebelumnya timeout.
Untuk pendalaman soal pola ini, baca idempotency API pembayaran. Idempotensi juga berlaku di sisi masuk: satu webhook yang kebetulan terkirim dua kali tidak boleh menggeser status order dua kali.
Strategi Retry yang Benar
Retry yang baik bukan sekadar "coba lagi secepatnya berulang-ulang". Itu justru bisa membanjiri server dan memperparah keadaan. Gunakan strategi yang sopan dan terukur.
| Prinsip | Penjelasan |
|---|---|
| Exponential backoff | Tambah jeda antar percobaan (misal 1s, 2s, 4s) agar tidak membanjiri |
| Jitter | Beri variasi acak pada jeda supaya banyak klien tidak retry serempak |
| Batas percobaan | Tetapkan jumlah maksimal retry, jangan tak terhingga |
| Pilih yang layak retry | Hanya ulang untuk timeout dan error server, bukan error validasi |
Perbedaan penting: error seperti 4xx (misalnya data yang kamu kirim salah) tidak boleh di-retry, karena mengulang permintaan yang sama tetap akan gagal. Yang layak diulang adalah timeout dan error sisi server yang bersifat sementara. Selalu pasangkan retry ini dengan reference_id yang sama agar tetap aman.
Menghadapi Status yang Ambigu
Setelah timeout dan retry, kamu mungkin tetap tidak yakin apakah pembayaran berhasil. Jangan menebak. Ada dua sumber kebenaran yang bisa kamu andalkan:
1. Webhook
BorderPay mengirim event seperti payment.paid, payment.expired, dan payment.failed ke endpoint-mu. Event ini adalah pemberitahuan resmi tentang apa yang sebenarnya terjadi pada pembayaran, lepas dari apakah panggilan API-mu sempat timeout. Webhook BorderPay ditandatangani HMAC, ber-log, dan bisa dikirim ulang bila server-mu sempat down. Verifikasi tanda tangannya, proses secara idempoten, dan pakai event ini untuk menetapkan status akhir. Pola lengkapnya ada di webhook pembayaran.
2. Cek Status Aktif
Bila kamu butuh kepastian saat itu juga dan tidak ingin menunggu webhook, kamu bisa mengecek status pembayaran berdasarkan reference_id. Ini berguna misalnya ketika pelanggan kembali ke halamanmu dan bertanya "apakah bayaran saya sudah masuk?". Alih-alih menebak dari hasil panggilan yang timeout, tanyakan status sebenarnya.
Kombinasi keduanya membuat sistemmu tahan banting: webhook menangani pembaruan otomatis, sementara cek status menangani momen ketika kamu butuh jawaban langsung.
Menyimpan Status dengan Benar
Semua strategi di atas hanya berguna jika kamu menyimpan status pembayaran dengan disiplin. Beberapa aturan main:
- Catat penanda sebelum kirim. Simpan
reference_iddan status awal (pending) sebelum memanggil API, supaya kamu punya jejak meski respons hilang. - Perlakukan status sebagai transisi terarah. Sebuah pembayaran yang sudah
paidtidak boleh turun lagi menjadipendinghanya karena ada webhook yang datang telat atau berurutan aneh. - Jangan menganggap redirect sebagai bukti bayar. Pelanggan yang mendarat di halaman "terima kasih" belum tentu berarti dana masuk; hanya webhook atau cek status yang membuktikannya.
Untuk pola penyimpanan status yang konsisten dan tahan terhadap event yang datang tidak berurutan, baca menyimpan status pembayaran. Disiplin di sini mencegah kelas bug yang paling menyakitkan: uang masuk tapi order tidak terproses, atau sebaliknya.
Menyetel Timeout yang Masuk Akal
Berapa lama kamu harus menunggu sebelum menyatakan sebuah panggilan timeout? Menyetelnya terlalu pendek membuat kamu menyerah padahal server sebenarnya sedang memproses; terlalu panjang membuat pelanggan menatap layar loading terlalu lama. Tidak ada satu angka ajaib, tapi ada prinsip yang bisa dipegang.
- Bedakan timeout koneksi dan timeout baca. Timeout koneksi (menyambung ke server) biasanya bisa lebih pendek dari timeout baca (menunggu respons diproses).
- Sesuaikan dengan jenis operasi. Membuat pembayaran mungkin butuh toleransi lebih dibanding sekadar mengambil daftar metode lewat
GET /payment-methods. - Jangan biarkan timeout menggantung tak terbatas. Panggilan tanpa batas waktu bisa menahan koneksi dan sumber daya server-mu, memperparah beban saat trafik tinggi.
Setelah timeout tercapai, jangan langsung menyimpulkan gagal. Lepaskan koneksi, catat kejadiannya, lalu jalankan alur retry-atau-cek-status seperti dibahas di atas. Yang penting, keputusan menyerah pada satu panggilan tidak sama dengan keputusan tentang nasib pembayaran itu sendiri.
Alur Lengkap: Dari Kirim sampai Pasti
Menyatukan semuanya, beginilah alur yang tahan banting untuk satu pembayaran:
- Buat
reference_idunik dan simpan status awalpendingdi database sebelum memanggil API. - Kirim permintaan dengan penanda tersebut dan terima
pay_url. - Jika timeout, ulang dengan
reference_idyang sama memakai backoff, sampai batas percobaan. - Jika masih tidak pasti, lakukan cek status berdasarkan
reference_id. - Tetapkan status akhir dari webhook (
payment.paid,payment.expired,payment.failed) yang sudah diverifikasi HMAC dan diproses idempoten. - Perbarui order hanya berdasarkan status resmi, bukan hasil panggilan yang timeout.
Perhatikan bahwa langkah 5 adalah penentu, bukan langkah 2 atau 3. Panggilan API awal hanyalah cara memulai pembayaran; kebenaran akhir tentang berhasil-tidaknya selalu datang dari webhook atau cek status. Sikap ini yang membuat sistemmu tidak pernah salah menyimpulkan hanya karena satu paket jaringan hilang.
Kesimpulan
Menangani timeout dan retry di integrasi pembayaran berakar pada satu sikap: perlakukan setiap kegagalan sebagai "tidak tahu", bukan "gagal". Selalu pasangkan retry dengan idempotensi lewat reference_id yang tetap, gunakan exponential backoff dengan jitter dan batas percobaan, dan jangan mengulang error yang memang tidak akan berhasil. Ketika status ambigu, jangan menebak: andalkan webhook ber-HMAC yang bisa dikirim ulang, atau lakukan cek status aktif berdasarkan penanda pesananmu.
Dengan pondasi ini, kamu bisa membangun integrasi yang tidak pernah men-charge pelanggan dua kali meski jaringan bermasalah. BorderPay menyediakan mode test/sandbox sejak hari pertama sehingga kamu bisa menyimulasikan skenario kegagalan ini tanpa risiko. Daftar akun dan pelajari detail teknisnya di dokumentasi.