Blog · Terbit · Diperbarui
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. Menutup tagihan lebih cepat lewat tombol batalkan berakhir pada status yang lain dengan akibat yang berbeda, dan perbandingan keduanya ada di membatalkan tagihan yang terlanjur dibuat. Keadaan yang paling sering membuat masa berlaku habis sebelum pembeli sempat membayar adalah tagihan yang terbit setelah jam tutup, dan pilihan yang tersedia untuk itu dibahas di pembayaran yang masuk saat toko tutup.
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. Hal yang sama berlaku untuk jam sewa, dan cara menahan slot hanya selama tagihannya hidup dibahas di tulisan tentang pembayaran sewa lapangan futsal dan badminton.
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 per pembayaran, ada di dokumentasi batas, dan seluruh parameter create ada di dokumentasi endpoint create.
Kedaluwarsa dikabarkan lewat webhook, tetapi bisa disusul pembayaran
Ini bagian yang paling sering luput, dan akibatnya paling mahal untuk toko yang menahan stok. Selain payment.paid saat pembayaran terkonfirmasi, Kasera Pay mengirim payment.expired saat permintaan lewat batas waktu tanpa dibayar, dan payment.failed saat rail menolak permintaannya. Setiap endpoint memilih event yang diterimanya di dashboard. Endpoint yang dibuat sebelum pilihan itu ada hanya menerima payment.paid sampai dua event lainnya dicentang, jadi sistem yang menunggu kabar kedaluwarsa lewat endpoint lama akan menunggu selamanya.
Kedaluwarsa juga bukan akhir yang pasti. Kalau uang pembeli sudah diterima sebelum timer kedaluwarsa berjalan, uang yang menang: statusnya menjadi succeeded dan payment.paid menyusul payment.expired yang sudah terkirim. Stok yang sudah dilepas saat expired harus ditarik kembali, atau dananya dikembalikan. Karena itu simpan juga expires_at dari respons create sebagai jadwal cadangan, dan periksa status terbaru lewat GET /v1/transactions/{id} sebelum mengambil tindakan yang tidak bisa dibatalkan.
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. Urutan penerbitan ulangnya sendiri, termasuk kapan tagihan lama masih bisa dibatalkan dan apa yang terpakai dari jatah sebelum verifikasi, ada di tulisan tentang menagih ulang tautan yang kedaluwarsa. 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 saat
payment.expireddatang, denganexpires_atsebagai cadangan, dan tarik kembali kalaupayment.paidmenyusul. - Terbitkan ulang dengan key baru, lalu uji jalurnya di mode tes.