Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save gyk/50e463966180db0033ca353c0525b1f2 to your computer and use it in GitHub Desktop.

Select an option

Save gyk/50e463966180db0033ca353c0525b1f2 to your computer and use it in GitHub Desktop.

Question

Regarding user subscription to our SaaS using Stripe: when they subscribe for the first time, upon receiving "checkout.session.completed" event, is it possible that the user has NOT paid the invoice?

And, on the first subscription, is "invoice.paid" usually sent before "checkout.session.completed" (if they pay immediately)? If they pay it later, will "invoice.paid" come later?

Answer (by Claude Sonnet 4.5)

Great questions about Stripe's webhook event ordering! Let me search for the most current information on this.Great questions! Here's what you need to know about Stripe subscription webhooks:

Can the invoice be unpaid when checkout.session.completed is received?

Yes, it's possible - but it depends on the payment method:

  • Card payments & synchronous methods: No, the invoice is already paid when you receive checkout.session.completed. The event only fires after successful payment[1][2][3].

  • Asynchronous payment methods (SEPA Direct Debit, BACS, bank redirects): Yes, the invoice may still be unpaid when checkout.session.completed fires. For these methods, you'll receive additional events:

    • checkout.session.async_payment_succeeded - when payment confirms
    • checkout.session.async_payment_failed - if payment fails[4][5]

Event Order: invoice.paid vs checkout.session.completed

For immediate payment (card payments):

  1. checkout.session.completed fires first - customer completed checkout
  2. invoice.paid fires second - invoice confirmed paid

If they pay later:

  • With async payment methods, checkout.session.completed fires immediately
  • invoice.paid fires later when the payment actually clears (days later for SEPA/BACS)

Special cases:

  • Free trials: checkout.session.completed fires, but invoice.paid won't fire until the trial ends and first payment succeeds
  • Network retries: Events may rarely arrive out of order - always design for idempotency[1][2][3]

Best Practice Recommendation

For critical access provisioning:

✅ Listen to invoice.paid for actual payment confirmation
✅ Use checkout.session.completed for UI/UX (thank you page)
✅ Handle checkout.session.async_payment_succeeded for async methods

This ensures your system works correctly regardless of payment method[4][3][6].


  1. Checkout Sessions | Stripe API Reference
  2. When Does Stripe's checkout.session.completed Trigger? Clarifying ...
  3. Will the Checkout.Session.Completed Stripe event be triggered only upon ...
  4. Stripe Webhooks: Invoice.paid vs Checkout.Session.Completed ...
  5. Stripe webhooks: checkout.session.completed for asynchronous payments ...
  6. Guide to Stripe Webhooks: Features and Best Practices
  7. Stripe Webhooks: Invoice.paid vs Checkout.Session.Completed
  8. Fulfill orders | Stripe Documentation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment