You can use Vercel Serverless Functions to recieve webhooks from third-party services like Stripe. Certain providers require access to the raw body inside the function to validate the signature from the request.
With Node.js
import type { VercelRequest, VercelResponse } from '@vercel/node';import type { Readable } from 'node:stream';
export const config = { api: { bodyParser: false, },};
async function buffer(readable: Readable) { const chunks = []; for await (const chunk of readable) { chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk); } return Buffer.concat(chunks);}
export default async function (req: VercelRequest, res: VercelResponse) { if (req.method === 'POST') { const buf = await buffer(req); const rawBody = buf.toString('utf8');
res.json({ rawBody }); } else { res.setHeader('Allow', 'POST'); res.status(405).end('Method Not Allowed'); }}
With Next.js
When using Next.js API Routes deployed as Serverless Functions on Vercel, you need to change your code to use the native Next.js types.
- import type { VercelRequest, VercelResponse } from '@vercel/node'+ import type { NextApiRequest, NextApiResponse } from 'next'
- export default async function (req: VercelRequest, res: VercelResponse) {+ export default async function (req: NextApiRequest, res: NextApiResponse) {
Testing Locally
You can verify your function can accept and parse raw bodies locally:
- Start your local development server with
vercel dev
(ornext dev
). - In another terminal window, run the
cURL
command below.
curl -X POST -H "Content-Type: text/plain" --data "This is raw data" http://localhost:3000/api/test
You should see a response like {"rawBody": "This is raw data"}
.