aiml docs
Billing

Billing basics

Prepaid credits, integer micro-USD, one rounding per line, and how a request is charged.

The model

aiml is prepaid. You top up in your billing currency, the money becomes USD credits, and every request settles against them. There are no monthly invoices for usage; every top-up gets an invoice.

  • Credits are integers. Balances and costs are micro-USD (1_000_000 = $1). Prices are nano-USD per token. Nothing in the billing path uses floats.
  • One rounding per line. Each usage line (input, output, cache read, cache write, reasoning, request fee) is tokens × nano_price → micro, rounded once. Sums are never rounded again. aiml.cost.lines in the response shows the lines.
  • Pinned prices. The price version is fixed when the request is reserved and the request settles against it, even if the catalog changes mid-flight. aiml.cost.price_version names it.

Life of a charge

  1. Reserve. Before the upstream call the gateway estimates the cost from your prompt and max_tokens and moves that amount from available to held. If available cannot cover it, the call fails with 402 insufficient_credits and x-aiml-required-micro tells you how much it needed.
  2. Checkpoint. Long streams re-reserve as they go; a stream that exhausts the balance ends with stop reason budget_exceeded rather than running negative.
  3. Settle. After the last byte, the held amount is replaced by the real cost from the provider's usage (usage.source = "provider") or, if the provider sent none, from the gateway's tokenizer (estimated). Settlement is idempotent on the request id.

GET /v1/credits returns available_micro_usd, held_micro_usd and the balance in your display currency. GET /v1/credits/ledger is the append-only ledger; add format=csv for a download.

Topping up

GET /v1/credits/topups/quote?amount_minor=… tells you what an amount buys before you pay: the booked FX rate (RBI reference rate + 0.5% for INR), tax, rail fees and the resulting credits. POST /v1/credits/topups creates the top-up and returns a hosted checkout URL (Razorpay for INR, Stripe otherwise); credits land when the payment webhook confirms.

RecipientInvoice
India, same state as the suppliertax invoice, CGST 9% + SGST 9%
India, other statetax invoice, IGST 18%
Outside Indiaexport invoice under LUT, no GST

Invoices are numbered per financial year (AIML/26-27/000001) and available as JSON, HTML and PDF under GET /v1/invoices. When the rail charges a processing fee it appears as its own line on the invoice (UPI is free; cards and Stripe pass their fee through at cost), so the invoice total always equals what you paid at checkout.

Auto top-up

Register a mandate once (POST /v1/credits/mandates with method upi, emandate or card; Razorpay e-mandate / UPI AutoPay in India, a saved card on Stripe elsewhere) and finish the authorisation on the rail's page. Then PUT /v1/credits/auto-topup with threshold_micro and amount_minor. When the balance drops below the threshold the worker schedules a debit 24 hours ahead and announces it (topup.scheduled webhook and the billing email; that is the RBI pre-debit notification), then charges the mandate for the amount plus tax and books the top-up like any other, invoice included. The amount plus tax must fit the mandate's per-debit cap (₹15,000 without additional authentication); a debit is skipped if the balance recovered meanwhile, and three consecutive failures disable auto top-up (mandate.failed). GET /v1/credits/auto-topup shows the mandate state, the cap and any scheduled debit.

Invoices, credit notes and refunds

An issued invoice never changes. Corrections are credit notes (kind: credit_note, numbered AIMLCN/26-27/000001, referencing the invoice through ref_invoice_id) and, where the recipient details were wrong, a reissued invoice that names the one it replaces (reissued_from). Both show up in GET /v1/invoices next to the original.

Unused credits go back the way they came. POST /v1/credits/topups/{id}/refund with an optional amount_minor (the taxable value; omit it for everything still refundable) sends the money plus its tax to the Razorpay or Stripe payment that funded the top-up, removes the credits at the top-up's booked FX rate (a refund ledger line) and issues a credit note against the top-up invoice. A refund needs the credits to still be in your balance; the processing fee is not refundable. Pass an Idempotency-Key header to make retries safe. GET /v1/credits/refunds lists them.

Indian GST e-invoicing (IRN + QR) is generated for B2B tax invoices, credit notes and exports once it applies to the supplier; irn_status on the invoice moves from pending to generated, and the PDF is re-rendered with the IRN block.

Plans

GET /v1/plans lists the plans: Pay as you go (no fee) and the team plans, which carry a monthly fee in USD, a bundle of included credits and higher limits. Periods are calendar months.

  • POST /v1/billing/subscription with plan_id moves the org. Upgrades and first subscriptions apply immediately and are prorated to the remaining whole days of the month: the fee difference is taken from your prepaid balance (plan_fee ledger line) and the included-credit difference is added (plan_credit), with a plan invoice in your billing currency.
  • Downgrades, including back to pay as you go, take effect at the end of the period; you keep what you paid for until then. Choosing your current plan again cancels a scheduled downgrade.
  • Renewal happens on the first of each month from the balance. If the balance cannot cover the fee the subscription is past_due; after seven days the org returns to pay as you go.

GET /v1/billing/subscription shows the current plan, period and any scheduled change.

Budgets and limits per key

Keys can carry budget.daily_micro and budget.monthly_micro, and so can the key's project; each is its own ceiling and the narrower one applies. A hard budget rejects calls with insufficient_credits code budget_exceeded.daily or budget_exceeded.monthly, and param names the ceiling that refused — budget_daily / budget_monthly for the key's own, project_budget_daily / project_budget_monthly for the project's; a soft one warns (budget_soft_exceeded, same param). The budget.threshold and budget.exhausted webhooks carry the same value as dimension. Rate limits (rpm, tpm, concurrency) are separate; see Rate limits.

On this page