General
Billing
Webhooks
Learn how to handle Stripe webhooks.
Webhooks are used to receive events from Stripe. They are important to get the latest data so your application is in sync with Stripe.
Setting up Webhooks
- Go to your Stripe Dashboard
- Click "Add endpoint"
- Enter your webhook URL:
https://yourdomain.com/api/webhooks/stripe - Select the required events (see list below)
- Copy the webhook signing secret
Required Webhook Events
The following Stripe webhook events are handled by the webhook handler:
Subscription Events
customer.subscription.created- When a new subscription is createdcustomer.subscription.updated- When a subscription is modified (plan changes, status updates)customer.subscription.deleted- When a subscription is canceled or expirescustomer.subscription.trial_will_end- When a trial is ending soon (3 days before)customer.subscription.paused- When a subscription is pausedcustomer.subscription.resumed- When a paused subscription is resumed
Checkout Events
checkout.session.completed- When a checkout session completes (subscriptions, one-time payments, credit purchases)
Invoice Events
invoice.paid- When an invoice payment succeedsinvoice.payment_failed- When an invoice payment fails
Charge Events
charge.refunded- When a charge is refunded (handles both full and partial refunds)
Refund Events
refund.created- When a refund is initiatedrefund.updated- When a refund's status updatesrefund.failed- When a refund fails
Dispute Events
charge.dispute.created- When a customer disputes a chargecharge.dispute.updated- When a dispute status updatescharge.dispute.closed- When a dispute is resolvedcharge.dispute.funds_withdrawn- Funds withdrawn from balancecharge.dispute.funds_reinstated- Funds reinstated to balance
Customer Events
customer.deleted- When a customer is deleted from Stripe
Payment Intent Events
payment_intent.succeeded- When a payment intent succeeds (for audit logging)
Webhook Handler
The starter kit includes a comprehensive webhook handler at app/api/webhooks/stripe/route.ts that handles all billing events. The handler includes:
- Signature verification - Validates webhook authenticity using Stripe's signature
- Idempotency - Prevents duplicate processing of the same event
- Error handling - Distinguishes between transient and permanent errors
- Event logging - Records all events in the database for audit trails
Supported Events
The handler processes the following events:
checkout.session.completed- Handles subscriptions, one-time payments and credit purchasescustomer.subscription.created- Creates subscription recordscustomer.subscription.updated- Updates subscription status and plan changescustomer.subscription.deleted- Marks subscriptions as canceledcustomer.subscription.trial_will_end- Sends trial ending notificationscustomer.subscription.paused- Handles subscription pausescustomer.subscription.resumed- Handles subscription resumptioninvoice.paid- Logs successful invoice paymentsinvoice.payment_failed- Sends payment failure notificationscharge.refunded- Handles refunds (full and partial)refund.created- Tracks refund lifecyclerefund.updated- Updates refund statusrefund.failed- Logs refund failurecharge.dispute.created- Alerts admins of new chargebackscharge.dispute.updated- Updates dispute statuscharge.dispute.closed- Logs dispute resolutioncustomer.deleted- Clears Stripe customer ID from organizationspayment_intent.succeeded- Logs payment intents for audit
Extending the Handler
To add custom logic for a specific event, you can modify the handler functions in app/api/webhooks/stripe/route.ts. For example, to add custom logic when a subscription is created:
app/api/webhooks/stripe/route.ts
async function handleSubscriptionCreated(
eventId: string,
subscription: Stripe.Subscription
): Promise<void> {
// ... existing code ...
// Add your custom logic here
await sendWelcomeEmail(organizationId);
await createInitialResources(organizationId);
}Testing Webhooks
Use Stripe CLI to test webhooks locally:
Terminal
stripe listen --forward-to localhost:3000/api/webhooks/stripe