Console
Core concepts/Pricing & billing

Pricing & billing

Pass-through prices, usage.cost on the wire, the billing math.

/llms.txt

Pricing is pass-through: the per-token price you pay is the provider's price, published per model in USD per million tokens. There is no per-token markup and no hidden fee line. Every billed response carries usage.cost — the exact amount your balance was debited, computed with the same integer math the ledger settles with — so you can recompute your bill from the wire at any time. One provider is our own: RouterPlus, which serves our own decision models on our own GPUs. Its models are free: $0 in and out (see Decision models).

Where prices live

The machine-readable catalog is public, no key required:

bash
curl -s https://app.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 (up to six fractional digits), USD per one million tokens. They convert exactly to the ledger's internal unit — no float rounding is involved anywhere in billing.

SKUWhat it billsExample (claude-sonnet-4-5)
promptnon-cached input tokens$3 / M
cached_promptprompt-cache reads$0.30 / M
cache_writeprompt-cache writes$3.75 / M
completionoutput tokens (including reasoning, unless a distinct rate is declared)$15 / M
internal_reasoningreasoning subset of output, when a provider declares a distinct rate—
Note

A model that does not declare a 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 free — that would be an accidental $0 SKU, and the ledger refuses to guess.

Image models

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

Model idText in /1MImage out /1MPer-image ceiling
gpt-image-1$5$406,240 tokens
gpt-image-1-mini$2$86,500 tokens
gpt-image-1.5$5$326,500 tokens
gpt-image-2$5$308,232 tokens
gpt-image-2.5-flare$5$308,232 tokens
gpt-image-2.5-sunburst$5$308,232 tokens

Every output token bills at the image rate, including the text output tokens gpt-image-1.5 folds into its output_tokens. The full route contract is POST /v1/images/generations.

Decision models

Decision models answer typed questions on POST /v1/decisions. They are priced like everything else: USD per million tokens.

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

Bespoke's Nimble models are billed on Bespoke's own input count at Bespoke's own prices, with no markup: $0.04 per million input tokens for Nimble v4, $0.09 for Nimble v4 Max, and output is free. Bespoke counts the state and the questions once per call, not once per question. A three-question call of 178 input tokens costs $0.000007 on Nimble v4 and $0.000016 on Nimble v4 Max. bespokelabs/nimble-latest, which no list shows, is billed at $0.04 per million input tokens, Bespoke's price for nimble-latest, whichever model Bespoke picks for it.

Clef and Clef-flash are billed on Cloudflare's own input count at Cloudflare's own price, with no markup: $0.24 and $0.09 per million input tokens, and output is free (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 are RouterPlus's own models, on our own GPUs, not an outside provider's. So their price is ours to set, not a provider's price passed through, and it is $0: input, cached input and output are all free, and 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, and it still needs an organization with credit. RouterPlus answers an identical request from its cache for 600 s.

Perplexity Decider v1 27B is billed on Perplexity's own input count at Perplexity's own price, with no markup: $0.04 per million input tokens, and output is free. Unlike Bespoke, Perplexity runs one prompt for each question, each with the whole state, and counts the state once per question. So a call costs about one state for each question it asks: 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 is billed on OpenAI's own input count at OpenAI's own price, with no markup: $0.10 per million input tokens, and output is free (OpenAI reports output_tokens: 0). It is billed at its list price: no discount applies to it today. OpenAI bills the state once per call, but 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. So one call with many questions saves round trips and the state's tokens, but not the questions' tokens. 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, and OpenAI bills input above it at twice the rate.

GLiNER-2.5-Decide is billed on Fastino's own input count: $0.03 per million input tokens, and output is free. usage.input_tokens is Fastino's prompt_tokens, and usage.output_tokens its completion_tokens. A call of 1,000 input tokens costs $0.00003.

Sage is billed on Levanto's own input count at Levanto's own price, with no markup: $0.05 per million input tokens, and output is free. Like Perplexity Decider, it reads and bills the state once per question, so a call costs about one state for each question it asks.

The decisions discount

A discount may apply to decision models: a percent taken off the charge of every decision model, or of some of them, each at its own percent, from 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 its row in the directory show the percent beside the struck list price, and its row in /api/models.json carries discount_percent. Every discounted response says what applied:

WhereWhat it shows
usage.costWhat you paid, after the discount
usage.cost_before_discountThe charge at the list price
usage.discount_percent and the x-tm-discount-percent headerThe percent taken off
cost_usd in GET /v1/generationWhat you paid, after the discount
inference_cost_usd in GET /v1/generationThe cost at the list price

The discounted charge is the list charge × (100 − percent) / 100, rounded down to the micro-dollar. When no discount applies, the three discount fields are absent and usage.cost is the list charge. A discount is a lower charge, not a markup: pricing stays pass-through. A discount is for organizations with credit: with a balance of $0 a discounted request is refused with 429 insufficient_quota, as any request is, even at 100 %.

When a discount covers a model whose list price is already $0 (Decider 2B and Kev 4B today), 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 on it, as on every model the discount covers, 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: the model is free, not discounted.

The math: integer micro-USD

All money math is integer micro-USD (millionths of a dollar). A published price like "2.50" becomes exactly 2500000 micro-USD per million tokens. Two rounding rules, both fixed:

  • Reserve rounds up (ceiling) — the pre-flight hold is conservative.
  • Settlement rounds down (floor) — the actual charge, in your favor.

The settlement formula, verbatim from the ledger:

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)

