Blog · 9 September 2026
Menguji webhook dari komputer sendiri: kenapa alamat localhost selalu ditolak, dan urutan yang bekerja
Integrasi yang masih berjalan di komputer sendiri selalu tersandung pada hal yang sama. Kolom URL webhook menolak http://localhost:3000/webhook, dan menolak juga alamat jaringan lokal seperti 192.168.1.7. Bukan bug, dan bukan sesuatu yang bisa dimintakan pengecualian: URL webhook wajib https dan wajib mengarah ke alamat publik. Jalan keluarnya bukan mencari cara melewati aturan itu, melainkan memberi mesin lokal sebuah alamat publik lewat tunnel, lalu memicu eventnya sendiri di mode tes.
Apa yang diblokir, dan kenapa aturannya seketat itu
Sebuah URL webhook adalah perintah untuk membuat server Kasera Pay mengirim permintaan ke suatu tempat. Kalau tempat itu boleh berada di jaringan privat, maka daftar tujuan yang sah mencakup layanan metadata cloud, basis data internal, dan seluruh mesin lain di jaringan yang sama, semuanya dijangkau dari alamat IP milik Kasera Pay. Karena itu seluruh rentang berikut ditolak, beserta padanan IPv6-nya:
- Loopback
127.0.0.0/8, yang mencakuplocalhost - Jaringan privat
10.0.0.0/8,172.16.0.0/12, dan192.168.0.0/16 - Link-local
169.254.0.0/16, tempat layanan metadata setiap cloud berada - CGNAT
100.64.0.0/10, dan bentuk IPv6 yang membungkus alamat IPv4 privat
Kredensial yang diselipkan di dalam URL juga ditolak, dan pengalihan tidak pernah diikuti: sebuah pengalihan adalah URL kedua yang belum pernah diperiksa siapa pun, jadi pengiriman berhenti di situ dan dihitung gagal. Ini penting saat memakai tunnel gratis yang kadang memasang halaman antara sebelum meneruskan ke mesin lokal.
Lolos saat disimpan bukan jaminan sampai saat dikirim
Pemeriksaan saat menyimpan URL hanyalah kemudahan, supaya kesalahan ketik terlihat seketika di dasbor. Pemeriksaan yang sebenarnya terjadi pada saat koneksi dibuka, terhadap alamat yang benar-benar dituju. Alasannya, jawaban DNS bisa berubah di antara kedua saat itu, dan alamat yang menentukan adalah yang benar-benar dihubungi.
Akibatnya ada dua, dan keduanya sering membingungkan saat pengembangan lokal. Nama host yang mengarah ke 127.0.0.1 sudah ditolak sejak disimpan, sehingga trik memakai domain sendiri yang diarahkan ke mesin lokal tidak berhasil. Sebaliknya, URL yang tersimpan rapi dan pernah bekerja bisa berhenti bekerja tanpa ada yang diubah di dasbor, kalau nama host itu belakangan mengarah ke alamat privat. Yang terbaca kemudian bukan kesalahan penyimpanan, melainkan percobaan pengiriman yang gagal di log.
Urutan yang bekerja
- Ambil secret-nya lebih dulu, sebelum tunnel ada. Endpoint boleh ditambahkan tanpa URL, dan secret-nya langsung bisa dibaca. Handler bisa dibangun dan diuji terhadap secret yang sungguhan sejak awal, alamatnya menyusul belakangan.
- Pasang endpoint itu di mode Sandbox, bukan di mode Live. Kedua mode adalah endpoint terpisah dengan signing secret masing-masing, dan event mode tes hanya pernah sampai ke endpoint mode tes. Batasnya lima endpoint per mode, cukup untuk beberapa tunnel milik beberapa orang ditambah satu endpoint staging bersama.
- Jalankan tunnel, lalu tempelkan nama host https-nya. Nama host tunnel gratis biasanya berubah setiap kali dijalankan ulang, jadi URL itu perlu ditempel ulang. Yang tidak ikut berubah adalah secret-nya: memindahkan URL webhook ke domain baru tidak mengganti secret, sehingga kode verifikasi tidak perlu di-deploy ulang.
- Buat pembayaran dengan kunci
kp_test_. Mode kunci menentukan mode segala yang dibuatnya, tanpa field tambahan apa pun. Pembayaran tes tidak memakan jatah harian dan tidak pernah menyentuh saldo. - Picu eventnya. Pembayaran tes tidak pernah lunas sendiri. Ambil token dari
checkout_url, yaitu bagian setelah/p/, lalu kirim hasil yang diinginkan:curl -X POST https://pay.kasera.id/api/v1/checkout/{token}/simulate-payment \ -H "Content-Type: application/json" \ -d '{ "outcome": "succeeded" }'Body kosong berartisucceeded,expiredjuga diterima, dan nilai lain ditolak422 invalid_outcome. Endpoint ini diotorisasi oleh token checkout itu sendiri, tanpa API key, dan menjawab404kalau dipanggil pada pembayaran live. Yang menyusul adalah pengirimanpayment.paidyang sungguhan dan bertanda tangan, ke endpoint mode tes, dengan secret mode tes. - Matikan endpoint saat laptop ditutup. Menonaktifkan endpoint menahan eventnya tanpa membakar percobaan ulang, jadi tunnel yang mati semalaman tidak menghabiskan tangga percobaan pada event yang masih ingin dilihat besok pagi.
Tiga jebakan yang khas pengembangan lokal
Batas sepuluh detik. Setiap pengiriman punya batas waktu sepuluh detik. Di server produksi angka itu longgar; di mesin sendiri, satu breakpoint yang menahan eksekusi sudah cukup membuat percobaan itu dihitung gagal, lalu percobaan berikutnya baru datang satu menit kemudian mengikuti tangga 1 menit, 5 menit, 30 menit, 2 jam, 6 jam, 24 jam sampai tujuh percobaan habis dalam sekitar 33 jam. Cara membedah baris demi baris tanpa membakar percobaan adalah menyimpan body mentahnya lebih dulu, menjawab 2xx, dan memutar ulang berkas itu ke handler dari terminal.
Jam mesin yang melenceng. Signature dikirim di header Kasera-Signature-V1 dalam bentuk t=<unix>,v1=<hex>, dan verifikasi yang benar menolak pengiriman yang timestamp-nya melenceng lebih dari lima menit dari jam penerima. Kontainer atau mesin virtual yang baru bangun dari suspend sering punya jam yang tertinggal, dan gejalanya menyesatkan: signature yang sebenarnya sah terbaca tidak sah, sementara secret dan kodenya sama sekali tidak bermasalah. Periksa jam mesin sebelum memeriksa apa pun yang lain.
Body yang sudah terlanjur diurai. Signature dihitung atas body mentah, bukan atas JSON yang sudah diurai lalu dirangkai ulang. Sebagian besar framework memasang pengurai body secara bawaan, dan di lingkungan pengembangan pengurai itu biasanya menyala lebih dulu daripada yang disadari. Simpan salinan mentahnya khusus untuk rute webhook. Rincian perhitungannya, termasuk dua entri v1 selama 24 jam setelah rotasi secret, ada di dokumentasi webhook, dan hal yang dibuktikan maupun tidak dibuktikan oleh signature yang sah dibahas di artikel tentang webhook yang aman.
Setelah jalur lokalnya hidup
Berpindah ke live berarti menukar kp_test_ dengan kp_live_, dan tidak ada lagi yang berubah. Kedua mode tidak berbagi ruang nama pembayaran, termasuk kunci idempotensi, jadi kunci yang sudah terpakai selama pengujian tetap segar di mode live. Yang perlu diingat hanyalah bahwa endpoint mode live adalah endpoint yang berbeda dengan secret yang berbeda, dan URL-nya bukan lagi tunnel.
Seluruh langkah mode tes beserta kartu ujinya ada di dokumentasi mode tes. Kalau jalurnya sudah hidup lalu sebuah event tidak juga sampai, penelusurannya berbeda dan dibahas di artikel webhook tidak sampai. Urutan memasang seluruh integrasi dari awal ada di panduan integrasi QRIS di website.