Blog · 30 Agustus 2026
Masa berlaku tagihan: berapa lama satu tautan pembayaran sebaiknya hidup
Masa berlaku default sebuah permintaan pembayaran di Kasera Pay adalah 60 menit, dan maksimumnya mengikuti konfigurasi akun, secara default 24 jam. Angka default itu bukan angka yang cocok untuk semua situasi. Yang menentukan angka yang tepat bukan selera, melainkan satu pertanyaan: berapa lama jarak antara tautan dikirim dan pembeli benar-benar duduk di depan aplikasi banknya.
| Situasi | Masa berlaku yang masuk akal | Alasannya |
|---|---|---|
| Jualan lewat chat, pembeli sedang membalas | 15 sampai 60 menit | Pembeli membayar dalam percakapan yang sama |
| Checkout di website sendiri | 60 menit | Cukup untuk berpindah aplikasi dan kembali |
| Tiket acara dengan kuota terbatas | 15 sampai 30 menit | Kursi tertahan selama tagihan masih hidup |
| Tagihan ke klien yang perlu persetujuan internal | Terbitkan ulang, bukan diperpanjang | Persetujuan tidak selesai dalam hitungan jam |
Apa yang terjadi saat masa berlakunya habis
Setiap permintaan pembayaran membawa expires_at. Lewat dari waktu itu, statusnya menjadi expired dan pembayaran tidak lagi bisa diselesaikan. Yang dilihat pembeli pada halaman checkout adalah pesan bahwa tautannya kedaluwarsa, waktu pembayaran sudah habis, dan tautan baru perlu diminta ke penjual. Halamannya tidak menghilang dan tidak berubah menjadi error, sehingga pembeli yang datang terlambat tetap tahu apa yang harus dilakukan.
Perilaku di sisi metode pembayarannya berbeda-beda, dan bedanya penting untuk dijelaskan ke pembeli. Kode QRIS dan nomor Virtual Account sama-sama berhenti berlaku pada expires_at, dan kode atau QR yang dipakai setelah waktu itu gagal di bank, bukan di halaman checkout. Untuk QRIS, kegagalan itu terjadi di detik pemindaian dan mudah dipahami pembeli. Untuk Virtual Account, kegagalan muncul setelah pembeli mengetik nomor panjang dan yakin sedang membayar tagihan yang benar, sehingga terbaca seperti kesalahan penjual. Karena itu tagihan Virtual Account yang memang ditujukan untuk dibayar besok pagi sebaiknya diberi masa berlaku yang menjangkau besok pagi, bukan dibiarkan pada default 60 menit.
Dua kesalahan yang biayanya tidak setara
Masa berlaku terlalu pendek dan terlalu panjang sama-sama merugikan, tetapi tidak dengan besaran yang sama.
Terlalu pendek berarti pembeli kembali ke tautan yang sudah mati. Biayanya satu pesan: pembeli meminta tautan baru, penjual membuatnya, transaksi berlanjut. Kerugian nyatanya adalah sebagian pembeli tidak repot meminta dan pergi begitu saja, dan ini paling terasa pada pembeli yang membuka tautan dari perangkat berbeda dengan tempat percakapan berlangsung.
Terlalu panjang lebih mahal karena biayanya bukan pada pembeli, melainkan pada catatan. Tagihan berumur 24 jam yang tidak dibayar menahan stok atau kursi selama satu hari penuh, menumpuk sebagai baris pending yang tidak bisa dibedakan dari pembayaran yang sedang berlangsung, dan membuat penutupan buku harian berisi angka yang belum pasti. Untuk penjualan tiket, satu tagihan menganggur selama sehari sama artinya dengan satu kursi yang tidak dijual ke orang yang siap membayar.
Karena itu arah defaultnya sebaiknya pendek, dengan penerbitan ulang yang mudah. Kebiasaan yang paling menolong bukan memperpanjang masa berlaku, melainkan menggeser waktu pembuatannya: tautan dibuat saat pembeli mengatakan akan membayar sekarang, bukan saat pesanan pertama kali dibicarakan. Konsekuensi praktis yang sama juga berlaku untuk tautan yang dibuat dari dashboard tanpa kode, dan dibahas berdampingan dengan jalur lain di panduan menerima pembayaran QRIS tanpa website.
Untuk integrasi sendiri: satu angka, dua batas
Pada endpoint create, masa berlaku diatur lewat expires_in_minutes, dengan default 60. Ada dua batas berbeda yang sering tertukar, dan keduanya menolak dengan cara yang berbeda:
- Batas validasi. Nilai di luar rentang 1 sampai 10080 ditolak lebih awal sebagai
422 validation_failed, dengan field yang bermasalah disebut dierror.fields. - Plafon akun. Nilai yang lolos validasi tetapi melewati plafon akun, secara default 24 jam, ditolak sebagai
422 expiry_too_long. Perbaikannya adalah meminta masa berlaku yang lebih pendek, atau meminta plafonnya dinaikkan.
Artinya angka 10080, yaitu tujuh hari, memang diterima oleh validasi tetapi tidak berarti diterima oleh akun mana pun. Kode yang menganggap keduanya satu batas akan lolos di pengembangan dan gagal di produksi. Batas lengkap yang berlaku saat pembuatan, termasuk nominal dan volume harian, ada di dokumentasi batas, dan seluruh parameter create ada di dokumentasi endpoint create.
Kedaluwarsa tidak dikabarkan lewat webhook
Ini bagian yang paling sering luput, dan akibatnya paling mahal untuk toko yang menahan stok. Webhook yang dikirim adalah payment.paid saat pembayaran terkonfirmasi. Tidak ada webhook untuk pembayaran yang kedaluwarsa. Sistem yang menunggu kabar untuk melepas stok akan menunggu selamanya.
Ada dua cara menanganinya, dan keduanya berjalan di sisi sendiri. Pertama, simpan expires_at dari respons create dan jalankan timer sendiri untuk melepas stok pada waktu itu. Kedua, periksa statusnya lewat GET /v1/transactions/{id} saat dibutuhkan, misalnya ketika pembeli membuka kembali halaman pesanan. Cara pertama lebih tepat untuk stok dan kursi karena tidak bergantung pada kunjungan pembeli.
Satu jebakan menyertainya. Endpoint daftar menyediakan filter status, tetapi filternya hanya berlaku pada halaman yang diambil, bukan pencarian atas seluruh riwayat. Menyapu tagihan yang kedaluwarsa dengan ?status=expired pada satu halaman akan melewatkan baris yang berada di halaman berikutnya. Cara yang benar adalah melakukan paging tanpa filter lalu menyaring di sisi sendiri. Detail perilaku webhook, termasuk verifikasi tanda tangan, ada di dokumentasi webhook.
Menerbitkan ulang butuh Idempotency-Key yang baru
Setelah sebuah tagihan kedaluwarsa, tagihan penggantinya adalah permintaan pembayaran yang benar-benar baru, dan itu berarti header Idempotency-Key yang baru. Key disimpan permanen dan tidak pernah kedaluwarsa, jadi mengirim ulang create dengan key lama dan body yang sama akan menjawab 200 berisi permintaan pembayaran yang lama, yang statusnya sudah expired. Yang terlihat di sisi penjual adalah tautan baru yang langsung mati.
Cara paling aman adalah menurunkan key dari percobaan, bukan dari pesanan: misalnya nomor pesanan digabung dengan nomor urut penerbitan. Pembahasan lengkap tentang key yang bertahan melewati retry, termasuk bentuk yang justru membuka celah tagihan ganda, ada di tulisan tentang tagihan ganda dan Idempotency-Key.
Mengujinya sebelum go-live
Jalur kedaluwarsa adalah jalur yang paling jarang diuji karena menunggu 60 menit tidak praktis. Mode tes menyelesaikannya: dengan kunci tes, satu permintaan simulasi dengan outcome bernilai expired memindahkan tagihan ke status akhirnya tanpa menunggu jam berjalan dan tanpa uang sungguhan berpindah. Langkahnya ada di dokumentasi mode tes. Uji dua hal sekaligus: pelepasan stok berjalan, dan penerbitan ulang menghasilkan tautan yang benar-benar bisa dibayar.
Ringkasnya
- Default 60 menit cocok untuk hampir semua penjualan yang dibayar saat itu juga.
- Persingkat ketika ada kuota yang tertahan; perpanjang hanya untuk Virtual Account yang memang ditujukan untuk esok hari.
- Jangan mengandalkan masa berlaku panjang sebagai pengganti penerbitan ulang.
- Lepaskan stok dengan timer dari
expires_at, karena tidak ada webhook kedaluwarsa. - Terbitkan ulang dengan key baru, lalu uji jalurnya di mode tes.