checkout object to the request you already send. Flexprice then defers the change, returns a payment link, and applies the change only after the payment succeeds. Omit checkout and the endpoint behaves exactly as before.
Supported flows
Both actions are created only through the endpoint that owns them. Passing either to
POST /checkout/sessions returns a validation error pointing you at the right endpoint:
The checkout object
How it works
- Flexprice validates the request and computes the amount to collect.
- A
ONE_OFFinvoice is created inDRAFTstatus. This invoice locks the amount — it is never recomputed later. - A checkout session is created in
pendingstatus. The change you asked for is stored on the session’sconfiguration, and the invoice and payment IDs are recorded ascheckout_invoice_idandcheckout_payment_id. - A payment is created in
INITIATEDstatus and the provider is called for a payment link. - The response includes a
checkout_sessionobject. Redirect the customer tocheckout_session.payment_action.url. - When the provider reports success, Flexprice completes the session: it applies the deferred change, finalizes the draft invoice, and marks the payment
SUCCEEDED.
Status at each phase
Poll
GET /v1/checkout/sessions/{id} from your redirect pages to read checkout_status before showing the customer a result.
Charge a saved payment method
Setcollection_method to charge_automatically to attempt an off-session charge against a payment method the customer has already authorized, instead of sending them to a payment page.
With
charge_automatically, Flexprice first looks for a confirmed saved token and tries to charge it off-session. Two outcomes are possible:
- The charge is submitted. No payment URL is returned, so there is nothing to redirect to. The session completes when the provider’s payment webhook arrives.
- No usable saved method exists, or the amount exceeds the mandate ceiling. Flexprice falls back to a Razorpay authorization link, which registers a mandate and collects this payment in one step. Redirect the customer to it as usual.
payment_action.url as optional in your integration and drive completion from the webhook rather than the redirect.
max_mandate_limit is capped against your tenant-level mandate ceiling for UPI only. If you request a higher limit than the tenant allows, the tenant ceiling applies. Card mandates have no ceiling.Guards and retries
One active session per target. A second pay-first request for the same subscription, or the same wallet, is rejected while a session isinitiated or pending. The error names the session that is already open:
idempotency_key scope. A key is reserved only while its session is active. Once the session reaches a terminal state the same key can be reused. Reusing a key that belongs to an active session returns a conflict rather than the existing session.
Webhook events
Completing a
modify_subscription session also publishes subscription.updated.
Related Topics
Gate a seat change
Require payment before a seat increase takes effect.
Gate a wallet top-up
Require payment before purchased credits land.