where each *_per_M is the integer micro-USD price. usage.cost on the wire is this number divided by 10⁶.

Reserve, then settle

Every billed request runs the same lifecycle:

  1. 01

    Reserve. Before any provider is contacted, the gateway holds a conservative estimate of the cost. On the chat surfaces the input is estimated at 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), and the output at your max_tokens (or max_completion_tokens, or max_output_tokens on POST /v1/responses), all of it. When you send no output limit, the output is held at 32,768 tokens at most, although 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 the output fit the model's context window (see POST /v1/chat/completions); on /v1/responses it adds none, and OpenAI applies the same maximum. Each side is priced at the model's most expensive rate for that side — cache writes and reasoning when they cost more than plain input or output — and the sum is rounded up to micro-USD. 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). 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. 02

    Dispatch. The request goes to a provider. Prices are pinned at this moment (see frozen snapshots).

  3. 03

    Settle. When the attempt finishes, the provider-reported token counts are priced with the formula above, rounded down. That is what you pay, also when it is more than the hold (a long answer to a request without a limit).

  4. 04

    Release. The hold is released in full, and you pay the settled amount. An attempt can end before the provider reports its usage: you cancelled it, or the provider failed after your answer started. Then you pay for the input and for the output already streamed to you, never 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, so a cancel during that time costs the input only. Such a charge has the provenance estimated. You are charged the reserved maximum only when the gateway itself stopped mid-request and cannot observe the outcome (unknown_after_crash in GET /v1/usage & /v1/generation), because the call may have been billed upstream, and in the rare case of an attempt that completes without the provider reporting any usage.

A reservation can be refused before dispatch:

  • Balance too low — your balance must cover every reservation your org has in flight, including this one. Refusal is a 429 with error_type: insufficient_quota (the OpenAI-native shape SDKs already handle; billing_error native type on the Anthropic surface).
  • Monthly spend cap hit — hard caps (org-wide and per-key, UTC calendar month, strictest wins) return the same 429 insufficient_quota with the exact reset time in the message and 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.

Remediation for each is in Errors & remediation.

All-or-nothing on images

An image generation either arrives whole or costs nothing. A failed attempt, a response over the 32 MiB cap, and a 200 that carries no decodable image all settle at zero — there is no partial image and no partial bill. The one nuance: if you hang up mid-render the render still finishes upstream, so that attempt settles the provider-reported usage, never the reservation and never a pretend $0.

The cost on the wire: usage.cost

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

  • Non-streaming — inline in the response body's usage, 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://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://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 exact ledger debit, in USD
python
import os
import anthropic

