> ## Documentation Index
> Fetch the complete documentation index at: https://docs.browsary.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Billing & usage

> Monitor balances, start subscriptions, and charge one-off top-ups through the Browsary billing endpoints.

All billing endpoints live under `/api/billing/*` and require an authenticated, email-verified user unless stated otherwise. Prices are stored in minor currency units and returned as strings to avoid floating-point drift.

## Read-only views

* **Plan catalog** – `GET /api/billing/plans` returns marketing-friendly cards with `{ priceId, planId, name, currency, monthlyPrice, discount, headline, subheading, features[] }`. Use it to populate plan selectors in your UI.
* **Balances & history** – `GET /api/billing/overview` bundles:
  * `balances`: available and pending funds per currency.
  * `activeSubscription`: current plan metadata plus any included bonuses (network, CPU, token pools, etc.).
  * `transactions`: up to 50 most recent usage records (unit, billed amount, discounts, pending remainder) interleaved with top-ups.
  * `usagePricing`: canonical per-unit prices derived from `globalPrices`.

## Starting or changing a subscription

`POST /api/billing/subscription` expects `{ "priceId": "<stripe price id>" }` and returns `{ url }`, the Stripe Checkout page for the desired plan.

* The backend prevents downgrades; you must cancel or wait for the current period to expire.
* Upgrades automatically calculate prorated credits by comparing the remaining time on the current plan with the target price. The endpoint returns a checkout URL even when a discount applies.
* Supply `priceId` values surfaced by `/api/billing/plans` or your custom Stripe catalog loader.

Once Stripe confirms the subscription, the webhook handler (see below) activates the plan and records any promotional bonuses.

## Billing portal

`POST /api/billing/portal` opens the customer portal so users can manage payment methods or cancel subscriptions themselves. The response structure is `{ url }`. Only email-verified users can request a portal link.

## Top-ups

Use top-ups when you want prepaid balances without a recurring plan.

```bash theme={null}
curl http://localhost:3000/api/billing/top-up \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Cookie: token=<session>" \
  -d '{ "amount": "25", "currency": "USD" }'
```

Notes:

* `amount` is a decimal string; the server converts it to minor units before creating the Stripe Checkout session.
* Only the default currency is supported today.
* The response is `{ url }`, just like the subscription endpoint.

## Webhooks

`POST /api/stripe/webhook` ingests Stripe events and requires the raw request body plus the `stripe-signature` header. Configure Stripe to send `checkout.session.completed`, `customer.subscription.updated`, and `customer.subscription.deleted` events to this endpoint.

For local testing, run `stripe listen --forward-to localhost:3000/api/stripe/webhook`.

## Usage metering

Quartz-level usage data flows through `reportContainerUsage` and shows up as `billing_usage_records`. When the coordinator reports `resourceId`, `amount`, and `unit`, the server returns `{ action: "continue" }` or `{ action: "shutdown" }` to signal whether the workload can keep running. Review the raw usage rows via `/api/billing/overview` to reconcile your own ledgers.
