AI Insights
Generate a summary and suggested tags for this post.
Webhook = cara service pihak ke-3 (GitHub, Stripe, dll) ngasih tau aplikasi kita saat ada event. Cloudflare Workers cocok banget jadi webhook receiver — cepat, global, dan ga perlu server.

Konsep Webhook
- Kamu kasih URL endpoint ke service (misal
https://myworker.workers.dev/webhook) - Saat ada event, service POST payload JSON ke endpoint kamu
- Worker terima, proses, kasih response 200
Endpoint Webhook Dasar
import { Hono } from "hono";
const app = new Hono();
app.post("/webhook", async (c) => {
const payload = await c.req.json();
console.log("Received:", payload);
// Proses event kamu di sini
await processEvent(payload);
return c.json({ ok: true });
});
export default app;Webhook GitHub (dengan Signature Verification)
GitHub kirim header x-hub-signature-256 — WAJIB diverifikasi!
async function verifyGitHubSignature(secret: string, body: string, signature: string) {
const encoder = new TextEncoder();
const key = await crypto.subtle.importKey(
"raw",
encoder.encode(secret),
{ name: "HMAC", hash: "SHA-256" },
false,
["sign"]
);
const sig = await crypto.subtle.sign("HMAC", key, encoder.encode(body));
const expected = "sha256=" + Array.from(new Uint8Array(sig))
.map(b => b.toString(16).padStart(2, "0")).join("");
return expected === signature;
}
app.post("/webhook/github", async (c) => {
const body = await c.req.text();
const signature = c.req.header("x-hub-signature-256") || "";
const valid = await verifyGitHubSignature(c.env.GITHUB_SECRET, body, signature);
if (!valid) return c.json({ error: "Invalid signature" }, 401);
const event = c.req.header("x-github-event");
const payload = JSON.parse(body);
if (event === "push") {
console.log("Push to", payload.repository.full_name);
}
return c.json({ ok: true });
});Webhook Stripe
app.post("/webhook/stripe", async (c) => {
const body = await c.req.text();
const sig = c.req.header("stripe-signature") || "";
// Verifikasi pakai library stripe atau manual HMAC
// ... verification code ...
const event = JSON.parse(body);
switch (event.type) {
case "payment_intent.succeeded":
await handlePaymentSuccess(event.data.object, c.env);
break;
case "customer.subscription.deleted":
await handleSubscriptionCancel(event.data.object, c.env);
break;
}
return c.json({ received: true });
});Best Practices Webhook
| Praktik | Kenapa |
|---|---|
| Selalu verify signature | Cegah request palsu |
| Response cepat (< 3 detik) | Kebanyakan service timeout > 3-10 detik |
| Idempotent handler | Service bisa retry — handler harus aman kalau dipanggil 2x |
| Simpan event ID | Cek duplikat sebelum proses |
| Return 200 dulu, proses async | Pakai ctx.waitUntil() |
Async Processing dengan waitUntil
app.post("/webhook", async (c) => {
const payload = await c.req.json();
// Kembalikan 200 langsung, proses di background
c.executionCtx.waitUntil(processHeavyTask(payload, c.env));
return c.json({ ok: true });
});Forward Webhook ke Cloudflare Queues (Advanced)
Untuk handle burst webhook:
app.post("/webhook", async (c) => {
const payload = await c.req.json();
await c.env.QUEUE.send(payload);
return c.json({ queued: true });
});Queue consumer akan proses satu per satu.
Deploy & Setup
- Deploy:
npx wrangler deploy - Set secret:
npx wrangler secret put GITHUB_SECRET - Copy URL:
https://myworker.<user>.workers.dev/webhook/github - Setting di GitHub: Repo → Settings → Webhooks → Add Webhook
Service yang Populer Kirim Webhook
- GitHub — push, PR, issue events
- Stripe — payment events
- Vercel / Netlify — deploy events
- Discord / Slack — chat events
- Sentry — error events
- Shopify — order events
- Meta / WhatsApp — message events
Kesimpulan
Cloudflare Workers = tempat ideal untuk webhook receiver. Cepat, gratis (100rb/hari), global. Yang paling penting: selalu verifikasi signature dan bikin handler idempotent biar aman dari duplicate & fraud.
