Skip to content
Open Markdown

Billing and checkout ​

Prerequisites: a user JWT, a configured product catalog and Stripe integration. The examples use Quickstart's apiRequest helper. Replace every example price/product ID with one returned by your deployment.

Choose and purchase a product ​

  1. Read listPublicProducts or the purchasable packs from getMyBilling. The public products endpoint returns a bare array.
  2. Select the product's configured price. A credit pack uses one-off payment; a plan uses a single-seat subscription.
  3. Create createCheckoutSession and redirect to its non-null URL.
ts
const checkout = await apiRequest("/v1/me/billing/checkout-session", {
  method: "POST",
  body: JSON.stringify({
    priceId: "price_example",
    successUrl: "https://portal.example.com/billing?checkout=success",
    cancelUrl: "https://portal.example.com/billing?checkout=cancelled",
    quantity: 1,
  }),
});
if (!checkout.url) throw new Error("Checkout did not return a redirect URL");
window.location.assign(checkout.url);
json
{"url":"https://checkout.stripe.com/example","id":"cs_example"}

Supply productId or priceId. When supplying both, the price must match the catalog product's default. quantity applies to credit packs; subscriptions remain single-seat. The server selects the payment mode and creates the customer's Stripe record when needed.

Returning to successUrl is not evidence that credits are available. Re-read billing until the processed payment is reflected; do not update balances from a redirect query parameter. Checkout has no client-facing Idempotency-Key contract, so avoid automatically resending a POST after an ambiguous result.

Manage and inspect billing ​

createBillingPortalSession takes { "returnUrl": "https://portal.example.com/billing" } and returns { "url": "..." }. Redirect there for provider-managed subscription/payment settings.

getMyBilling includes credit balance, tier/limits, subscription state and live credit lots. Numeric values can be strings or numbers; normalize before arithmetic. listMyCreditLedger has { data, meta: { page, per_page } } without total. listMyInvoices wraps data and returns up to 50 recent invoices; it is empty before a Stripe customer exists. Stripe invoice amount fields use the currency's minor units; credit values are separate units.

Recover from 404 product by refreshing catalog choices. 422 price_mismatch or product_has_no_price needs a corrected selection/catalog configuration. Maintenance can return 503 with Retry-After; see Errors. Staff adjustments, gifts, refunds and plan changes have separate permissions and operations in the reference; they are not a user checkout shortcut.

Built for developers. Ready for agents.