Route Handlers in Next.js for webhooks and APIs
3 min read
By Juliano Alves
app/api/**/route.ts (or route.js) defines Route Handlers: HTTP methods as named exports (GET, POST) colocated with the App Router. They replace much of what you previously did in pages/api but follow Web Request/Response APIs.
Stripe-style webhook
import { headers } from 'next/headers';
import Stripe from 'stripe';
export async function POST(req: Request) {
const body = await req.text();
const sig = headers().get('stripe-signature');
if (!sig) return new Response('Missing signature', { status: 400 });
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
} catch {
return new Response('Invalid signature', { status: 400 });
}
// Idempotent: store event.id before side effects
await processStripeEvent(event);
return new Response(null, { status: 200 });
}
Use req.text() not req.json() when the provider signs the raw body.
Dynamic routes
app/api/users/[id]/route.ts exports handlers with context.params. Validate id before DB calls.
Edge vs Node
Pick export const runtime = 'edge' only when dependencies support it (no Node-only Stripe SDK on edge without wasm). Webhooks often need Node for crypto and official SDKs.
Summary
Route Handlers are ideal for webhooks and small BFF endpoints. Verify signatures on raw bodies, run idempotent business logic, and choose runtime based on library support—not hype.