GET/billing/usage
GET/billing/purchase
POST/billing/checkout/subscribe
POST/billing/checkout/topup
POST/billing/portal
The two checkout/* calls and portal each return a Stripe URL for the customer to open. Card details never touch this API and there is no endpoint that accepts them, plan changes, payment methods and cancellations all happen in Stripe's hosted portal.
{ "url": "https://billing.stripe.com/p/session/live_YWNjd…" }
Do not poll
/billing/usage to detect a plan change
The subscription becomes active when Stripe's webhook lands, which is shortly after the customer finishes checkout but is not synchronous with their return to your page. Poll briefly after a return from the portal if you must, but treat a tier that has not moved yet as "not yet", not as a failure.
When billing blocks a call#
code | Situation | Resolution |
|---|---|---|
payment_past_due | The subscription exists but the last invoice failed. | POST /billing/portal → update the card. |
allowance_exhausted | The plan's included generation allowance is used up for the period. | POST /billing/checkout/topup, or wait for the period to roll. |
Both are 403. Neither is retryable. A retry loop on allowance_exhausted will run until the period ends.