Webhooks
The MLM Platform uses Stripe webhooks to receive real-time notifications about subscription and payment events.
Overview
When events occur in Stripe (e.g., subscription created, payment succeeded), Stripe sends webhook events to the MLM Platform, which then processes them to:
- Create commission entries for purchases
- Update subscription statuses
- Track payment lifecycle events
Setting Up Webhooks
Step 1: Get Your Webhook Endpoint
Your webhook endpoint is:
https://api.mlm-platform.example.com/functions/v1/stripe-webhook
For sandbox environments:
https://api.mlm-platform.example.com/functions/v1/stripe-webhook?environment=sandbox
- Go to Stripe Dashboard
- Click Add endpoint
- Enter your webhook URL
- Select events to listen for (see below)
- Click Add endpoint
- Copy the Signing secret
Step 3: Save the Webhook Secret
In the MLM Platform Admin Dashboard:
- Navigate to Settings > Integrations > Stripe
- Enter the webhook signing secret
- Click Save
Supported Events
| Event | Description | Action |
|---|
checkout.session.completed | Checkout completed | Creates commission entries |
invoice.paid | Invoice payment succeeded | Records purchase event |
customer.subscription.created | New subscription | Creates subscription record |
customer.subscription.updated | Subscription changed | Updates subscription status |
customer.subscription.deleted | Subscription cancelled | Marks subscription inactive |
Webhook Signature Verification
All webhook requests are verified using Stripe’s signature verification:
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
async function handleWebhook(req) {
const sig = req.headers['stripe-signature'];
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
let event;
try {
event = stripe.webhooks.constructEvent(
req.body,
sig,
webhookSecret
);
} catch (err) {
console.error('Webhook signature verification failed:', err.message);
return { status: 400, body: 'Invalid signature' };
}
// Process the event
switch (event.type) {
case 'checkout.session.completed':
await handleCheckoutComplete(event.data.object);
break;
// ... handle other events
}
return { status: 200, body: 'OK' };
}
Always verify webhook signatures to prevent spoofed requests.
Idempotent Handling
Stripe may send the same event multiple times. Handle this by:
- Storing processed event IDs
- Checking before processing
async function handleWebhook(event) {
// Check if already processed
const existing = await db.webhookEvents.findUnique({
where: { stripeEventId: event.id }
});
if (existing) {
console.log('Event already processed:', event.id);
return { status: 200, body: 'Already processed' };
}
// Process the event
await processEvent(event);
// Mark as processed
await db.webhookEvents.create({
data: {
stripeEventId: event.id,
type: event.type,
processedAt: new Date()
}
});
return { status: 200, body: 'OK' };
}
Retry Behavior
Stripe retries failed webhook deliveries:
| Attempt | Delay |
|---|
| 1 | Immediate |
| 2 | 5 minutes |
| 3 | 30 minutes |
| 4 | 2 hours |
| 5 | 5 hours |
| 6 | 10 hours |
| 7+ | 24 hours (up to 3 days) |
Return a 2xx status code quickly to acknowledge receipt. Process events asynchronously if needed.
Testing Webhooks
Using Stripe CLI
# Install Stripe CLI
brew install stripe/stripe-cli/stripe
# Login
stripe login
# Forward webhooks to local server
stripe listen --forward-to localhost:54321/functions/v1/stripe-webhook
# Trigger test events
stripe trigger checkout.session.completed
Using Sandbox Environment
- Use Stripe test mode
- Use sandbox API keys
- Create test subscriptions with test cards
Test card numbers:
4242 4242 4242 4242 - Succeeds
4000 0000 0000 0002 - Declines
Troubleshooting
Webhook Not Received
- Check endpoint URL is correct
- Verify webhook is enabled in Stripe
- Check Stripe webhook logs for errors
- Ensure firewall allows Stripe IPs
Signature Verification Failed
- Verify webhook secret is correct
- Ensure raw request body is used (not parsed JSON)
- Check for proxy modifications to headers
Event Processing Failed
- Check MLM Platform logs
- Verify user exists for the customer
- Check commission rules are configured