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

Handled events

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).