10 min readCyber Infoware

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
  • Webhooks
  • SaaS
  • Security
  • Queues
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

  1. Capture the raw request body — signature verification must use the exact bytes the provider signed
  2. Verify authenticity — validate HMAC or provider signatures before parsing or trusting any field
  3. Claim the event idempotently — insert the provider event id behind a unique constraint
  4. Persist the payload — store an inbox record with provider, type, timestamps, and processing status
  5. Acknowledge quickly — return the required 2xx response before expensive business logic begins
  6. Enqueue processing — hand the inbox id to BullMQ, RabbitMQ, or another durable worker pipeline
  7. 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.

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

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.

Explore Cyber Infoware packages

Production NestJS SaaS foundations with commercial licensing — pick the architecture that matches your team.

See pricingContact us

More from the blog

← Back to all articles