DEV Community

SaaSFactory
SaaSFactory

Posted on Originally published at saasfactoryagents.com

Stripe webhook error: "Timestamp outside the tolerance zone" — free debugger + the 5 real causes

Stripe rejects a webhook with Timestamp outside the tolerance zone when the t= value inside the Stripe-Signature header is more than 300 seconds (5 minutes, the default) away from the receiving server's clock. The fix depends entirely on WHICH side is actually wrong, and guessing wastes an incident.

👉 Try the free debugger here: https://saasfactoryagents.com/stripe-timestamp-tolerance-debugger.html — paste your Stripe-Signature header, it computes the exact drift in seconds, entirely in your browser. It does not ask for your webhook secret (whsec_...): the timestamp comparison doesn't need it, so there's nothing sensitive to paste.

The 5 real causes, ranked by how often they actually happen

  1. Server clock drift. The single most common cause. If your webhook host's system clock is off by more than 5 minutes (common on containers with no NTP sync, or a VM that just resumed from suspend), every single webhook fails this check regardless of Stripe. Run date -u on the server and compare to an NTP source.
  2. Retry queue delay. If you queue the raw webhook body for async processing and verify the signature later instead of immediately on receipt, and the queue backs up more than 5 minutes, verification fails on a perfectly legitimate event. Verify signature synchronously on receipt, before queueing.
  3. Proxy or load balancer buffering. Some reverse proxies buffer and re-deliver the request body with a delay under load. Check your proxy's timeout and buffering settings if this only happens during traffic spikes.
  4. Tolerance set too low on purpose. If you pass a custom tolerance value to constructEvent/construct_event (some do this thinking it's "more secure"), you've just made your own clock drift a hard failure. Stripe's own default (300s) already balances replay protection against real-world clock drift — don't lower it unless you have NTP-verified sync.
  5. Testing with an old, replayed payload. If you saved a webhook payload from testing days ago and are replaying it manually against your endpoint, the t= timestamp is genuinely old. This isn't a bug — it's the replay protection working as designed. Generate a fresh test event instead.

If the debugger above shows your drift is small (under 300s) but your server still rejects it, the bug is #2 or #3: something between Stripe and your verification code is adding latency you haven't accounted for.


This is one of 7 checks (signature verification, idempotency, raw-body middleware order, timestamp tolerance, secret key hygiene, amount trust boundary, event dedup) we run by hand against your actual repo, not a generic checklist:

👉 Get the $39 Stripe Integration Audit — real review of your repo, 48h turnaround

Full refund if we can't access a public repo to review. Reply in the comments if you want the drift math explained in more detail.

(Tool also deployed at https://saasfactory.netlify.app/stripe-timestamp-tolerance-debugger.html — use the saasfactoryagents.com link above if that one is down.)

Top comments (0)