WeBuildCrew
🔌 API Integrations

Webhook Integration Guide: Receive, Verify & Process Events Reliably

How to build a webhook receiver that never loses an event — signature verification, idempotency, async queues and retry logic explained with real code.

Zahid Ghotia7 min read
#Webhook Integration#API Development#Stripe Webhooks#Event-driven Architecture#Node.js#API Integration Services
Webhook Integration Guide: Receive, Verify & Process Events ReliablyWeBuildCrew

Webhooks are how the internet talks to itself — Stripe fires one when a payment completes, GitHub when a PR merges, Twilio when a message arrives. Building a receiver that's fast, secure and never drops an event requires more than a simple POST handler. This guide covers the full pattern.

Step 1 — Always verify the signature

Every serious webhook provider signs its payloads with an HMAC-SHA256 signature. Your receiver must verify this before doing anything else — an unverified handler is an open door for replay attacks and forged events.

app/api/stripe/webhook/route.ts
TypeScript
import Stripe from "stripe";const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!); export async function POST(req: Request) {  const body = await req.text(); // raw body — required for signature check  const sig = req.headers.get("stripe-signature")!;  let event: Stripe.Event;  try {    event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);  } catch {    return new Response("Bad signature", { status: 400 });  }  await queue.add("stripe-event", event); // hand off immediately  return new Response("ok");}
Stripe webhook verification — the raw body must be used, not the parsed JSON.

Step 2 — Respond fast, process async

Webhook providers (Stripe, GitHub, etc.) expect a 2xx response within 5–30 seconds or they retry. Heavy processing — sending emails, updating databases, calling other APIs — should happen in a background queue, not in the handler itself.

Step 3 — Idempotent processing

Every webhook can be delivered more than once (network blips, provider retries). Your processor must be idempotent — running it twice on the same event must have the same result as running it once. The simplest pattern: store the event ID and skip if already seen.

workers/stripe.ts
TypeScript
export async function handleStripeEvent(event: Stripe.Event) {  const exists = await db.processedEvent.findUnique({ where: { id: event.id } });  if (exists) return; // already handled — safe to skip   await db.processedEvent.create({ data: { id: event.id } });   if (event.type === "checkout.session.completed") {    const session = event.data.object as Stripe.Checkout.Session;    await activateSubscription(session.metadata!.orgId);  }}
Idempotent event processing — skip already-handled events.

Step 4 — Handle retries gracefully

When your handler returns a non-2xx, providers retry with exponential backoff. Configure your queue with the same pattern for downstream failures — up to 3 retries with delays, then move to a dead-letter queue for manual inspection.

< 200ms

Handler response time

event_id

Idempotency key

Retry attempts

DLQ

Failed events

Need this built? Explore our API Development & Integrations service.

View service →

Written by Zahid Ghotia · Published 5 June 2026 · 7 min read

FAQ

Frequently asked questions

Which providers use webhooks?

Stripe, GitHub, Shopify, Twilio, SendGrid, Clerk, PlanetScale — almost every modern API uses them for async events.

How do I test webhooks locally?

Use the Stripe CLI (`stripe listen`) or ngrok to forward provider events to localhost during development.

Do I need a separate queue service?

For low volume, a simple database-backed queue works. For production scale, BullMQ (Redis) or a managed queue is more reliable.

What if an event is never delivered?

Most providers have a dashboard to replay events. For critical flows, also poll the provider API periodically as a safety net.

Keep reading

Related articles

Need API & webhook integrations?

Reliable, verified webhook systems and third-party integrations — built to production standard.