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

# Credits and billing

> Credit model, balance, usage, Stripe checkout, and webhook fulfilment.

ai-cmo.dev uses a micro-USD credit system. 1,000,000 µUSD = \$1.00. Every metered operation (measurement run, SEO refresh, chat, research) reserves credits up front and settles the actual cost after completion.

## Endpoints

| Method | Path                                              | Scope          | Description                                      |
| ------ | ------------------------------------------------- | -------------- | ------------------------------------------------ |
| GET    | `/api/v1/workspaces/{workspace}/credits/balance`  | `credits:read` | Current balance (posted, held, available)        |
| GET    | `/api/v1/workspaces/{workspace}/credits/usage`    | `credits:read` | Usage ledger (limit param, default 100, max 500) |
| POST   | `/api/v1/workspaces/{workspace}/credits/top-up`   | Session-only   | Mock top-up (local/test only)                    |
| POST   | `/api/v1/workspaces/{workspace}/billing/checkout` | Session-only   | Create Stripe checkout session                   |
| GET    | `/api/v1/workspaces/{workspace}/billing/status`   | Session        | Billing status                                   |

## Credit model

1. **Free grant**: New workspaces receive 1,000,000 µUSD (\$1.00), expiring in 30 days. One grant per user.
2. **Reserve-then-settle**: An operation reserves an estimated amount. As the operation runs, incremental leases are authorized against the reservation. When complete, the actual cost is settled.
3. **Insufficient credits**: If the balance cannot cover a reservation, the operation fails with `402 insufficient_credits` including `requiredMicrousd` and `availableMicrousd` in `details`.

## Read balance

```bash theme={null}
curl -H "Authorization: Bearer gp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
     https://ai-cmo.dev/api/v1/workspaces/{workspace}/credits/balance
```

Response:

```json theme={null}
{
  "workspace": "acme",
  "state": "active",
  "postedMicrousd": 1000000,
  "heldMicrousd": 250000,
  "availableMicrousd": 750000,
  "nextExpiryAt": "2026-09-09T10:00:00.000Z"
}
```

## Read usage

```bash theme={null}
curl -H "Authorization: Bearer gp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
     "https://ai-cmo.dev/api/v1/workspaces/{workspace}/credits/usage?limit=100"
```

Returns minimal ledger and metered-operation data. The `limit` parameter defaults to 100 and has a maximum of 500.

## Stripe checkout

Session-only. Creates a Stripe Checkout Session for a credit top-up.

```bash theme={null}
curl -X POST https://ai-cmo.dev/api/v1/workspaces/{workspace}/billing/checkout \
  -H "Cookie: geo.session=..." \
  -H "Content-Type: application/json" \
  -d '{"amountMicrousd": 10000000}'
```

Request body:

<ParamField name="amountMicrousd" type="integer" required>
  Top-up amount in micro-USD. Minimum 5,000,000 µUSD ($5.00), maximum 500,000,000 µUSD ($500.00), in whole cents (multiples of 10,000 µUSD).
</ParamField>

Response:

```json theme={null}
{
  "url": "https://checkout.stripe.com/pay/cs_test_...",
  "checkoutSessionId": "cs_test_abc123"
}
```

## Mock top-up

Available only in local/test mode (when `STRIPE_SECRET_KEY` is not set or `GEO_OPERATOR_MODE=local`). Session-only.

```bash theme={null}
curl -X POST https://ai-cmo.dev/api/v1/workspaces/{workspace}/credits/top-up \
  -H "Cookie: geo.session=..." \
  -H "Content-Type: application/json" \
  -d '{"amountMicrousd": 500000, "idempotencyKey": "topup-unique-01"}'
```

When Stripe is configured, mock top-ups return `409 mock_topup_disabled`.

## Reservation amounts

| Operation              | Current reservation                               |
| ---------------------- | ------------------------------------------------- |
| Measurement (standard) | From pricing config + workspace prompts           |
| Measurement (lite)     | From pricing config + workspace prompts           |
| Measurement (smoke)    | From pricing config + workspace prompts           |
| Measurement (exa)      | From pricing config + workspace prompts           |
| SEO refresh            | From pricing config                               |
| Chat                   | 720,000 µUSD per turn (6 steps, 120,000 per step) |
| Prompt generation      | 250,000 µUSD per call, max 100 calls              |
| Research               | 80 provider calls with provider-specific caps     |

## Billing status

```bash theme={null}
curl -H "Cookie: geo.session=..." \
     https://ai-cmo.dev/api/v1/workspaces/{workspace}/billing/status
```

Returns receipts for the latest 20 checkout sessions with their status (`pending`, `succeeded`, `failed`).

## Stripe webhook

`POST /api/v1/webhooks/stripe` (public route)

Stripe sends `checkout.session.completed` and `checkout.session.expired` events to this endpoint. The server verifies the signature against `STRIPE_WEBHOOK_SECRET`. If the secret is unset, the webhook fails closed with `503 billing_unavailable`.

The webhook is idempotent: a replayed `checkout.session.completed` event never double-credits.
