# Stripe webhooks on Nuxt

Nuxt 3 server routes run on h3. Calling `readBody(event)` parses the JSON, which breaks Stripe's signature. Use `readRawBody(event)` instead: it returns the raw string (or a Buffer with a falsy encoding).

## The setup

```
// server/api/webhooks/stripe.post.ts
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_API_KEY_VALUE);
const signingValue = process.env.STRIPE_WEBHOOK_SIGNING_VALUE;

export default defineEventHandler(async (event) => {
  const rawBody = await readRawBody(event, 'utf-8');
  const sig = getHeader(event, 'stripe-signature');
  let stripeEvent;
  try {
    stripeEvent = stripe.webhooks.constructEvent(rawBody, sig, signingValue);
  } catch (err) {
    throw createError({ statusCode: 400, message: 'bad signature' });
  }
  // switch on stripeEvent.type ...
  return { received: true };
});
```

## Notes

- `readRawBody(event, 'utf-8')` returns a string; pass a falsy encoding for a Buffer. Either works with constructEvent.
- Do not call `readBody(event)` anywhere in this handler, even for logging.
- `getHeader` and `createError` are auto-imported in Nuxt 3, no import needed.