BillingWebhookKit

Paddle webhook signature verification in Next.js

Next.js teams often break Paddle webhook verification when a route parses JSON before checking the exact raw body behind the Paddle-Signature header.

Generate a test plan

Read the raw body first

In an App Router webhook route, read await request.text() before calling JSON.parse or request.json(). The signature check must use the exact string Paddle signed.

Keep signed Paddle fixtures

Store fake transaction.completed, subscription lifecycle, cancellation, and adjustment payloads with test Paddle-Signature headers so CI protects the raw-body behavior.

Replay duplicates safely

Run the same signed event multiple times and assert that entitlements, downloads, invoices, and emails happen once. Signature verification proves authenticity; idempotency proves retry safety.

Separate provider verification

Verify Paddle before normalizing the event into your internal billing model, just as you would keep Stripe, Lemon Squeezy, and Polar verification separate. Do not reuse a Stripe signing helper for Paddle without checking header format and raw-body rules.

FAQ

Why does Paddle webhook signature verification fail in Next.js?

The common cause is parsing or changing the request body before verification. The Paddle-Signature check must use the exact raw body delivered to the route.

Can Paddle signature tests run without a live Paddle account?

Yes. Route tests can use fake JSON fixtures and fake signing secrets. A separate checkout smoke test is still required before production traffic.

Use the free sample before wiring production checkout

Download a public sample pack with fake fixtures, signature tests, contract checks, duplicate replay tests, and CI skeletons. The Pro Kit preview shows the full paid package structure without exposing the private archive.