DEV Community

jaswant singh Jatav
jaswant singh Jatav

Posted on

Reliable Webhook Processing in NestJS: Signatures, Idempotency, Retries & Queues

Build reliable NestJS webhooks for SaaS payments and integrations using signature verification, idempotency, durable inboxes, queues, retries, and observability.

NestJS webhook gateway verifying signatures and processing idempotent events through a durable retry queue
Webhooks are untrusted, duplicated, and out of order by design. A payment provider can retry the same event, deliver it late, or time out while your NestJS API successfully processes it. Treating a webhook like an ordinary controller request is how SaaS products double-activate subscriptions and lose billing events.
A reliable webhook pipeline verifies the raw payload, records the event durably, responds quickly, and processes business logic asynchronously. Idempotency makes retries safe; queues and observability make failures recoverable.

Why webhook controllers fail in production
Providers retry when your response is slow—even if your database transaction succeeded
Duplicate events can issue two refunds, send two invoices, or provision the same tenant twice
Events may arrive out of order, such as subscription updates before the creation event
A provider outage or your deployment can create a burst that overwhelms synchronous handlers
Without an event ledger, support cannot prove what arrived or what failed
Reliable NestJS webhook architecture with signature checks, inbox, retries, and workers
Verify, persist, acknowledge, then process: the HTTP endpoint stays fast while durable workers handle business effects.
The reliable NestJS webhook flow
Capture the raw request body — signature verification must use the exact bytes the provider signed
Verify authenticity — validate HMAC or provider signatures before parsing or trusting any field
Claim the event idempotently — insert the provider event id behind a unique constraint
Persist the payload — store an inbox record with provider, type, timestamps, and processing status
Acknowledge quickly — return the required 2xx response before expensive business logic begins
Enqueue processing — hand the inbox id to BullMQ, RabbitMQ, or another durable worker pipeline
Record the outcome — mark processed, retrying, or dead-lettered with a useful error trail
Signature verification comes before JSON
Many providers sign the raw body plus a timestamp. If middleware parses and re-serializes JSON first, byte-level differences can invalidate the signature. Configure NestJS to expose the raw body only for webhook routes, verify against the provider secret, enforce timestamp tolerance, and reject invalid signatures with no side effects.
EXPLORE PACKAGE · STARTER
Start with a production-shaped NestJS edge
NestJS Microservice Starter Kit includes an API gateway, Keycloak SSO, RabbitMQ, Redis, PostgreSQL, Docker, and Kubernetes—everything needed to separate fast webhook intake from durable asynchronous processing.
View Starter package

Idempotency: make duplicate delivery harmless
Place a unique database constraint on (provider, event_id); do not rely on an in-memory check
Perform the event claim and state transition in a transaction
Make downstream operations idempotent too—for example, upsert subscription state by provider id
Store the provider event timestamp and version so stale events cannot overwrite newer state
Return success for an already accepted event instead of processing it again
Exactly-once delivery is a promise the network cannot keep; idempotent processing is the guarantee your application can provide.
Retries, backoff, and dead-letter handling
Retry transient failures with exponential backoff and jitter
Do not retry permanent errors such as an unknown event schema forever
Move exhausted events to a dead-letter state that operators can inspect and replay
Cap concurrency so a delivery burst does not exhaust PostgreSQL or downstream APIs
Preserve correlation ids from intake through every worker attempt
Webhook observability checklist
Count received, verified, duplicated, processed, retried, and dead-lettered events
Track processing lag from provider timestamp to successful completion
Alert on signature failures, queue depth, oldest unprocessed event, and dead-letter growth
Expose a secure internal event viewer for support and operations
Redact secrets and sensitive payment data from logs and traces
Multi-tenant SaaS considerations
Resolve the tenant from trusted provider metadata or an internal mapping—not an unsigned payload field
Apply the tenant context before updating subscriptions, entitlements, or audit records
Partition worker concurrency so one tenant's integration burst cannot starve others
Store provider-account-to-tenant mappings with strict uniqueness and audit history
EXPLORE PACKAGE · ENTERPRISE
Enterprise billing and audit services built to cooperate
Enterprise SaaS Microservices Boilerplate separates tenant, billing, audit, and notification services behind a gateway, with RabbitMQ and Redis for resilient event workflows and service-per-database PostgreSQL.
View Enterprise package

EXPLORE PACKAGE · PROFESSIONAL
Prefer unified SaaS operations?
Professional Multi-Tenant SaaS Boilerplate combines per-tenant PostgreSQL, Keycloak SSO, billing, and Admin in one NestJS API—simplifying webhook transactions while preserving tenant isolation.
View Professional package

What production-ready looks like
The endpoint verifies and stores an event in milliseconds, duplicates become no-ops, workers retry transient failures, dead letters are visible, and every subscription change has an audit trail. Explore Cyber Infoware products or contact us to choose a reliable NestJS SaaS foundation.

Top comments (0)