▲16 ▼0 @iduarte 2026-08-28 stripe webhooks nodejs reliability

Stripe webhook 400 "No signatures found matching the expected signature": clock skew, duplicate deliveries, and the tolerance window nobody set

verbatim errorStripeSignatureVerificationError: No signatures found matching the expected signature for payload (400 returned to https://api.example.com/webhooks/stripe, event evt_1Pabc...)

Problem

The raw-payload rule is followed — the endpoint reads req.text() and passes it straight to the verifier. Signature verification still fails, intermittently and only on one of three webhook endpoints:

StripeSignatureVerificationError: No signatures found matching the expected signature for payload (400 returned to https://api.example.com/webhooks/stripe, event evt_1Pabc...)

Intermittent is the tell: the same event sometimes verifies, sometimes 400s, and nothing about the payload changed.

Root cause

The Stripe-Signature header carries a timestamp, and the SDK rejects signatures whose timestamp is older than the tolerance window — 5 minutes by default. Two failure shapes produce expired timestamps on a correctly-verified body:

1. Clock skew: the webhook receiver sits behind a load balancer whose clock drifts, or the container it runs in inherits a skewed clock after a host resume. The signature is computed by Stripe at send time; a receiver clock 6+ minutes behind (or ahead) fails the age check on every request. 2. Queue-delayed deliveries: the endpoint enqueues the raw request for async processing, and a worker replays it later. By the time it verifies, the header is stale. And when Stripe retries a delivery, the same event id arrives twice — a handler without dedup applies it twice, which is a different failure wearing the same endpoint.

fix preview — first 3 of 5 lines (bash), truncated:
# on the receiver host: is skew the problem? Compare against a reference. timedatectl status | grep -E 'System clock|NTP' timedatectl set-ntp true … 2 more lines in the fix

🔒 the fix — including 2 code blocks — is members-only. $1/mo unlocks everything.

✅ 1 confirmation

🔒 comments and voting are for members. $1/mo · every diagnosis is free to read, plus 3 complete sample fixes.