client = anthropic.Anthropic(base_url="https://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 slice. If a provider failed mid-prompt and the gateway failed over before your answer started, any tokens the failed attempt consumed are included in the number you see. The per-attempt breakdown is always available at GET /v1/generation — nothing is hidden in an average.

One documented limitation: an Anthropic-surface stream that dies after your answer started has no legal wire slot for usage outside message_delta, so its terminal error event carries no cost. Recompute those from /v1/generation. (The OpenAI surface emits any known usage+cost before its terminal error, so its wire stays complete.)

Usage reporting is always on: streams and non-streams both carry it, and the gateway requests usage upstream regardless of what you send, because unreported usage would be an unrecomputable bill. The one stream_options value that changes anything is an explicit include_usage: false: you are billed the same, but no usage chunk is written to you.

Cache reads and writes

Cache tokens are billed at their own rates on both surfaces, and both surfaces report the split:

ConceptOpenAI surfaceAnthropic surfaceBilled at
Non-cached inputprompt_tokens minus the two details belowinput_tokensprompt
Cache readsprompt_tokens_details.cached_tokenscache_read_input_tokenscached_prompt
Cache writesprompt_tokens_details.cache_write_tokenscache_creation_input_tokenscache_write
Outputcompletion_tokensoutput_tokenscompletion

On the OpenAI surface prompt_tokens is cache-inclusive (reads and writes are inside it), and billed responses always carry prompt_tokens_details with both fields — zero-filled when the upstream reports none — so stream and non-stream usage share one recomputable shape.

On Claude, a cache write costs 1.25 times the input price (cache_write), and 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 then pays a cache write on its prompt, and the next turns read that prompt at the cache price. The x-tm-auto-cache response header says whether it was applied, and the request header x-tm-auto-cache: off turns it off. The rules are on Wire compatibility.

A web search that the provider runs for the model is billed at the provider's price per search, in addition to the tokens:

ToolWherePrice
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 toolClaude models on POST /v1/messagesno fee: only the tokens of the fetched page
OpenAI's hosted web_search toolOpenAI models on POST /v1/responses$10 per 1,000 calls
OpenAI's older web_search_preview toolGPT-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, and a search that fails is not billed. The pages a search returns become input tokens, billed at the model's input price, as on the provider's own API; on a stream, too, 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, where each attempt also shows server_tool_use (web_search_requests, web_fetch_requests) and server_tool_fee_usd. On /v1/messages the number of searches is in the answer's usage.server_tool_use.web_search_requests too.
  • 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 that happens to be named web_search holds nothing. If the model searches more often than the hold allows, you pay for every search it made: the hold bounds what is set aside, never the charge.
  • On your own provider connection (BYOK) there is no fee from us: the provider bills you directly.

Anthropic's server tools, web search included, work only for Claude models on POST /v1/messages (Claude Code calls it there). See POST /v1/messages.

Reasoning tokens

Reasoning tokens are a subset of output, never billed on top of it. The settle 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 is billing-neutral until a provider declares a distinct rate. The OpenAI surface reports them in completion_tokens_details.reasoning_tokens; the Anthropic wire does not report them separately.

Price changes: frozen snapshots

The price you pay is the price at dispatch time. Price rows are append-only — a change is a new effective-dated row, never an edit — and 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 cannot touch it, and historical attempts always settle (and audit) against the prices they were dispatched under.

Create an account at Sign up, 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. The payment adds the amount you buy as paid credit. Your balance is the sum of credit ledger entries minus settled spend.

We match your first $100 in credit purchases, dollar for dollar. The offer applies to eligible accounts; Billing shows your remaining match.

With the full match available: $10 purchase → $20 credits. $100 purchase → $200 credits. A partially used cap adds only the matching credit remaining.

The cap applies across eligible purchases, not afresh to each checkout. Billing shows the offer and remaining matching credit for your account. Matching credit is promotional and appears separately in the ledger. Refunds and chargebacks reverse the corresponding match; 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, but those signup offers are no longer available.

Before an organization buys credit, its customer keys share the trial rate of 20 requests/minute. A purchase lifts that cap; each key then has its own ceiling (300 for a console key). Historical trial credit can also be limited when unusual usage is detected; contact support if that happens.

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 on the wire: 0.00669. The same number appears as the attempt's cost_usd in GET /v1/usage & /v1/generation, because they are the same computation on the same integers.

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 any provider is contacted:

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), so settlement is:

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 on the wire: 0.08454. The hold is released in full; you pay the settled number, not the reservation.

Markdown source for agents: /docs/pricing.md · index at /llms.txt