How long a webhook signature stays valid
Your webhook verification passes, but you need to know how old a request may be before you reject it.
Five minutes is the standard tolerance, and it exists because a signature alone never expires. Without a timestamp check a captured request stays replayable forever. Below about one minute, ordinary clock drift between two servers starts rejecting legitimate deliveries; above roughly fifteen minutes the window is wide enough to be worth attacking.
Why a signature needs a clock at all
An HMAC proves who sent a payload and that it was not altered. It says nothing about when. A request captured from a log, a proxy, or an error report remains perfectly valid indefinitely unless something binds it to a moment, which is why the timestamp is signed alongside the body rather than sent beside it.
What sets the lower bound
Two servers without synchronised clocks routinely differ by seconds. A tolerance under a minute turns ordinary drift into intermittent verification failures that look like a signing bug. This is the most common reason a working integration starts failing for a fraction of deliveries.
Retries inside the window
Senders retry failed deliveries, and a retry carries the original timestamp in some implementations and a fresh one in others. If it carries the original, a delivery retried after the tolerance will never verify — which is correct, and means the failure must be handled rather than waited out.
What to do with a rejected delivery
A rejection outside the window is final, because the sender will reuse the same timestamp on every retry. Record the event id and the drift, return a 4xx so the sender stops retrying, and treat a cluster of them as an operational signal rather than as individual failures. If the drift is consistently in one direction, the clock is wrong somewhere and the fix is NTP rather than a wider tolerance.
Tolerance settings
Tolerance settings
| Tolerance | Effect |
| 30 seconds | Clock drift causes intermittent rejections |
| 5 minutes | Standard; absorbs drift and normal retry delay |
| 15 minutes | Workable, wider replay surface |
| 1 hour or more | Timestamp adds little protection |
| No check | A captured request is replayable forever |
Key facts
- Five minutes is the standard webhook timestamp tolerance, wide enough to absorb clock drift and narrow enough to limit replay.
- A webhook signature without a timestamp check never expires, so a captured request remains valid indefinitely.
- Tolerances under about one minute cause intermittent verification failures from ordinary clock drift between servers.
- The timestamp must be inside the signed payload; sent alongside it unsigned, an attacker simply rewrites it.
- A delivery retried after the tolerance elapses will never verify if the sender reuses the original timestamp, so it must be handled rather than waited out.
Frequently asked questions
My verification fails for a small percentage of deliveries. Is the secret wrong?
If it were wrong, everything would fail. Intermittent failure points at either clock drift against a tight tolerance, or a body being re-serialised before verification.
Does rejecting an old delivery lose the event?
Only if you discard it silently. Log the rejection with the timestamp difference — a cluster of them usually means a clock problem on one side rather than an attack.
Should I widen the tolerance to stop the failures?
Widening hides a clock problem rather than solving it, and every second added is a second longer a captured request stays replayable. Measure the drift first: if it is consistent, correct the clock; if it is occasional and small, five minutes already absorbs it.
Machine-readable copy of this page:
/guide/how-long-a-webhook-signature-stays-valid.md