Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.aspfox.com/llms.txt

Use this file to discover all available pages before exploring further.

AspFox handles five Stripe webhook events. The endpoint is POST /api/v1/webhooks/stripe.

Handled events

EventWhat triggers it in StripeAspFox actionLocal state change
checkout.session.completedCustomer completes payment on Stripe’s hosted checkout pageCreates 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.updatedPlan change, trial conversion to paid, cancellation scheduled, pauseUpdates local subscription fields to match Stripe.Updates Plan, Status, CurrentPeriodEnd, CancelAtPeriodEnd. If cancel_at_period_end becomes true, creates SubscriptionCanceled notification.
customer.subscription.deletedSubscription fully canceled (immediately or at period end)Marks local subscription as canceled.Sets Status = Canceled.
invoice.payment_failedStripe could not charge the customer’s payment methodMarks local subscription as past due. Sends payment failed email. Creates SubscriptionPastDue notification for owner.Sets Status = PastDue.
invoice.payment_succeededStripe successfully charged the customerIf 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 if StripeSubscriptionId already matches before creating a new record
  • customer.subscription.updated — compares incoming values to current values; if identical, no database write
  • customer.subscription.deleted — if status is already Canceled, no-op
  • invoice.payment_failed — if status is already PastDue, skips the email and notification to avoid duplicate sends
  • invoice.payment_succeeded — if status is already Active, 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 the Stripe-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 by SubscriptionSyncJob).