Billing
Read org balance, usage, and transactions; deposit funds via Stripe Checkout; manage BYOK keys.
Billing is pay-as-you-go with a real USD balance held in cents. Token usage is recorded in microcents (1 cent = 10,000 microcents). Deposits raise both balanceCents and cumulativeDepositsCents; the platform fee is waived until cumulative deposits exceed the configured threshold.
Endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/v1/billing | Balance, current-month usage, recent transactions, waiver status. |
PATCH | /api/v1/billing | Configure auto top-up. Requires billing-manage permission. |
POST | /api/v1/billing/deposit | Start a deposit (Stripe Checkout or direct in non-production). |
GET | /api/v1/billing/transactions | Paginated transaction history. |
GET | /api/v1/billing/pricing | Per-model pricing with platform fee applied, plus service prices. |
GET | /api/v1/billing/spending | Spending summary, daily series, and top agents/models. |
GET | /api/v1/billing/spending/by-model | Spending grouped by model. |
GET | /api/v1/billing/spending/by-agent | Spending grouped by agent. |
GET | /api/v1/billing/spending/by-project | Spending grouped by project. |
GET | /api/v1/billing/byok-keys | List Bring-Your-Own-Key entries. |
POST | /api/v1/billing/byok-keys | Add a BYOK entry. |
DELETE | /api/v1/billing/byok-keys/:id | Remove a BYOK entry. |
Balance and usage summary
GET /api/v1/billing returns the org's billing snapshot:
{
"success": true,
"data": {
"balance": {
"balanceCents": 0,
"cumulativeDepositsCents": 0,
"autoTopupEnabled": false,
"autoTopupThresholdCents": 500,
"autoTopupAmountCents": 2500
},
"waiver": { "active": true, "remainingCents": 10000 },
"payment": {
"stripeConfigured": true,
"webhookConfigured": true,
"publishableKeyConfigured": true,
"directDepositAvailable": false,
"billingEnforced": true
},
"usage": {
"currentMonth": {
"inputTokens": 0,
"outputTokens": 0,
"cacheReadTokens": 0,
"cacheWriteTokens": 0,
"providerCostMicrocents": 0,
"platformFeeMicrocents": 0,
"totalChargedMicrocents": 0,
"totalChargedCents": 0,
"requestCount": 0,
"byokRequestCount": 0,
"totalTokens": 0,
"monthStart": "2026-05-01T00:00:00.000Z",
"operationBreakdown": [
{ "operation": "chat", "requestCount": 12, "totalChargedMicrocents": 1234, "totalChargedCents": 1 }
]
}
},
"transactions": [
{ "id": "uuid", "type": "deposit", "amountCents": 1000, "stripePaymentIntentId": "pi_...", "notes": null, "createdAt": "..." }
],
"promotions": []
}
}
Update auto top-up
PATCH /api/v1/billing
| Field | Type | Description |
|---|---|---|
autoTopupEnabled | boolean | Toggle automatic top-ups when balance drops below threshold. |
autoTopupThresholdCents | integer | Minimum 100 (=$1.00). |
autoTopupAmountCents | integer | Minimum 100 (=$1.00). |
Requires the caller to pass assertCanManageBilling. Returns { "updated": true }.
Deposit
POST /api/v1/billing/deposit
| Field | Type | Required | Description |
|---|---|---|---|
amountCents | integer | yes | 100 ≤ x ≤ 100,000 (i.e. $1.00–$1,000.00). |
method | "direct" | no | Only honored in non-production when Stripe is unconfigured or the env opts in. |
When Stripe is configured, the response is a Checkout Session:
{ "success": true, "data": { "checkoutUrl": "https://...", "sessionId": "cs_..." } }
Redirect the user to checkoutUrl. On completion, Stripe sends a webhook to /api/v1/billing/webhooks/stripe, which credits the balance and writes a deposit transaction.
When Stripe is not configured (local/dev), the response is:
{ "success": true, "data": { "deposited": 1000, "method": "direct", "message": "Deposit applied directly (Stripe not configured)" } }
curl -X POST https://alumia.com/api/v1/billing/deposit \
-H "Authorization: Bearer alm_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "amountCents": 1000 }'Transactions
GET /api/v1/billing/transactions?type=&limit=&page= — Paginated list. Valid type values: deposit, usage, refund, adjustment, platform_fee. Unknown values fall back to no filter.
Pricing
GET /api/v1/billing/pricing — Returns the platform fee rate, per-model rates with the fee already applied, and the list of billable service prices.
Spending analytics
GET /api/v1/billing/spending?period= returns a summary, daily series, and the top agents and models by spend. The period query accepts today, week, month, year, etc. (normalized server-side). Sub-routes (by-model, by-agent, by-project) return single-axis breakdowns over the same period.
BYOK
GET /api/v1/billing/byok-keys returns the caller's keys (provider, label, fingerprint), never the plaintext.
POST /api/v1/billing/byok-keys
| Field | Type | Required | Description |
|---|---|---|---|
provider | string | yes | Must be one of BYOK_PROVIDERS (Anthropic, OpenAI, etc.). |
key | string | yes | 16–500 chars. |
label | string | no | Up to 200 chars. |
Rate-limited per userId + IP.
DELETE /api/v1/billing/byok-keys/:id removes the entry.
Errors
| Code | When |
|---|---|
UNAUTHORIZED | No valid key. |
PAYMENT_REQUIRED | Org cannot use paid models because the balance is exhausted. (Surfaced from chat routes, not billing reads.) |
FORBIDDEN | Caller lacks billing-manage role for PATCH or POST /deposit. |
BAD_REQUEST | Amount out of range, invalid auto top-up values, missing/oversized BYOK fields, unknown provider, or rate limit exceeded. |