This guide explains how to configure Stripe webhooks to keep your application in sync with subscription changes.
Configure Webhook Endpoint
- Go to Stripe Dashboard → Developers → Webhooks
- Click "Add endpoint"
- Select API version:
2024-11-20.acacia
- Enter the iaptic webhook URL:
https://validator.iaptic.com/v3/webhook/stripe
Required Events
Select these webhook events:
[
"customer.subscription.created",
"customer.subscription.updated",
"customer.subscription.deleted",
"payment_intent.succeeded",
"payment_intent.payment_failed",
"price.created",
"price.updated",
"price.deleted",
"product.created",
"product.updated",
"product.deleted"
]
Configure iaptic
- Copy the webhook signing secret (
whsec_...
) - Go to iaptic Dashboard → Settings
- Enter the webhook secret:
Stripe Webhook Secret: whsec_...
Test the Configuration
-
Use Stripe's webhook tester:
stripe trigger customer.subscription.updated
-
Check iaptic logs for the event:
// In your application const { purchases } = await iaptic.getPurchases('sub_xyz'); console.log('Updated subscription:', purchases[0]);
Webhook Events Reference
Subscription Lifecycle
// checkout.session.completed
// New subscription created
{
type: 'checkout.session.completed',
data: {
object: {
subscription: 'sub_xyz',
metadata: {
application_username: 'user123'
}
}
}
}
// customer.subscription.updated
// Plan changed, renewal, cancellation
{
type: 'customer.subscription.updated',
data: {
object: {
id: 'sub_xyz',
status: 'active',
cancel_at_period_end: false
},
previous_attributes: {
items: [{ price: { id: 'price_old' } }]
}
}
}
// customer.subscription.deleted
// Subscription ended
{
type: 'customer.subscription.deleted',
data: {
object: {
id: 'sub_xyz',
status: 'canceled'
}
}
}
Best Practices
-
Event Processing
- Handle events idempotently
- Process in chronological order
- Verify webhook signatures
- Log all events
-
Error Handling
- Retry failed webhooks
- Monitor webhook health
- Set up alerts for failures
- Keep audit logs
-
Security
- Keep signing secret secure
- Validate all webhooks
- Monitor for suspicious activity
- Rotate secrets periodically
Common Issues
Events Not Received
- Check webhook configuration
- Verify signing secret
- Check event selection
- Test with Stripe CLI
Invalid Signature
- Verify secret matches
- Check for request modification
- Ensure raw body is preserved
- Verify timestamp tolerance
Out of Order Events
- Use event timestamps
- Implement idempotency
- Handle race conditions
- Log event sequence
Example: Event Handler
class WebhookHandler {
constructor(stripeSecret) {
this.stripeSecret = stripeSecret;
}
async handleWebhook(rawBody, signature) {
try {
// 1. Verify signature
const event = stripe.webhooks.constructEvent(
rawBody,
signature,
this.stripeSecret
);
// 2. Process based on type
switch (event.type) {
case 'customer.subscription.updated':
await this.handleSubscriptionUpdate(event.data.object);
break;
case 'invoice.payment_failed':
await this.handlePaymentFailure(event.data.object);
break;
// ... handle other events
}
// 3. Log success
await this.logWebhookEvent(event);
return { ok: true };
} catch (error) {
// 4. Log failure
await this.logWebhookError(error);
throw error;
}
}
async handleSubscriptionUpdate(subscription) {
// Implement your update logic
}
async handlePaymentFailure(invoice) {
// Implement your failure handling
}
async logWebhookEvent(event) {
// Implement your logging
}
async logWebhookError(error) {
// Implement your error logging
}
}