# Billing Portal

- **Method:** `POST`
- **Path:** `/api/v1/billing/portal`
- **Operation ID:** `billing_portal`
- **Tags:** usage

A link into Stripe's hosted customer portal for this tenant: cards, invoices, receipts.

Saram holds no payment instrument and renders no payment form - what it holds is the usage the
invoice is derived from, which is the two routes above. The Stripe customer is created here if this
tenant has never had one (`billing.ensure_customer`), so a tenant that has not run yet can still put
a card on file.

Minted per call and never cached: a portal session is short-lived and single-use, and a cached link
would hand the second person the first person's session.

## Effective servers

- `https://api.saram.sh`

  Saram

## Authentication

- **HTTPBearer**: HTTP bearer

  a Saram API key (`sk_saram_<env>_...`) or a person's AuthKit access token, as `Authorization: Bearer <credential>`. Both are told apart by shape and produce the same principal.

## Responses

### 200 Successful Response

**Content type:** `application/json`

schema: `BillingPortal`, no additional properties

A one-use link into Stripe's hosted customer portal (`POST /api/v1/billing/portal`).

Where a customer manages the card Saram never sees: Saram stores no payment instrument, renders no
payment form and is not in the flow at all. The link is short-lived and single-use by Stripe's design, so it
is minted per click and never cached; the invoices, receipts and the subscription behind it are Stripe's
screens, and what this API serves is the usage the invoice is derived from (`GET /api/v1/usage`).

- **`url` (required)**: `string`

  Where to send the customer. Short-lived and single-use; mint a new one per click.
- **`return_url`**: `string | null`

  Where Stripe sends them back to afterwards, when this deployment names one.

**Example:**

```json
{
  "url": "",
  "return_url": ""
}
```

### 403 this credential may not manage billing: an API key without the keys:admin scope, or a person whose role in this tenant is not owner or admin

### 502 Stripe refused the request or could not be reached; the detail is Stripe's own message

### 503 this deployment has no Stripe key configured, so there is no billing account to open

## Schemas

- `BillingPortal` — shown above.
