Webhooks
Smidge uses Stripe webhooks to handle payment events and keep subscription state synchronized. This page documents the webhook events that Smidge processes.
Handled Events
| Event | Description | Action |
|---|---|---|
checkout.session.completed | Customer completed a Stripe checkout session. | Credits are added to the user's account, or subscription is activated. |
customer.subscription.updated | A subscription was modified (plan change, renewal, etc.). | User's plan and unlimited status are updated accordingly. |
customer.subscription.deleted | A subscription was cancelled or expired. | User is downgraded. Access continues until the current period ends. |
checkout.session.completed
Triggered when a customer completes payment through Stripe Checkout. Smidge reads the session metadata to determine the action:
Credit Purchase
For one-time credit pack purchases (Starter, Pro Pack), the webhook adds the corresponding credits to the user's account:
| Plan | Credits Added |
|---|---|
| Starter | 5 credits |
| Pro Pack | 15 credits |
Subscription Start
For Unlimited subscriptions, the webhook activates the subscription and sets the user's is_unlimited flag to true.
customer.subscription.updated
Triggered when a subscription changes state. Common scenarios:
| Change | Action |
|---|---|
| Renewal | Subscription period is extended. No user-facing change. |
| Payment failed | Status updated to past_due. User is notified via email. |
| Plan change | User's plan tier is updated. |
customer.subscription.deleted
Triggered when a subscription is cancelled or reaches its end date. Smidge:
1. User cancels subscription (via Stripe Customer Portal)
2. Stripe fires customer.subscription.deleted at period end
3. Smidge sets is_unlimited = false
4. User reverts to credit-based usage
5. Existing credits (if any) remain availableWebhook Security
All incoming webhooks are verified using Stripe's webhook signature mechanism. Smidge uses the stripe.webhooks.constructEvent() method to verify the Stripe-Signature header against the webhook signing secret.
const event = stripe.webhooks.constructEvent(
requestBody,
request.headers['stripe-signature'],
process.env.STRIPE_WEBHOOK_SECRET
);Requests that fail signature verification are rejected with a 400 Bad Request response.