Webhook that pays out twice
SAAS3-02Stripe and Polar retry deliveries. A handler that adds credits without recording the event id grants them again on every retry.
app/api/stripe/webhook/route.ts
Flagged
export async function POST(req: Request) {
const evt = stripe.webhooks.constructEvent(await req.text(), sig, secret);
if (evt.type === 'checkout.session.completed') {
await prisma.user.update({
where: { id: evt.data.object.metadata.userId },
data: { credits: { increment: 100 } },
});
}
return new Response('ok');
}
Passes
export async function POST(req: Request) {
const evt = stripe.webhooks.constructEvent(await req.text(), sig, secret);
if (evt.type === 'checkout.session.completed') {
await prisma.$transaction(async (tx) => {
if (await tx.processedWebhook.findUnique({ where: { id: evt.id } })) return;
await tx.processedWebhook.create({ data: { id: evt.id } });
await tx.user.update({
where: { id: evt.data.object.metadata.userId },
data: { credits: { increment: 100 } },
});
});
}
return new Response('ok');
}