Payment webhook dead letter queue in Next.js
A billing webhook can fail after the provider already considers the event delivered. Store failed events, prove replay safety, and keep entitlement writes idempotent before the buy link goes public.
What to record
Record provider, event ID, event type, object ID, raw body hash, and signature result after the raw-body gate passes.
Separate signature failure, unknown event, missing customer mapping, database write failure, email failure, and fulfillment failure.
Store a sanitized cURL command or fixture reference so the team can reproduce the event without exposing webhook secrets.
Persist the same key used by the handler so manual replay cannot grant access, revoke access, or send delivery twice.
Next.js table shape
The dead letter table can be small. The important rule is that it records enough evidence to replay safely without storing production API keys or private checkout links.
create table payment_webhook_dead_letters (
id text primary key,
provider text not null,
event_type text not null,
object_id text not null,
idempotency_key text not null,
raw_body_sha256 text not null,
signature_verified boolean not null,
failure_reason text not null,
replay_status text not null default 'pending',
created_at timestamptz not null default now()
);
CI gates
- Signed failed fixture creates one dead letter row with a stable idempotency key.
- Duplicate replay updates or skips the same row instead of creating duplicate side effects.
- Mutated raw body fails before trusted entitlement or fulfillment logic.
- Replay command uses fake fixtures and never prints API keys, webhook secrets, customer emails, or private checkout URLs.
- Resolved dead letters produce a short release note with provider, event type, outcome, and rollback status.
FAQ
Should a payment webhook return 500 to force provider retries?
Only when the event is safe to retry and the handler failed before durable recording. If the event is recorded in a dead letter queue, return the status your runbook expects and replay from storage.
What should a webhook dead letter queue store?
Store provider, event ID, event type, object ID, signature verification result, raw body hash, failure reason, idempotency key, replay command, and operator notes without storing private API keys.
Turn failed webhook handling into release evidence
The free replay and test plan tools help design the recovery path. The CNY 69 Pro Kit is for teams that want fixtures, idempotency tests, entitlement matrices, and review templates already packaged.