# razorpay webhook signature verification failed: event tampered or replayed

## TL;DR
Your handler could not prove the event really came from Razorpay. Check the webhook secret first (most failures are a stale or wrong secret), then reject any event whose timestamp is too old or whose event id you have already seen. Only process events that pass all three checks.

```text
razorpay webhook signature verification failed: event tampered or replayed
```

## Steps

1. Verify the signature using the webhook secret configured in your Razorpay dashboard, not an API key. Success check: a known-good recent event verifies against your code.
2. Check the event timestamp: reject deliveries older than your window (a few minutes) as replays. Success check: stale test replays are refused.
3. Dedupe on the event id before doing any work; store processed ids with a TTL. Success check: double deliveries of the same event produce one side effect.
4. Compare the payload hash to what was signed if you log raw bodies; a mismatch means tampering in transit. Success check: tampered events are dropped before any business logic runs.
5. Rotate the webhook secret if you cannot explain the failures, then update every receiver the same day. Success check: failures stop and all receivers verify.

## When this applies

- Razorpay webhook deliveries are rejected by your signature check.
- You suspect replayed or tampered events hitting your endpoint.
- The endpoint worked before and broke with no code change (secret rotated).

## When it doesn't

- Razorpay API calls returning auth errors; webhooks use a different secret.
- Events not being delivered at all; check the endpoint URL and retries instead.
- Signature passing but payload parsing failing; that is a schema issue.

## Tool + version compatibility

Razorpay webhooks, signature verification helpers in the official SDKs (all current versions).

### "razorpay webhook signature mismatch"
Same triage: secret first, then timestamp, then dedupe.

### "razorpay event signature failed verification"
Confirm you are using the webhook secret, not the API key.

### "razorpay replayed webhook event"
Timestamp window plus event-id dedupe stops these.

## Why it happens

Razorpay signs each webhook with your webhook secret. Agents commonly verify with the wrong credential (an API key instead of the webhook secret), or keep an old secret cached after a dashboard rotation. Replays happen because Razorpay retries deliveries; without dedupe, the retry looks like tampering. The signature check is doing its job in all three cases.

## Edge cases / pitfalls

- The webhook secret and the API key are different credentials; mixing them up is the number one cause.
- Do not widen the timestamp window to fix failures; you are widening the replay window.
- If you verify on a parsed-then-reserialized body instead of the raw body, signatures will never match.
- Keep a dead-letter log of rejected events; silent drops hide real attacks and real bugs.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_RyMyaMrdcZ2zq7GKZAMqdA
