Database Anda tumbang pukul 2 dini hari. Saat Anda bangun dan memperbaikinya, webhook selama tiga jam sudah terkirim dan ditolak. Sekarang Anda menatap Slack sambil bertanya-tanya berapa banyak pembayaran Stripe yang tidak terpenuhi dan berapa banyak push GitHub yang tidak memicu job CI yang seharusnya.
Tulisan ini adalah playbook nyata untuk memulihkan webhook yang terlewat, provider demi provider, lalu pola yang mengubah urusan ini menjadi masalah satu klik, bukan satu Minggu sore.
TL;DR
- Stripe: kirim ulang secara manual per event dari dashboard, atau buat skripnya lewat Events API. Tidak ada UI massal.
- GitHub: tombol Redeliver (kirim ulang) per pengiriman. Juga satu per satu, kecuali Anda membuat skrip dengan Redelivery API.
- Shopify: mencoba ulang 8 kali dalam 4 jam, lalu event-nya hilang dan Anda harus meng-query ulang Orders API untuk merekonsiliasi.
- Putar ulang (replay) satu klik butuh pencatatan di upstream sebelum pengiriman, dan itulah seluruh desain relay webhook.
Stripe
Stripe memungkinkan Anda mengirim ulang event webhook secara manual dari dashboard:
- Buka Developers → Events di Dashboard Stripe.
- Klik event yang ingin Anda kirim ulang.
- Gulir ke Webhook attempts lalu klik Kirim ulang (Resend).
Cara ini berlaku satu event per kali, dan hanya selama 15 hari setelah event dibuat. Jika Anda melewatkan 300 event, Anda harus mengeklik 300 tombol. Ada perintah Stripe CLI (stripe events resend <event_id>), tetapi Anda tetap harus tahu ID setiap event.
Memutar ulang event Stripe secara massal
Tidak ada UI putar ulang massal bawaan dari Stripe. Cara mengakalinya:
- Tulis skrip yang memakai Stripe API untuk menampilkan daftar event dalam rentang gangguan, memfilternya berdasarkan status, lalu mengirim POST setiap event kembali ke endpoint Anda sendiri. Anda menyusun ulang webhook dari objek event, dan bentuknya tidak persis sama.
- Atau, jika Anda mencatat webhook di upstream dari titik gangguan, putar ulang dari log Anda sendiri.
Pendekatan log di upstream inilah yang akhirnya dibangun tim production. Itu juga persis yang dilakukan relay webhook untuk Anda.
GitHub
GitHub menampilkan tombol kirim ulang per pengiriman di Settings → Webhooks → (pilih webhook) → Recent Deliveries milik repo. Klik Redeliver di samping setiap pengiriman.
Masalahnya sama: satu per satu. GitHub hanya menyimpan pengiriman yang bisa dikirim ulang selama 3 hari, dan putar ulang massal tetap berarti menulis skrip yang memanggil Redelivery API. Dan log itu satu-satunya yang Anda punya, karena GitHub tidak pernah mencoba ulang pengiriman yang gagal dengan sendirinya.
Shopify
Shopify mencoba ulang 8 kali dalam rentang empat jam sebelum menyerah. Setelah itu, satu-satunya cara memulihkan adalah meng-query ulang Shopify API untuk apa yang terlewat. Webhook-nya sendiri sudah hilang.
Kasus ini sangat menyakitkan karena rentang pemulihan Shopify sejauh ini yang paling pendek di antara tiga provider besar. Jika server Anda mati Jumat malam dan Anda baru menyadarinya Senin, Anda harus melakukan rekonsiliasi penuh dari Orders API.
Pola umumnya
Apa pun provider-nya, prosedur pemulihan tanpa relay kira-kira seperti ini:
- Tentukan rentang gangguan. Kapan server Anda berhenti membalas 2xx?
- Ambil event yang terdampak, biasanya lewat panggilan API berhalaman untuk setiap provider.
- Kirim lagi setiap event dengan POST ke endpoint Anda sendiri, atau query ulang sumber kebenarannya dan sinkronkan state secara manual.
- Lakukan deduplikasi, karena handler Anda harus idempoten dan sebagian event mungkin sudah sempat terkirim.
Ini memakan waktu berjam-jam. Dan Anda hanya punya satu kesempatan: jika Anda melewatkan event di luar rentang percobaan ulang (retry), event itu hilang.
Versi satu klik
AnyHook ada untuk mengubah semua ini menjadi satu klik. Saat Anda mengarahkan webhook ke in.anyhook.net/you/app:
- Setiap event disimpan secara persisten sebelum dikirim, dengan enkripsi saat disimpan (at rest).
- Jika server Anda mengembalikan 5xx, AnyHook mencoba ulang dengan backoff eksponensial (Free=3, Pro=5, Scale=10 upaya).
- Jika server Anda mati cukup lama hingga percobaan ulang habis, event ditandai gagal, tetapi payload-nya tetap ada di log Anda.
- Buka halaman App (satu URL masuk untuk satu sumber webhook), pilih rentang waktu di banner event gagal (satu jam terakhir, 24 jam terakhir, atau seluruh masa putar ulang), lalu klik Replay (putar ulang). Event dikirim 100 sekaligus, dimulai dari yang terlama. Selesai.
Memutar ulang event yang gagal tidak mengurangi kuota bulanan Anda, tetapi memakai jatah komputasi (compute allowance) paket Anda. Setiap paket punya batas putar ulang harian (100 di Free, 500 di Pro, 1.000 di Scale), dan event yang ditahan (held) karena melewati kuota dihitung sebagai event baru saat diputar ulang. Putar ulang dikirim sebagai pengiriman baru ke endpoint Anda dengan tanda tangan (signature) baru, sementara body dan header masuk aslinya tetap dipertahankan, sehingga handler Anda melihat event persis seperti yang dikirim provider.
Padanannya di API cukup satu POST:
curl -X POST https://anyhook.net/api/v1/apps/stripe-prod/replay-failed \
-H "Authorization: Bearer $ANYHOOK_KEY" \
-H "Content-Type: application/json" \
-d '{"since": "2026-04-18T02:00:00Z", "limit": 100}'
Satu panggilan, hingga 100 event diputar ulang, tanpa klik di dashboard.
Implikasi desain
Yang membuat putar ulang murah adalah persistensi di edge, sebelum pengiriman. Jika log webhook Anda dimulai di origin, Anda hanya bisa memutar ulang apa yang diterima origin. Jika log Anda dimulai di edge jaringan, sebelum origin sempat gagal, Anda bisa memutar ulang apa pun yang pernah datang.
Jadwal yang berjalan di antara upaya tersebut adalah masalah desain tersendiri. Jadwal AnyHook berupa tangga tetap tanpa jitter, dan Backoff Eksponensial dan Jitter untuk Percobaan Ulang Webhook membahas mengapa tangga seperti itu menggiring setiap klien ke detik yang sama setelah gangguan, dan mengapa putar ulang yang murah tetap lebih unggul daripada percobaan ulang yang agresif. Dan jika Anda sering membutuhkan putar ulang, pertanyaan yang lebih awal adalah apakah batas integrasi ini memang membutuhkan webhook sejak awal, dan itu dibahas di Webhook vs Polling.
Pindahkan pencatatan ke upstream, buat putar ulang idempoten, dan gangguan webhook terburuk Anda menjadi pemulihan satu menit, bukan satu akhir pekan.
Dua bacaan lanjutan yang layak dibaca sebelum Anda membutuhkannya. “Buat putar ulang idempoten” adalah separuh yang menopang segalanya, dan itu lebih sulit daripada sekadar tabel deduplikasi begitu percobaan ulang datang secara bersamaan: Anda Menerima Webhook yang Sama Dua Kali. Dan jika Stripe sudah menyerah dan menonaktifkan endpoint Anda, Stripe sudah berhenti mencoba ulang dan Anda harus mem-backfill dari Events API dalam rentang 30 hari: Stripe Menonaktifkan Endpoint Webhook Anda.
Coba di anyhook.net.