---
title: "Start checkout (principal-scoped)"
method: POST
path: "/v2/billing/checkout"
tags: ["Billing"]
---

# Start checkout (principal-scoped)

`POST /v2/billing/checkout`

## Request

- Base URL: `https://api.infolang.ai`
- URL: `https://api.infolang.ai/v2/billing/checkout`
- Auth: HTTP bearer

Starts a subscription for an account that does NOT have one. An account that already subscribes is refused `409 already_subscribed` — a second checkout would create a second subscription against the same Stripe customer and bill both. Switch plans with `POST /v2/billing/plan`.

## Request body

- object
  - `plan` string

## Response `200`

Checkout URL

- object
  - `url` string, required

## Other responses

- `401`: Missing or invalid session token
- `403`: Caller lacks a grant on the workspace, or role too low. Or `lane_not_supported` — an `il_live_`/`il_test_`/`il_oauth_` credential, though valid, was presented to a route that accepts the session lane only
- `409`: already_subscribed — this account already holds a live Stripe subscription. Returned by CHECKOUT, which would otherwise create a SECOND subscription against the same customer and bill both (it did, in production, to anyone who upgraded). Switch plans with the plan route instead.
- `500`: internal_error — unexpected failure (e.g. billing backend misconfigured or unreachable)
- `503`: not_configured — self-serve billing is not available on this deployment: either no payment processor is wired, or its prices do not reconcile with the published catalog. Returned INSTEAD of a checkout URL, because the alternatives were a link to a domain that does not resolve and a checkout that charges an amount the page never showed. Mirrors `self_serve_checkout` on both summaries exactly — same evaluation, same cache.

---

[API](https://skmtc.dev/infolang/apis/infolang-api.md) · [All operations](https://skmtc.dev/infolang/apis/infolang-api/llms.txt) · [OpenAPI document](https://skmtc.dev/infolang/apis/infolang-api/revisions/d04bf6de72c8?raw)
