Skip to content

The raw-body rule ​

Providers sign the exact bytes they send. If your framework parses the JSON first, the bytes are gone and verification fails — this is the #1 webhook bug. Every adapter detects a pre-parsed body and returns 400 body_already_parsed instead of failing silently.

FrameworkWhat to do
ExpressRoute-level express.raw({ type: 'application/json' }). If you need a global express.json(), add verify: (req, _res, buf) => { req.rawBody = buf } — the adapter reads req.rawBody first.
FastifyRegister the route inside a scoped plugin and call useRawJsonBody(scope).
NestJSNestFactory.create(AppModule, { rawBody: true }). Don't set bodyParser: false.
KoaUse @koa/bodyparser — it exposes ctx.request.rawBody.
Next.js App Router, Hono, Workers, Deno, BunNothing. fetchWebhook reads request.arrayBuffer(). With Hono, pass c.req.raw.
Next.js Pages Routerexport const config = { api: { bodyParser: false } } in the route file.
AWS LambdaNothing. Base64 bodies (isBase64Encoded) are decoded for you.
DjangoNothing — request.body is raw.
FlaskNothing — the helper uses request.get_data(). Don't read request.json first.
FastAPIDon't declare a Pydantic body parameter on the webhook route.

Proxies and gateways that re-encode JSON (some API gateways, some no-code tools) also break signatures — forward bodies untouched.

MIT Licensed