// app/routes/api+/webhook.ts
export async function action({ request }: ActionFunctionArgs) {
const event = await getStripeEvent(request, stripe) // verifies the signature
// Stripe delivers at-least-once: a retry or network blip means the
// same event.id can arrive twice. Without this guard, a duplicate
// 'checkout.session.completed' double-applies the subscription.
if (await eventAlreadyHandled(event.id)) return data({}, { status: 200 })
switch (event.type) {
case 'checkout.session.completed': {
const session = event.data.object
await updateSubscriptionByUserId(session /* … */)
return data({}, { status: 200 })
}
}
}