# clerk webhook svix signature verification failed error

## TL;DR
Signature verification fails when you verify the wrong bytes or with the wrong secret. Use the raw request body exactly as received (never re-serialized JSON), the Svix signing secret from the Clerk dashboard for that endpoint, and Svix's verification library which handles the timestamp and signature headers. Re-send a test event from Clerk and confirm it verifies.

```text
clerk webhook svix signature verification failed error
```

## Use this when

- Clerk webhooks return 400 on signature verification
- Events verify in local testing but fail in production
- Recently rotated the webhook signing secret

## Not for this skill when

- Clerk API calls failing (not webhook related)
- Verified events with unexpected payload shapes (handle the data, not the signature)
- Webhooks not arriving at all (delivery or URL problem)

## Steps

### Step 1: Use the raw request body

Ensure your handler reads the exact raw bytes of the POST body for verification, before any JSON parsing. Expected: the verified bytes match what Clerk signed.

### Step 2: Check the signing secret

Copy the signing secret from the Clerk dashboard's webhook endpoint settings, watching for dev vs production endpoints. Expected: the secret matches the endpoint that sent the event.

### Step 3: Use the Svix verification library

Verify with Svix's official library, which checks the svix-id, svix-timestamp, and svix-signature headers and the timestamp tolerance. Expected: verification passes for genuine events.

### Step 4: Check the timestamp window

Confirm events are processed within the tolerance (replays older than a few minutes fail by design). Expected: no queue delay is pushing events outside the window.

### Step 5: Re-send a test event

Trigger a test webhook from the Clerk dashboard and watch it verify. Expected: a 200 response and a verified event in your logs.

## Tool compatibility

Clerk webhooks via Svix; Svix signature verification libraries; raw-body-preserving web frameworks.

## Variant phrasings

### Variant 1

clerk svix webhook signature verification failed

### Variant 2

clerk webhook 400 invalid signature raw body

### Variant 3

svix signature verification failed clerk signing secret

## Why it happens

Svix signs the exact bytes of the webhook body with HMAC, and any transformation between receipt and verification, JSON parsing followed by re-serialization, whitespace normalization, or a framework that decodes the body first, produces different bytes and a failed signature. The second classic failure is the secret itself. Clerk issues a separate signing secret per webhook endpoint, and dev/prod or old/rotated secrets get mixed up. The failure is cryptic by design, a 400 with no detail, because a verifier should not explain itself to a forger. Working through bytes first, then secret, resolves nearly every case.

## Edge cases / pitfalls

- Body-parsing middleware that consumes the raw body is the number one cause; configure a raw-body route for webhooks.
- Clock skew beyond the timestamp tolerance fails verification; keep server time synced.
- After rotating the secret, both Clerk and your app must switch together; there is no grace period.

## Provenance

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