Billing & Payments

AIUS bills usage in AIUS tokens. Stripe handles payment processing (subscriptions, top-ups, the customer portal, invoices); the token balance and its per-org allocation are owned by the accounts backend.

AIUS tokens — the unit

The user-facing currency is AIUS tokens, never dollars-of-usage or provider cost.
  • **Grants are at par: 1=1,000tokens.Thefreetrialseeds50,000tokens;theProplan(1 = 1,000 tokens.** The free trial seeds **50,000 tokens**; the **Pro** plan (200/mo) grants 210,000 tokens per month (a deliberate bonus over the 200,000 you’d get at par).
  • Usage debits tokens at a spend rate that hides the platform margin: a call costing cost_cents of real compute debits round(cost_cents * 1000 / 90) tokens. You never see dollars-of-usage or the margin — only a token balance going down.
There is no “1 credit = $0.01” unit, and no monthly credit-quota plans (no Free/Basic/Pro/Enterprise quota tiers, no quota refresh). Spend is a single token balance.
For backward compatibility some balance responses still carry legacy *_usd and monthly_quota_* fields. They are vestigial — the meaningful unit is the AIUS-token field (balance_credits). Read tokens, ignore the dollar/quota fields.

Owner-held, allocatable balance (ADR-0060)

The token balance belongs to the account owner (the User), not to one organization. The owner allocates their balance across the orgs (clients) they created:
global = unallocated + Σ(each org's allocation)        # derived, never a stored counter
A per-call spend debits the org’s allocation. If an org’s allocation is exhausted, that call returns 402 even while the owner still holds unallocated tokens — the owner re-allocates to refill it. The conservation invariant (Σ org allocations ≤ global) reduces to unallocated ≥ 0, enforced hard-atomically at allocation time.

Get the owner balance

GET /v1/owner/balance
Response 200:
{
  "owner_id": "usr_abc123",
  "global_credits": 50000,
  "unallocated_credits": 0,
  "lifetime_granted_credits": 50000,
  "allocations": [
    {
      "org_id": "client_xyz789",
      "name": "Acme Corp",
      "is_default": true,
      "allocated_credits": 50000
    }
  ]
}
global_credits is derived (unallocated_credits + Σ of the owner’s live orgs’ allocations) — never a stored mutable counter.

Set an org’s allocation

Set an org’s allocation to an absolute token amount (this covers both funding an org and reclaiming from it). Only the org’s owner may allocate — a plain member cannot.
PUT /v1/owner/orgs/{org_id}/allocation
Request body:
{ "target_credits": 30000 }
Response 200: the updated owner balance (same shape as GET /v1/owner/balance). Raising an allocation beyond the unallocated pool returns 402 INSUFFICIENT_UNALLOCATED. Allocating to an org you don’t own returns 403 NO_ACCESS.

Subscriptions

Create a subscription checkout

Create a Stripe checkout session for a subscription (e.g. Pro).
POST /v1/clients/{client_id}/subscription/checkout
Request body:
{
  "price_id": "price_pro_monthly",
  "success_url": "https://aius.co/account/clients/{client_id}/billing?success=true",
  "cancel_url": "https://aius.co/account/clients/{client_id}/billing?canceled=true",
  "customer_email": "user@example.com"
}
Response 200:
{
  "session_id": "cs_1234567890",
  "checkout_url": "https://checkout.stripe.com/..."
}
On a completed Pro subscription the org’s owner pool is credited 210,000 tokens for the period.

Get the subscription

GET /v1/clients/{client_id}/subscription
Response 200:
{
  "org_id": "client_xyz789",
  "plan_name": "pro",
  "status": "active",
  "current_period_start": 1714560000,
  "current_period_end": 1717238400,
  "cancel_at_period_end": false,
  "stripe_subscription_id": "sub_1234567890"
}

Top-ups

Create a token top-up

Buy more tokens at par ($1 = 1,000 tokens) via Stripe checkout.
POST /v1/clients/{client_id}/credits/topup
Request body:
{
  "amount_usd": 1000,
  "success_url": "https://aius.co/account/clients/{client_id}/billing?success=true",
  "cancel_url": "https://aius.co/account/clients/{client_id}/billing?canceled=true",
  "customer_email": "user@example.com"
}
amount_usd is in cents (so 1000 = $10 → 10,000 tokens at par). Response 200:
{
  "session_id": "cs_1234567890",
  "checkout_url": "https://checkout.stripe.com/..."
}

Balance & transactions

Get the token balance

GET /v1/clients/{client_id}/credits/balance
Response 200:
{
  "org_id": "client_xyz789",
  "balance_credits": 48750,
  "allocation_credits": 50000
}
balance_credits is this org’s current AIUS-token balance; allocation_credits is the budget the owner last allocated to it (the dashboard’s progress bar scales against this, draining as the org spends).

List transactions

GET /v1/clients/{client_id}/credits/transactions?limit=50&offset=0
Response 200:
[
  {
    "id": 1,
    "org_id": "client_xyz789",
    "amount_credits": 50000,
    "transaction_type": "trial",
    "balance_after_credits": 50000,
    "description": "Free-trial tokens",
    "created_at": 1714560000
  }
]
Transaction types: trial (free-trial grant), subscription_credit (a subscription period’s grant), topup (purchased tokens), usage (tokens consumed by a run), refund.

Billing portal

Open Stripe’s self-service customer portal.
POST /v1/clients/{client_id}/billing/portal
Request body: { "return_url": "https://aius.co/account/clients/{client_id}/billing" } Response 200: { "portal_url": "https://billing.stripe.com/..." }

Payment methods

GET /v1/clients/{client_id}/payment-methods
Response 200:
[
  {
    "id": "pm_1234567890",
    "org_id": "client_xyz789",
    "type": "card",
    "brand": "visa",
    "last4": "4242",
    "exp_month": 12,
    "exp_year": 2027,
    "is_default": true
  }
]

Invoices

GET /v1/clients/{client_id}/invoices?limit=50&offset=0
Response 200:
[
  {
    "id": "in_1234567890",
    "org_id": "client_xyz789",
    "amount_due_cents": 20000,
    "amount_paid_cents": 20000,
    "status": "paid",
    "currency": "usd",
    "invoice_pdf": "https://pay.stripe.com/...",
    "created_at": 1714560000,
    "due_date": 1714646400
  }
]
Invoices are denominated in the currency Stripe charged (USD) — that’s the money you paid, distinct from the AIUS tokens those payments granted.

Webhooks

Stripe webhooks keep billing in sync (token grants are applied here, to the owner pool):
  • checkout.session.completed — processes a successful payment (top-up or subscription start); credits tokens.
  • invoice.paid — syncs a paid invoice; a Pro renewal grants the period’s 210,000 tokens.
  • invoice.payment_failed — handles a failed payment.
  • customer.subscription.created / updated / deleted — syncs subscription state.

Error handling

Billing endpoints return the standard error envelope:
{
  "detail": {
    "code": "INSUFFICIENT_UNALLOCATED",
    "message": "Not enough unallocated tokens for this allocation"
  }
}
Common codes:
  • INSUFFICIENT_UNALLOCATED — allocation exceeds the owner’s unallocated pool.
  • NO_ACCESS — you don’t own the org you tried to allocate to.
  • insufficient_credits / 402 — an org’s allocation is exhausted; re-allocate or top up.
  • payment_failed — Stripe payment processing error.
  • subscription_not_found — no active subscription for the client.