void-webhook-handler-pattern

Implements webhook handlers with signature verification, idempotency, and dead-letter routing for Stripe, Resend, and GitHub.

Updated May 29, 2026
One-click install
npx skills add https://github.com/voidcorp-core/void-harness --skill void-webhook-handler-pattern-voidcorp-core
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: void-webhook-handler-pattern
Source: https://github.com/voidcorp-core/void-harness/tree/main/packages/cli/core-assets/packs/pack-server/skills/void-webhook-handler-pattern
Command: npx skills add https://github.com/voidcorp-core/void-harness --skill void-webhook-handler-pattern-voidcorp-core

SYSTEM DOCUMENTATION & REQUIREMENTS

💡 This Skill requires stripe, zod, svix, @sentry/nextjs.

What problem does it solve? Inbound webhook endpoints are untrusted POST targets, and a wrong handler means forged events accepted, duplicate charges from missing idempotency, or silently lost events with no dead-letter trail. This Skill enforces the five non-negotiable layers every webhook handler needs. ## Core Features & Use Cases - Five-layer handler pattern: signature verification, idempotency via an inbox table, Zod validation, service dispatch, and correct acknowledgment status codes. - Per-source guidance: concrete signature, idempotency key, and retry semantics for Stripe, Resend (Svix), GitHub, and custom HMAC-based internal webhooks. - Dead-letter routing: permanent failures are written to a dead-letter table and answered with 4xx, while transient failures return 5xx for sender retries. - Use Case: When adding a Stripe billing webhook to a Next.js app, generate a route at apps/<app>/src/app/api/webhooks/stripe/route.ts that verifies the stripe-signature header, deduplicates on event.id, and routes permanent failures to a reviewable DLQ. ## Quick Start Ask the agent to add a webhook endpoint for Stripe (or Resend, GitHub, or a custom source) following the webhook handler pattern with signature verification and idempotency.

Frequently Asked Questions about void-webhook-handler-pattern

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I build a Stripe webhook handler in Next.js?

Create a route at app/api/webhooks/stripe/route.ts that reads the raw body, verifies the stripe-signature header with stripe.webhooks.constructEvent, deduplicates on event.id in an inbox table, validates with Zod, then dispatches to a service. Return 2xx on success and 5xx only for retryable failures.

How do I make webhook handlers idempotent?

Insert the source's unique event identifier (Stripe event.id, svix-id, or x-github-delivery) into a webhook_inbox table with a unique key constraint before processing. If the insert conflicts, the event was already handled, so return 2xx immediately to stop sender retries.

What status code should a webhook endpoint return on failure?

Return 2xx for accepted events, 401 for invalid signatures, 4xx for permanent failures like malformed payloads (logged to a dead-letter queue), and 5xx only for transient errors. Never return 200 to a malformed event, since that silently accepts invalid data.

Does GitHub retry failed webhook deliveries?

No, GitHub does not auto-retry webhooks, so a 5xx response means the event is lost. Stripe retries with exponential backoff for up to 3 days, and Svix (Resend) retries automatically, so dead-letter routing matters most for GitHub endpoints.

Why use crypto.timingSafeEqual for webhook HMAC verification?

timingSafeEqual performs a constant-time comparison that prevents timing attacks, where an attacker measures response times to guess a valid signature byte by byte. Using == for HMAC comparison exits early on the first mismatched byte and leaks that information.