AspFox handles five Stripe webhook events. The endpoint isDocumentation Index
Fetch the complete documentation index at: https://docs.aspfox.com/llms.txt
Use this file to discover all available pages before exploring further.
POST /api/v1/webhooks/stripe.
Handled events
| Event | What triggers it in Stripe | AspFox action | Local state change |
|---|---|---|---|
checkout.session.completed | Customer completes payment on Stripe’s hosted checkout page | Creates or updates the local Subscription record. Reads tenantId from session.metadata. | Sets Plan and Status to Trialing (if trial started) or Active. Sets StripeSubscriptionId and StripeCustomerId. |
customer.subscription.updated | Plan change, trial conversion to paid, cancellation scheduled, pause | Updates local subscription fields to match Stripe. | Updates Plan, Status, CurrentPeriodEnd, CancelAtPeriodEnd. If cancel_at_period_end becomes true, creates SubscriptionCanceled notification. |
customer.subscription.deleted | Subscription fully canceled (immediately or at period end) | Marks local subscription as canceled. | Sets Status = Canceled. |
invoice.payment_failed | Stripe could not charge the customer’s payment method | Marks local subscription as past due. Sends payment failed email. Creates SubscriptionPastDue notification for owner. | Sets Status = PastDue. |
invoice.payment_succeeded | Stripe successfully charged the customer | If subscription was PastDue, recovers it. Sends payment recovered email. Creates PaymentRecovered notification. | If was PastDue: sets Status = Active, sends email and notification. If already Active: no-op. |
Idempotency
Every handler checks current state before writing. Running the same handler twice with the same event produces the same result:checkout.session.completed— checks ifStripeSubscriptionIdalready matches before creating a new recordcustomer.subscription.updated— compares incoming values to current values; if identical, no database writecustomer.subscription.deleted— if status is alreadyCanceled, no-opinvoice.payment_failed— if status is alreadyPastDue, skips the email and notification to avoid duplicate sendsinvoice.payment_succeeded— if status is alreadyActive, no-op
AspFox returns
200 OK for all webhook events, including events it does not handle. Stripe requires a 2xx response to consider delivery successful. Returning non-2xx for unhandled events causes Stripe to retry indefinitely and eventually disable the endpoint.Webhook signature verification
Every request to the webhook endpoint is verified using theStripe-Signature header and STRIPE_WEBHOOK_SECRET. Requests with an invalid or missing signature are rejected with 400 Bad Request before any processing occurs.
Do not disable signature verification. The webhook endpoint is public — without signature verification, anyone could send fake webhook events to manipulate subscription state.
Webhook delivery timing
Stripe delivers webhooks asynchronously after the triggering event. The delay is typically under 30 seconds but can be longer during Stripe incidents. AspFox does not poll Stripe on every request — local state may lag behind Stripe by up to 30 seconds after an event, or up to 2 hours in the case of a missed webhook (corrected bySubscriptionSyncJob).