discourse/plugins/discourse-subscriptions/app
David Taylor aa2dc0ad1d FIX: Gate checkout provisioning on payment_status and handle async payments [backport 2026.4]
Backport of #628 to release/2026.4.

---

When a Stripe Checkout session uses a delayed payment method (e.g., bank transfers, SEPA debits), Stripe fires [`checkout.session.completed`](https://docs.stripe.com/api/events/types#event_types-checkout.session.completed) with [`payment_status: "unpaid"` rather than `"paid"`](https://docs.stripe.com/api/checkout/sessions/object#checkout_session_object-payment_status). The discourse-subscriptions plugin previously ignored this field entirely, provisioning group membership and creating customer/subscription records as soon as the checkout completed.

This meant users could gain access to subscription-gated groups without having paid, and the plugin had no handler for the follow-up [`checkout.session.async_payment_succeeded`](https://docs.stripe.com/api/events/types#event_types-checkout.session.async_payment_succeeded) event that Stripe sends once the delayed payment clears.

This commit adds a `payment_status` guard to the `checkout.session.completed` handler so sessions with unpaid status return early without provisioning. It also introduces a `checkout.session.async_payment_succeeded` handler that provisions access once the delayed payment succeeds.

https://github.com/discourse/discourse/security/advisories/GHSA-pjgj-7mjq-6j7g
2026-05-19 00:25:09 +01:00
..
controllers FIX: Gate checkout provisioning on payment_status and handle async payments [backport 2026.4] 2026-05-19 00:25:09 +01:00
jobs
models/discourse_subscriptions
serializers/discourse_subscriptions
services/discourse_subscriptions DEV: Fix assigned but unused variable Prism warnings (#39436) 2026-04-22 12:42:14 +02:00