# Pricing & billing

You pay the provider's per-token price, published per model in USD per million tokens.
RouterPlus adds no per-token markup and no fee line.

Every billed response has `usage.cost`: the amount debited from your balance. You can recompute
it from the response.

One provider
is our own: RouterPlus, which runs its decision models on its own GPUs. These models cost $0
for input and output (see [Decision models](#decision-models)).

In the console, open Billing > Credits to buy credits and see your balance.

## Where prices live

The catalog is public and needs no key:

```bash
curl -s https://demo.routerplus.com/api/models.json \
  | jq '.models[] | select(.id == "claude-sonnet-4-5").pricing_usd_per_million'
```

```json
{
  "prompt": "3",
  "cached_prompt": "0.30",
  "cache_write": "3.75",
  "completion": "15"
}
```

Prices are **decimal strings** with up to six fractional digits, in USD per million tokens. They
convert without loss to the ledger's unit, so billing uses no floating-point rounding.

| SKU | What it bills | Example (`claude-sonnet-4-5`) |
|---|---|---|
| `prompt` | Non-cached input tokens | $3 / M |
| `cached_prompt` | Prompt-cache **reads** | $0.30 / M |
| `cache_write` | Prompt-cache **writes** | $3.75 / M |
| `completion` | Output tokens, including reasoning unless a distinct rate is declared | $15 / M |
| `internal_reasoning` | The reasoning part of output, when a provider declares a distinct rate | (none) |

> [!NOTE]
> A model that declares no cache or reasoning SKU bills those tokens at its base rate.
> `cached_prompt` and `cache_write` default to the `prompt` price. `internal_reasoning`
> defaults to the `completion` price. A missing price never means $0.

## Image models

Image models bill on the **same two SKUs**, in USD per million tokens: `prompt` for the text you
send, `completion` for the image that comes out. OpenAI reports image output in tokens, and the
size and quality you ask for set the count. The per-image ceiling is the most output tokens one
image can bill. It is `max_output_tokens` on the model page and in `/api/models.json`.

| Model id | Text in /1M | Image out /1M | Per-image ceiling |
|---|---|---|---|
| `gpt-image-1` | $5 | $40 | 6,240 tokens |
| `gpt-image-1-mini` | $2 | $8 | 6,500 tokens |
| `gpt-image-1.5` | $5 | $32 | 6,500 tokens |
| `gpt-image-2` | $5 | $30 | 8,232 tokens |
| `gpt-image-2.5-flare` | $5 | $30 | 8,232 tokens |
| `gpt-image-2.5-sunburst` | $5 | $30 | 8,232 tokens |

Every output token bills at the image rate. This includes the text output tokens that
`gpt-image-1.5` counts in its `output_tokens`. See [POST /v1/images/generations](/docs/api-images).

## Models billed at the provider's reported cost

Some image and video models are billed at the provider's listed price for the render or the job,
with no margin. RouterPlus reserves the model's ceiling (per image, or per second of video),
charges the cost the provider reports, and releases the rest. The prices and ceilings are on
[POST /v1/images/generations](/docs/api-images) and [Videos](/docs/api-videos).

## Decision models

Decision models answer typed questions on [POST /v1/decisions](/docs/api-decisions). They are
priced in USD per million tokens, like every other model.

| Model id | Input /1M | Cached /1M | Output /1M | What the token counts are |
|---|---|---|---|---|
| `typesafe/jev-1.13` | $0.042 | – | $0 | The provider's input count |
| `bespokelabs/nimble-v4` | $0.04 | – | $0 | The provider's input count |
| `bespokelabs/nimble-v4-max` | $0.09 | – | $0 | The provider's input count |
| `cloudflare/clef` | $0.24 | – | $0 | The provider's input count |
| `cloudflare/clef-flash` | $0.09 | – | $0 | The provider's input count |
| `routerplus/decider-2b` | $0 | $0 | $0 | The provider's input count; an answer from its cache bills $0 |
| `routerplus/kev-4b` | $0 | $0 | $0 | The provider's input count; an answer from its cache bills $0 |
| `perplexity/pplx-decider-v1-27b` | $0.04 | – | $0 | The provider's input count, which holds the state once per question |
| `openai/gpt-6-luna-decisions` | $0.10 | – | $0 | The provider's input count: the state once, and about 150 tokens for each question |
| `levanto/sage-1.2` | $0.05 | – | $0 | The provider's input count, which holds the state once per question |
| `scaledown/classify-1` | $0.05 | – | $0 | The provider's input count, summed over its questions (each one is a call) |
| `fastino/gliner-2.5-decide` | $0.03 | – | $0 | Fastino's `prompt_tokens` |

Output is free on every decision model. Each model is billed on its provider's input count at
the provider's price, with no markup, unless its section below says otherwise.

### Bespoke Nimble

- $0.04 per million input tokens for Nimble v4, $0.09 for Nimble v4 Max.
- Bespoke counts the state and the questions once per call.
- A three-question call of 178 input tokens costs $0.000007 on Nimble v4 and $0.000016 on
  Nimble v4 Max.
- `bespokelabs/nimble-latest` is in no list. It bills at $0.04 per million input tokens,
  Bespoke's price for `nimble-latest`, whichever model Bespoke picks for it.

### Clef and Clef-flash

- $0.24 and $0.09 per million input tokens. Cloudflare reports `output_tokens: 0`.
- Cloudflare bills Workers AI in neurons, at $0.011 per 1,000 neurons. Its price page lists Clef
  at 21,818 neurons ($0.24) and Clef-flash at 8,182 neurons ($0.09) per million input tokens.
- A call of 400 input tokens costs $0.000096 on Clef and $0.000036 on Clef-flash.

### Decider 2B and Kev 4B

Decider 2B and Kev 4B are RouterPlus's own models, on RouterPlus's own GPUs. RouterPlus
charges nothing for them.

- Input, cached input and output are free. `usage.cost` is `0` on every call.
- RouterPlus still reports its input count, which is at most the model's context. A long input
  that Decider 2B (25,600 tokens) cuts counts only the tokens the model read.
- A free call is still metered, counted against your limits and its pool, and recorded in
  `GET /v1/generation`. It still needs an organization with credit.
- RouterPlus answers an identical request from its cache for 600 s.

### Perplexity Decider v1 27B

- $0.04 per million input tokens.
- Perplexity runs one prompt for each question, and each prompt holds the whole state.
- Five questions about a state of 1,843 tokens bill 9,215 input tokens, $0.000368.
- One call with many questions still saves round trips.

### GPT-6 Luna Decisions

- $0.10 per million input tokens. OpenAI reports `output_tokens: 0`.
- It bills at its list price: no discount applies to it today.
- OpenAI bills the state once per call. It runs a prompt for each question, so each question
  adds about 150 input tokens. One yes/no about a two-character state billed 156 tokens, and
  five billed 760.
- A three-question call (a choice, a score and a yes/no about a short complaint)
  billed 396 input tokens, $0.000039.
- One call with many questions saves round trips and the state's tokens. The questions' tokens
  stay the same.
- A question that OpenAI declines (its answer is `{"type": "refusal"}`) is billed too.
- The listing's context is 272,000 tokens. Up to there, OpenAI's listed price holds. OpenAI
  bills input above it at twice the rate.

### GLiNER-2.5-Decide

- $0.03 per million input tokens.
- `usage.input_tokens` is Fastino's `prompt_tokens`. `usage.output_tokens` is its
  `completion_tokens`.
- A call of 1,000 input tokens costs $0.00003.

### Sage

- $0.05 per million input tokens.
- Sage reads and bills the state once per question, like Perplexity Decider.

### The decisions discount

A discount can apply to decision models: a percent off the charge of every decision model, or of
some of them, each at its own percent. It applies to every key, the Playground's included. It
does not change the list price, and it can change or end.

A discounted model's page and directory row show the percent beside the struck list price. Its
row in `/api/models.json` has `discount_percent`. Every discounted response says what applied:

| Where | What it shows |
|---|---|
| `usage.cost` | What you paid, after the discount |
| `usage.cost_before_discount` | The charge at the list price |
| `usage.discount_percent` and the `x-tm-discount-percent` header | The percent taken off |
| `cost_usd` in [GET /v1/generation](/docs/api-usage) | What you paid, after the discount |
| `inference_cost_usd` in GET /v1/generation | The cost at the list price |

- The discounted charge is the list charge × (100 − percent) / 100, rounded down to the
  micro-dollar.
- With no discount, the three discount fields are absent and `usage.cost` is the list charge.
- A discount needs an organization with credit. With a balance of $0, a discounted request gets
  `429 insufficient_quota`, as any request does, even at 100 %.

A discount can cover a model whose list price is already $0 (Decider 2B and Kev 4B today). Then
the discount has nothing to take off: `usage.cost` and `usage.cost_before_discount` are both
`0`. The gateway still reports `usage.discount_percent` and the header, and `/api/models.json`
still carries `discount_percent` on its row, so one reader works for all
twelve models. The model's page, the directory and the Playground show no "N % off" beside a $0
price, because the model is free, not discounted.

## The math: integer micro-USD

All money math is in integer micro-USD (millionths of a dollar). A published price of `"2.50"`
becomes `2500000` micro-USD per million tokens. Two rounding rules apply:

- **Reserve rounds up** (ceiling), so the hold is conservative.
- **Settlement rounds down** (floor).

The settlement formula:

```
non_cached_input = max(0, input_tokens − cached_tokens − cache_write_tokens)
reasoning        = clamp(reasoning_tokens, 0, output_tokens)
plain_output     = output_tokens − reasoning

cost_micro = floor((
    non_cached_input   × prompt_per_M
  + cached_tokens      × cached_prompt_per_M
  + cache_write_tokens × cache_write_per_M
  + plain_output       × completion_per_M
  + reasoning          × reasoning_per_M
) / 1,000,000)
```

Each `*_per_M` is the integer micro-USD price. `usage.cost` is this number divided by 10⁶.

## Reserve, then settle

Every billed request has four steps:

1. **Reserve.** Before RouterPlus contacts a provider, the gateway holds an estimate of the
   highest cost.
   - **Input (chat surfaces):** one token per byte of the request body, plus 65,536 tokens for
     each image or document part. An image sent inline counts the 65,536 only, not its base64
     bytes.
   - **Output:** all of your `max_tokens` (or `max_completion_tokens`, or `max_output_tokens`
     on [POST /v1/responses](/docs/api-responses)).
   - **No output limit:** the hold covers at most 32,768 output tokens, and the model gets its
     own maximum. On the chat surfaces, the gateway writes that maximum into the request,
     lowered when needed so that the input and output fit the model's context window (see
     [POST /v1/chat/completions](/docs/api-chat-completions)). On `/v1/responses` the gateway
     adds none, and OpenAI applies the same maximum.
   - **Rate:** each side is priced at the model's highest rate for that side (cache writes and
     reasoning, when they cost more than plain input or output). The sum rounds **up** to
     micro-USD.
   - **Web search:** a request with a web search tool also holds the search fee for the tool's
     `max_uses` searches (at most 20), or for 5 when it sets none (see [Web search](#web-search)).
   - **Images:** on `/v1/images/generations`, the output is reserved at `n` × the model's
     per-image ceiling (not `max_tokens`), and the input at the prompt bytes ÷ 4.
2. **Dispatch.** The request goes to a provider. Prices are pinned at this moment (see
   [Price changes](#price-changes-frozen-snapshots)).
3. **Settle.** When the attempt finishes, RouterPlus prices the provider-reported token counts
   with the formula above and rounds **down**. You pay that amount, also when it is more than the
   hold (a long answer to a request without a limit).
4. **Release.** RouterPlus releases the hold in full.

### When usage is not reported

An attempt can end before the provider reports usage: you cancelled it, or the provider failed
after your answer started. You then pay for the input and for the output already streamed to
you. RouterPlus does not charge the hold.

- **Input:** the provider's own count when it sent one. Claude sends it when its answer starts,
  with its cache reads and writes, each at its own price. Otherwise, the request's likely input
  (its size at four bytes a token, with 1,600 tokens for each image or document part) at the
  plain input price.
- **Output:** what was streamed to you before the end (text, tool-call arguments and any
  reasoning you received), at four characters a token. If you cancel before the first token, or
  the call does not stream, the output part is $0.

A model that hides its thinking (the Claude 5 models, by default) streams nothing while it
thinks. A cancel during that time costs the input only. Such a charge has the provenance
`estimated`.

You pay the reserved maximum in two cases:

- The gateway stopped mid-request and cannot observe the outcome (`unknown_after_crash` in
  [GET /v1/usage & /v1/generation](/docs/api-usage)), because the provider may have billed the
  call.
- An attempt completes and the provider reports no usage. This is rare.

### Refusals before dispatch

| Cause | Refusal |
|---|---|
| **Balance too low.** Your balance must cover every reservation your org has in flight, this one included. | `429` with `error_type: insufficient_quota` (the OpenAI shape SDKs handle; native type `billing_error` on the Anthropic surface) |
| **Monthly spend cap hit.** Caps are org-wide and per key, per UTC calendar month. The strictest wins. | The same `429 insufficient_quota`, with the reset time in the message and in the `x-tm-cap-reset` header |
| **A rate limit hit.** The key's RPM, a shared limit of the organization, or the provider's pool. | `429` with `error_type: rate_limit` and `retry-after` |

[Errors & remediation](/docs/errors) gives the fix for each.

### Failed images cost nothing

A failed attempt, a response over the 32 MiB cap, and a 200 with no decodable image all settle
at zero. RouterPlus never returns or bills a partial image.

If you hang up mid-render, the render still finishes upstream. That attempt settles the
**provider-reported** usage: never the reservation, and never $0.

## The cost on the wire: `usage.cost`

Every billed response has `usage.cost` (USD, a JSON number):

- **Non-streaming:** in the response body's `usage`, on both surfaces.
- **Streaming, OpenAI surface:** in the final usage chunk, before `[DONE]`.
- **Streaming, Anthropic surface:** in the `message_delta` usage at stream end.

```bash
curl -s https://demo-api.routerplus.com/v1/chat/completions \
  -H "Authorization: Bearer $TM_API_KEY" -H "content-type: application/json" \
  -d '{"model":"claude-sonnet-4-5","max_tokens":350,"messages":[{"role":"user","content":"hello"}]}' \
  | jq .usage
```

```json
{
  "prompt_tokens": 1200,
  "completion_tokens": 350,
  "total_tokens": 1550,
  "prompt_tokens_details": { "cached_tokens": 800, "cache_write_tokens": 0 },
  "cost": 0.00669
}
```

```python
import os
from openai import OpenAI

client = OpenAI(base_url="https://demo-api.routerplus.com/v1", api_key=os.environ["TM_API_KEY"])
r = client.chat.completions.create(
    model="claude-sonnet-4-5", max_tokens=350,
    messages=[{"role": "user", "content": "hello"}],
)
print(r.usage.model_dump()["cost"])  # the ledger debit, in USD
```

```python
import os
import anthropic

client = anthropic.Anthropic(base_url="https://demo-api.routerplus.com", api_key=os.environ["TM_API_KEY"])
msg = client.messages.create(
    model="claude-sonnet-4-5", max_tokens=350,
    messages=[{"role": "user", "content": "hello"}],
)
print(msg.usage.model_dump()["cost"])
```

> [!WARNING]
> `usage.cost` is the **full request debit**, not the serving attempt's share. If a
> provider failed mid-prompt and the gateway failed over before your answer started,
> the number includes the tokens the failed attempt used. The per-attempt breakdown is
> at [GET /v1/generation](/docs/api-usage).

Usage reporting is always on:

- Streams and non-streams both carry usage.
- The gateway requests usage from the provider whatever you send, because RouterPlus cannot
  recompute unreported usage.
- Only an explicit `stream_options.include_usage: false` changes anything. You are billed the
  same, but no usage chunk is written to you.

On the Anthropic surface, a **stream that fails after your answer started** has no place for
usage outside `message_delta`. Its terminal error event carries no cost. Read those costs from
[/v1/generation](/docs/api-usage). The OpenAI surface sends any known usage and cost before its
terminal error.

## Cache reads and writes

Cache tokens bill at their own rates on **both** surfaces. Both surfaces report the split:

| Concept | OpenAI surface | Anthropic surface | Billed at |
|---|---|---|---|
| Non-cached input | `prompt_tokens` minus the two details below | `input_tokens` | `prompt` |
| Cache reads | `prompt_tokens_details.cached_tokens` | `cache_read_input_tokens` | `cached_prompt` |
| Cache writes | `prompt_tokens_details.cache_write_tokens` | `cache_creation_input_tokens` | `cache_write` |
| Output | `completion_tokens` | `output_tokens` | `completion` |

On the OpenAI surface, `prompt_tokens` includes cache reads and writes. Billed responses always
have `prompt_tokens_details` with both fields, set to zero when the provider reports none. Stream
and non-stream usage have the same shape.

On Claude, a cache write costs 1.25 times the input price (`cache_write`). A cache read costs a
tenth of it or less (`cached_prompt`).

When an agent sends a conversation with tools or earlier turns and no cache marks of its own,
the gateway turns on Claude's automatic caching for it. The first turn pays a cache write on its
prompt. The next turns read that prompt at the cache price.

- The `x-tm-auto-cache` response header says whether automatic caching applied.
- The request header `x-tm-auto-cache: off` turns it off.
- [Wire compatibility](/docs/compat#automatic-caching-on-claude) has the rules.

## Web search

RouterPlus bills a web search that the provider runs for the model at the provider's price per
search, plus the tokens:

| Tool | Where | Price |
|---|---|---|
| Anthropic's web search server tool (`web_search_20250305` and later) | Claude models on `POST /v1/messages` | **$10 per 1,000 searches** ($0.01 a search) |
| Anthropic's web fetch server tool | Claude models on `POST /v1/messages` | No fee: only the tokens of the fetched page |
| OpenAI's hosted `web_search` tool | OpenAI models on [POST /v1/responses](/docs/api-responses) | $10 per 1,000 calls |
| OpenAI's older `web_search_preview` tool | GPT-4o, GPT-4o mini and GPT-4.1 mini on `POST /v1/responses` | $25 per 1,000 calls |

- Each search counts once, whatever the number of results. A failed search is not billed.
- The pages a search returns become input tokens at the model's input price, as on the
  provider's own API. On a stream, the input is the count at the end of the turn.
- The fee is part of `usage.cost`, and of `cost_usd` in
  [GET /v1/usage & /v1/generation](/docs/api-usage). There, each attempt also shows
  `server_tool_use` (`web_search_requests`, `web_fetch_requests`) and `server_tool_fee_usd`. On
  `/v1/messages`, the answer's `usage.server_tool_use.web_search_requests` also gives the number
  of searches.
- While the request runs, the hold includes the fee for each web search tool's `max_uses`
  searches (at most 20), or for 5 searches when the tool sets no `max_uses`. A tool of your own
  named `web_search` holds nothing.
- If the model searches more often than the hold allows, you pay for every search it made. The
  hold limits what is set aside, and the charge has no such limit.
- On your own provider connection (BYOK), RouterPlus charges no fee. The provider bills you.

Anthropic's server tools, web search included, work only for Claude models on
`POST /v1/messages`. Claude Code calls them there. See [POST /v1/messages](/docs/api-messages).

## Reasoning tokens

Reasoning tokens are **part of output**. They are never billed on top of it.

- The settlement math splits them out and prices them at the model's reasoning rate.
- Today every cataloged model prices reasoning equal to `completion`, so the split changes
  nothing until a provider declares a distinct rate.
- The OpenAI surface reports them in `completion_tokens_details.reasoning_tokens`. The Anthropic
  surface does not report them separately.

## Price changes: frozen snapshots

You pay the price in effect at **dispatch time**.

- Price rows are append-only. A change is a new effective-dated row, never an edit.
- The row in effect when your request is reserved is pinned into the reservation and written
  onto every attempt's ledger row.
- A price change published while your request is in flight does not affect it.
- Past attempts always settle, and audit, against the prices they were dispatched under.

## Paid credits and purchase matching

Create an account at [Sign up](https://demo.routerplus.com/signup), complete Clerk authentication and email
verification, and save your first API key. Signup and card verification alone do not grant
credit. Existing customers keep their balance and API keys.

Standard credit purchases start at **$10** in [Billing](https://demo.routerplus.com/console/billing). The
payment adds the amount you buy as paid credit. Your balance is the sum of credit ledger entries
minus settled spend.

If purchase matching is offered for your account, Billing shows the cap and remaining matching credit.

Only eligible paid purchases receive a match, when the offer is available in Billing.

- New matching offers have a lifetime maximum of **$100 per account** across eligible
  purchases. Billing shows the offer and the matching credit left for your account.
- Matching credit is promotional and shows as its own ledger entry.
- Refunds and chargebacks reverse the matching credit. A partial refund reverses its
  proportional matching credit.
- Adding a card without a purchase does not earn a bonus.
- Existing trial and card-verification grants stay in the ledger. Those signup offers are no
  longer available.

Before an organization buys credit, its customer keys share the trial rate of 20 requests a
minute. A purchase lifts that cap. Each key then has its own ceiling (300 for a console key).
RouterPlus can also limit past trial credit when it detects unusual usage. Contact support if
that happens. See [Rate limits & spend caps](/docs/limits).

## Worked example

A `claude-sonnet-4-5` request reports 1,200 prompt tokens (800 of them cache reads, no cache
writes) and 350 completion tokens:

```
non-cached input:   400 × 3,000,000  = 1,200,000,000
cache reads:        800 ×   300,000  =   240,000,000
output:             350 × 15,000,000 = 5,250,000,000
                                       ─────────────
sum / 1,000,000 (floor)              = 6,690 micro-USD
```

`usage.cost` in the response is `0.00669`. The attempt's `cost_usd` in
[GET /v1/usage & /v1/generation](/docs/api-usage) is the same number, from the same computation.

## Worked example: an image

A `gpt-image-1` request for two medium 1024×1024 images (`n: 2`) with a 12-token prompt
estimate. Text in is $5 / M, image out is $40 / M, and the per-image ceiling is 6,240 tokens.

The reservation, before RouterPlus contacts a provider:

```
prompt estimate:  12 ×  5,000,000 =         60,000,000
output ceiling:   2 × 6,240 × 40,000,000 = 499,200,000,000
                                           ───────────────
ceil(sum / 1,000,000)                    = 499,260 micro-USD
```

The provider reports 12 input tokens and 2,112 output tokens (1,056 per image). Settlement:

```
input:            12 ×  5,000,000 =         60,000,000
output:        2,112 × 40,000,000 =     84,480,000,000
                                        ──────────────
floor(sum / 1,000,000)            =     84,540 micro-USD
```

`usage.cost` in the response is `0.08454`. RouterPlus releases the hold in full, and you pay the
settled amount.
