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

# Billing

> Prepaid balance, billable tokens, adding credit, and credit expiry.

## Prepaid balance

The Decision API is prepaid. Your account has one balance in US dollars, and each successful request is charged from it. There are no subscriptions and no invoices for usage.

The balance belongs to your personal console account. It is separate from any Torchcast app subscription or credits your organization has, and the two never transfer into each other.

## Prices

Prices are per 1,000,000 billable input tokens and can differ by model. The live price of each model is the `price_per_million_input_tokens_usd` field of [`GET /v1/models`](/models#list-the-models). These docs never state a price; read it from that endpoint.

## What is charged

Only successful (`200`) requests are charged. Errors, including timeouts (`504`), are never charged.

A request is charged for its **billable input tokens**, reported in the response as `usage.input_tokens`:

* the `state`, counted once, however many questions the request has;
* every question's `instructions`;
* every question's `criteria`: `noul` descriptions, `choice` option names and their descriptions, and `score` level labels.

Objects and arrays count as their compact JSON. `usage.output_tokens` is reported for information and is not charged.

The charge for a request is `usage.input_tokens` x the model's price / 1,000,000, rounded up to the next 0.000001 USD, with a minimum of 0.000001 USD.

### How a request draws on the balance

Before calling the model, the API sets aside an upper bound for the request from your balance, based on the size of its billable text (text outside the ASCII range sets aside more per character). When the request succeeds, it is charged its actual cost, never more than the amount set aside, and the rest is returned at once. When it fails, the whole amount is returned.

A request goes ahead when your balance is above zero and at most 0.01 USD short of the amount set aside. This small allowance lets a nearly used-up balance finish its last requests. It is shared by all of the account's requests at once, not granted to each one, so API usage can take your balance at most 0.01 USD below zero. The next credit added to your account pays off that negative part first.

If your balance is zero or negative, or is more than 0.01 USD short of the amount set aside, the request fails with `402 insufficient_balance` and is not sent to the model:

```json Error theme={null}
{
  "error": {
    "message": "Insufficient balance for this request. Add credits to continue.",
    "type": "billing_error",
    "code": "insufficient_balance",
    "required_usd": "0.000150",
    "available_usd": "0.000000",
    "topup_url": null
  }
}
```

API usage takes your balance at most 0.01 USD below zero, as described above. A refund, a dispute, or a negative adjustment made by our staff can take it further; see [Refunds and disputes](#refunds-and-disputes).

## Per-key spend limits

When you create a key in the console, you can give it a spend limit in USD with a reset period: daily, weekly, monthly, or no reset. Periods are calendar periods in UTC; weeks start on Monday. Use spend limits to cap what a leaked or runaway key can spend.

A request is refused with `402 key_limit_reached` when the key's charges in the current period, plus its requests still in flight, plus this request's amount set aside, would pass the limit. Your other keys keep working. With a reset period, the key works again at `resets_at`. With no reset, the limit covers the key's whole lifetime and `resets_at` is `null`. A key's limit cannot be changed after the key is created, so when a lifetime limit is reached, create a new key.

The key's spend limit is checked before your balance, so a key at its limit gets `key_limit_reached` even when the balance is also too low.

## Adding credit

Card top-ups in the console are not available yet. To add credit to your account, contact sales at [contact@torchcast.ai](mailto:contact@torchcast.ai) with the email address you use in the console. The console's **Billing** page shows the same note. Until top-ups open, the `topup_url` of a `402 insufficient_balance` is `null`. This page will be updated when top-ups open.

When top-ups open, you will add credit with **Add credits** on the console's **Billing** page and pay on a Stripe-hosted checkout page. You accept the Decision API terms before your first top-up and whenever they change. Sales tax or VAT, where it applies, is calculated and shown by Stripe at checkout and added on top of the amount you choose; your balance is credited with the pre-tax amount. The payment is sold and processed by Link (Sold through Link, LLC), Stripe's affiliate, as seller of record. Each top-up in your transactions links to its receipt where Stripe provides one.

## Transactions

The console's **Billing** page shows your balance, the amount that expires soonest and when, and every transaction: top-ups, refunds, disputes, adjustments and expired credit, each with its amount, the balance right after it, and, for credits, its expiry date. API charges are not listed there (see [Usage](#usage)), but the balance after each row already includes them.

## Refunds and disputes

A refund or dispute takes back the pre-tax part of what was paid. Your balance was credited with the pre-tax amount of a top-up, so a full refund removes exactly that amount, and a partial refund removes the same share of it, in whole cents. The tax part goes back with the payment and was never in your balance. Refunds and disputes on one payment normally take back no more than that payment's credited amount: a dispute on a payment that was already partly refunded holds only what the refunds left. The exception is an inquiry, the early stage of a dispute: a refund made while an inquiry is open is taken in full on top of the inquiry's hold, so for a while more than the credited amount is taken. When the inquiry closes in your favor, the hold comes back. If the inquiry is instead escalated to a dispute and lost, more stays taken than the payment credited; that raises an alert to our staff, who correct it.

* **Refund**: the amount is taken from that top-up's credit first, then from your other credits, the one expiring soonest first. If a refund fails or is canceled, the amount comes back to your balance, with the original top-up's expiry date.\*
* **Dispute**: when a dispute is opened, the pre-tax share of the disputed amount is held (up to what earlier refunds left): it is taken from your balance the same way as a refund. If the dispute is decided in your favor, the amount comes back, with the original top-up's expiry date,\* and shows as "Dispute reversed". If it is lost, the amount stays taken, unless the funds are later reinstated in your favor; then it comes back the same way.

\* If the amount comes back before the top-up itself has been credited to your balance, it gets a new one-year expiry instead.

If you already spent the credit a refund or dispute takes back, your balance can go below zero. While it is zero or negative, your account cannot pay for requests: they are refused with `402 insufficient_balance` (or `402 key_limit_reached` when the key is also at its spend limit, since that is checked first). The next credit added to your account pays off the negative part first.

## Credit expiry

Each credit expires one year after it is added to your balance. A credit that comes back after a won dispute or a failed refund keeps the original top-up's expiry date (with the rare exception noted under [Refunds and disputes](#refunds-and-disputes)). When you spend, the credit that expires soonest is used first. Credit still unused when it expires is removed from your balance and shows as an expiry in your transactions.

## Usage

The console's **Usage** page shows spend, tokens and requests per day, filterable by key, and exports per-request records as CSV. Each record has the request id, key, model, tokens, cost, latency and status, so you can match a charge to the `x-request-id` of a response. Requests refused before any amount is set aside from your balance (for example a `400` for an invalid field, a `401`, a `402` or a `429 rate_limited`) are not listed. Once an amount is set aside, the request is listed even if it then fails, with its status and a cost of zero: for example a `400` for an input over the model's [input-length limit](/limits#input-length), a `503` or a `504`. No failed request is charged.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.