Skip to content
/api/v1/payment/create-checkout-session

Create a Stripe-hosted Checkout session for a subscription upgrade.

Create a Stripe-hosted Checkout session for a subscription upgrade. EXEMPT (`cost: 0`). Returns the Stripe URL — frontend MUST redirect via `window.location.href`.

Why use this

Server-side wrapper for `stripe.checkout.Session.create` (mode=subscription) — returns a Stripe-hosted checkout URL where the user enters card details and confirms the upgrade. EXEMPT (`cost: 0`). The frontend MUST redirect (not iframe-embed). On successful payment, Stripe webhooks `checkout.session.completed` → `_handle_checkout_completed` activates the subscription on `user_plans` (sets `plan`, `stripe_subscription_id`, `current_period_end`). On cancellation / failure the user is redirected back to `/account/subscription?cancelled=true`. The monthly paid plan uses the active canonical token-billing plan price maintained by Stripe provisioning, never the legacy catalogue price. Missing, inactive, or unconfigured paid token billing returns 400 `BAD_REQUEST` before Stripe is called. Free plans without a price remain unpurchasable.

Common use case

Pricing-page 'Upgrade to Paid' button: get plan id from /api/v1/plans/ → POST here with `?plan_id=2` → redirect browser to the returned URL → Stripe-hosted checkout → on success Stripe redirects back to `/account/subscription?session_id=...` → SPA polls /api/v1/billing/subscription for the activated state.

Monthly upgrades resolve their Stripe price from the active paid token-billing plan, the same source maintained by Stripe provisioning; the legacy catalogue price is ignored, with no fallback if billing setup is missing. Stripe-hosted subscription Checkout session for plan upgrades. EXEMPT (cost: 0). Wraps stripe.checkout.Session.create(mode='subscription'). The frontend MUST redirect (not iframe-embed) — Stripe blocks framing. On successful payment Stripe webhooks checkout.session.completed to /api/v1/payments/webhook → _handle_checkout_completed activates the subscription on user_plans (sets plan, stripe_subscription_id, current_period_end). The Free plan cannot be checked out (no stripe_price_id) — gate the 'Upgrade' button server-side rather than rendering for Free. To list available plans use GET /api/v1/plans/; to check post-upgrade state use GET /api/v1/billing/subscription; for self-serve subscription management (cancel, change card) once on a paid plan use POST /api/v1/account/billing-portal. For one-time USD wallet top-ups (NOT subscription upgrades) use POST /api/v1/payments/create-intent.

Parameters

NameInRequiredDefaultAllowedDescriptionExample
plan_idqueryrequired——Plan database ID (NOT name) — the integer `id` from [GET /api/v1/plans/](/docs/account/billing-and-subscription/get-plans). Returns 400 `BAD_REQUEST` if missing or non-numeric, 404 `NOT_FOUND` if the plan does not exist or is inactive, 400 `BAD_REQUEST` if the selected plan has no purchasable price; monthly upgrades require an active paid token-billing plan with a configured Stripe price.2

Response schema

FieldTypeNullableDescription
statusstringnoCheckout session was created successfully.
request_idstringyesRequest correlation identifier, when available.
timestampstringnoResponse creation time in UTC.
dataobjectnoCheckout-session payload.
data.urlstringnoStripe-hosted Checkout URL. Redirect the browser to this URL; do not embed it in an iframe. Creating a session does not activate the subscription: payment completion and the existing Stripe webhooks do that.

Sample response

·
  • "status": "success"
  • "request_id": "req_3OqK2jK9L8pQ4xZ6"
  • "timestamp": "2026-05-02T15:51:00.000Z"
  • "data":
    • "url": "https://checkout.stripe.com/c/pay/cs_test_b1Yq8nL7aP2kT6sB1mDfHj9vC3xRtKzE5wQ8jN4uM2pX7yI6oA9hT0gU1vF#fidkdWxOYHwnPyd1blpxYHZxWjA0SF9MUFc2dVZxYG1QSXNqcGhJQDR9aGhNNXxPSk09Q1xLTHN1MnxwfFBIYDU8YzVtXX1HSUtAaD1KaHM3RkB"
    }
}

Errors

StatusLabelDescription
200OKRequest succeeded.
400Bad RequestInvalid query, body, or path parameter.
401UnauthorizedMissing or invalid Authorization header / api_Token.
402Payment RequiredInsufficient token balance for this call. Top up
429Too Many RequestsRate limit exceeded for your tier (see /pricing for tier limits). Tier limits
500Server ErrorUnexpected server-side failure. Retry with backoff; report if persistent.

Code samples

curl -X POST "https://api.finradar.ai/api/v1/payment/create-checkout-session?plan_id=2" \
  -H "X-API-Key: YOUR_API_KEY"

Generate an API key in /account/credentials to run live queries (literal YOUR_API_KEY placeholder shown until then).