Skip to main content

reconcileCheckoutSession

Settle a completed Stripe Checkout Session immediately, instead of waiting for the webhook.

Between checkout completing and customer.subscription.* landing — measured at 5-30 seconds — the organization still resolves to the Free entitlement, so a customer who has just paid is told to upgrade. Refreshing does not help, and a reasonable person concludes the payment failed.

The console calls this on the Stripe return, with the session_id Stripe substitutes into the success URL. The webhook remains authoritative for anyone who closed the tab, and the two converge: settling the same session through both paths, in either order, leaves exactly one subscription.

sessionID is CLIENT-SUPPLIED and Stripe session ids are not secrets — they appear in URLs, browser history, referrer headers and support tickets. Ownership is therefore proved from the session's own Stripe-side metadata, which the server stamped at creation, never from the caller's word. Every refusal returns one indistinguishable CHECKOUT_SESSION_NOT_FOUND so the mutation cannot become an oracle over session ids.

Deliberately NOT @requiresStepUp. The manage-billing grant is consumeOnFirstUse and was spent creating the session, and bouncing the customer to re-authenticate on the Stripe return is precisely the friction this mutation exists to remove — roughly half of production users cannot answer a password challenge.

Returns the organization's subscription posture after settling, so the caller refreshes from the same response rather than racing a refetch.

reconcileCheckoutSession(
ownerID: String!
sessionID: String!
): SubscriptionInfo!

Arguments​

reconcileCheckoutSession.ownerID ● String! non-null scalar​

reconcileCheckoutSession.sessionID ● String! non-null scalar​

Type​

SubscriptionInfo object​

Current subscription information for an organization, including plan details and feature access