Overview
Deltalytix uses Stripe webhooks to receive real-time notifications about subscription events, payment status changes, and other billing activities. The webhook endpoint processes events and updates subscription data in the database accordingly.Endpoint
Authentication
Webhook requests are authenticated using Stripe signature verification to ensure they originate from Stripe.Signature Verification
All incoming webhook events are verified using thestripe-signature header and your webhook secret:
Configuration
Environment Variables
Configure the following environment variables:| Variable | Description | Required |
|---|---|---|
STRIPE_WEBHOOK_SECRET | Webhook signing secret from Stripe Dashboard | Yes |
STRIPE_SECRET_KEY | Stripe API secret key | Yes |
DATABASE_URL | PostgreSQL connection string | Yes |
Setup in Stripe Dashboard
- Go to Developers → Webhooks in your Stripe Dashboard
- Click Add endpoint
- Enter your webhook URL:
https://your-domain.com/api/stripe/webhooks - Select the events to listen to (see Supported Events)
- Copy the webhook signing secret and add it to your environment variables
Supported Events
The webhook endpoint handles the following Stripe event types:checkout.session.completed
Triggered when a checkout session is successfully completed. Handles:- Recurring subscription checkouts (
mode: subscription) - One-time payment checkouts for lifetime plans (
mode: payment) - Referral code application from session metadata
- Creates or updates subscription record in database
- Sets subscription plan based on product name
- Configures billing interval (monthly, quarterly, or lifetime)
- Applies referral codes if present in metadata
/app/api/stripe/webhooks/route.ts:81-234
customer.subscription.created
Triggered when a new subscription is created. Actions:- Creates subscription record for new customer
- Sets initial status (
TRIALorACTIVE) - Records trial period if applicable
- Links subscription to user account
/app/api/stripe/webhooks/route.ts:351-402
customer.subscription.updated
Triggered when subscription details change (plan upgrade/downgrade, status change, etc.). Actions:- Updates subscription status in database
- Handles subscription cancellation scheduling
- Records cancellation feedback if provided
- Updates billing period and plan information
active→ACTIVEtrialing→TRIALpast_due→PAST_DUEincomplete→PAYMENT_PENDINGincomplete_expired→EXPIREDcanceled→CANCELLEDunpaid→UNPAID
/app/api/stripe/webhooks/route.ts:260-350
customer.subscription.deleted
Triggered when a subscription is cancelled and deleted. Actions:- Updates subscription status to
CANCELLED - Sets plan to
FREE - Records final end date
/app/api/stripe/webhooks/route.ts:240-259
invoice.payment_failed
Triggered when an invoice payment fails. Actions:- Updates subscription status to
PAYMENT_FAILED - Allows retry logic to handle payment recovery
/app/api/stripe/webhooks/route.ts:403-417
payment_intent.succeeded
Triggered when a payment is successfully processed. Actions:- Logs successful payment
- Used for monitoring and debugging
/app/api/stripe/webhooks/route.ts:235-239
payment_intent.payment_failed
Triggered when a payment attempt fails. Actions:- Logs payment failure details
- Records error message for debugging
/app/api/stripe/webhooks/route.ts:418-424
customer.subscription.trial_will_end
Triggered 3 days before a trial period ends. Actions:- Can be used to send reminder emails to customers
- Currently logged for monitoring
Request Format
Headers
Body
Stripe sends event data as JSON:Response Format
Success Response
200 OK
Error Responses
Invalid Signature
400 Bad Request
Processing Error
500 Internal Server Error
Subscription Plans
The webhook handler supports multiple subscription types:Recurring Subscriptions
- Monthly plans:
interval: month,interval_count: 1 - Quarterly plans:
interval: month,interval_count: 3 - Plan name is derived from Stripe product name (uppercase)
Lifetime Plans
- One-time payment mode
- End date set to 100 years in the future
interval: lifetime
Referral Code Handling
Referral codes can be passed via checkout session metadata:- Retrieves the referral by slug
- Validates the referral doesn’t belong to the purchasing user
- Adds user to referral list if not already present
- Logs application success or errors
Referral code application errors are non-fatal and won’t block subscription creation.
Security Considerations
Best Practices
- Signature Verification: Always verify the
stripe-signatureheader - HTTPS Only: Only accept webhooks over HTTPS in production
- Secret Rotation: Regularly rotate webhook signing secrets
- Idempotency: Handle duplicate events gracefully (Stripe may send the same event multiple times)
- Timeout Protection: Respond to webhooks within 10 seconds to avoid retries
Environment Security
Testing
Local Testing with Stripe CLI
-
Install the Stripe CLI:
-
Login to Stripe:
-
Forward webhooks to your local server:
-
Copy the webhook signing secret displayed and add it to your
.env.local: -
Trigger test events:
Testing in Development
Use the Stripe Dashboard to send test webhooks:- Go to Developers → Webhooks
- Click on your endpoint
- Click Send test webhook
- Select an event type
- Optionally customize the event data
- Click Send test webhook
Monitoring Webhook Delivery
View webhook delivery attempts in the Stripe Dashboard:- Go to Developers → Webhooks
- Click on your endpoint
- View recent deliveries with response codes and timing
- Click on individual events to see request/response details
Troubleshooting
Common Issues
Signature Verification Failed
Problem: Webhook returns 400 with “Webhook Error” Solutions:- Verify
STRIPE_WEBHOOK_SECRETmatches the secret in Stripe Dashboard - Ensure you’re using the correct endpoint URL
- Check that the request hasn’t been modified by middleware
Database Update Failed
Problem: Webhook returns 500 with “Webhook handler failed” Solutions:- Verify
DATABASE_URLis correctly configured - Check database connection and permissions
- Review application logs for detailed error messages
- Ensure user exists in database before subscription creation
Events Not Received
Problem: Stripe shows events sent but webhook not triggered Solutions:- Verify endpoint URL is accessible from the internet
- Check firewall rules allow Stripe IPs
- Ensure webhook endpoint is configured in Stripe Dashboard
- Review server logs for incoming requests
Duplicate Events
Problem: Same event processed multiple times Solutions:- Stripe may send duplicate events, implement idempotency checks
- Use event ID (
event.id) to track processed events - Consider implementing event deduplication logic
Rate Limits
Stripe webhooks have the following characteristics:- Timeout: 10 seconds (respond within this time to avoid retries)
- Retries: Failed webhooks are retried with exponential backoff for up to 3 days
- Order: Events may arrive out of order; use timestamps to handle this