Stripe events are asynchronous. When a subscription updates, Stripe signals your backend. If your endpoint is down, slow, or fails to parse a payload, you risk desynchronizing user states and leaking services.
A zero-failure webhook channel is founded on idempodence and asynchronous queueing. Your webhook endpoint should only validate the signature, write the event payload raw to a database table, and return a 200 OK immediately.
A separate queue processor consumes these logged records one-by-one, handling transactions and checking for double-processing via the unique Stripe event ID. If a process errors, the queue retries without blocking other accounts.
app/api/stripe/webhook/route.tstypescript
export async function POST(req: Request) {
const payload = await req.text();
const signature = req.headers.get("stripe-signature")!;
try {
// 1. Verify Event authenticity
const event = stripe.webhooks.constructEvent(payload, signature, WEBHOOK_SECRET);
// 2. Queue event payload into DB table and return immediately
await db.stripeEvent.create({
data: { id: event.id, status: "PENDING", data: payload }
});
return Response.json({ received: true }, { status: 200 });
} catch (err) {
return Response.json({ error: "Webhook Error" }, { status: 400 });
}
}