Lifecycle and What You Pay
How a task moves from exploring to a fixed price, who pays for the model calls we make along the way, and how to see what you were actually charged.
The value you put in model names a task, not a specific LLM. We pick which model runs it. To pick well we have to measure, and measuring costs money — sometimes yours. This page explains when, and how to see it.
The authority for everything commercial here is the Pricing Terms and the Terms of Service . Where this page and those differ, those govern.
Two facts decide your bill
1. Who pays the provider. Every task declares one of two access modes, and it is readable on the task:
pricing_mode | Who pays the provider | What we charge |
|---|---|---|
byok | You do, directly — we call the provider with your vaulted key | the per-call fee only |
managed | We do, on our own credentials | the per-call fee, plus the model usage |
A task lazily created by your first request to an unrecognised model string defaults to byok. So does anything you create yourself unless you ask otherwise.
curl https://YOUR-HOST/api/inference/v1/management/capabilities/support-triage \
-H "Authorization: Bearer llmb_m_EXAMPLE_MANAGEMENT_KEY"
{
"slug": "support-triage",
"pricing_mode": "byok",
"lifecycle": "draft",
"maturity": {
"status": "exploring",
"mature_groups": 1,
"total_groups": 4,
"threshold_band": "MEDIUM",
"countdown_judged_calls": 62
}
}
2. Whether the task is still exploring. That is the rest of this page.
What exploration is
To route your calls to a good model we need evidence about how each candidate performs on your task — not on a public leaderboard. We get it by occasionally running more than one model for a request and having a judge model score the outputs.
Pricing Terms §1.2, verbatim on what that means for your invoice:
Some tasks run more than one model while we establish which performs best for that task — this is how the benchmark is produced. While a task is in that state, every model call in the chain appears on your invoice, per model. That includes calls whose output was not returned to you: alternatives, and the evaluation calls that compare them. It also includes calls that failed, and our own retries after a provider error.
Two consequences worth internalising before you size a budget:
- The chain is a fraction of the eligible set, not all of it. We pick alternatives by what would actually improve the comparison — favouring models we have least evidence about, weighing what each costs. Pricing Terms §3.2: “This is the same rule we apply when we are paying, and we do not widen it because you are.” And on a task you are paying the provider for — your own keys, or a managed task still exploring — a failure in the machinery that chooses alternatives means we serve your request with one model rather than falling back to running every model.
- Exploration’s share of your provider spend is much larger than its share of your call count. Terms §11 states this explicitly, because a figure quoted only as a percentage of calls would understate what you pay. Most calls are never evaluated; the ones that are, are expensive relative to a plain delivery.
The three charging modes
Pricing Terms §1.4 states a separate rule for each, because they differ on the thing people get wrong: what happens when something fails.
| Model usage | A request that failed | Retries, alternatives, evaluation calls | |
|---|---|---|---|
| Published rate (managed, matured) | our published rate | not billed — no token charge, no per-call fee | ours |
| Exploring (managed, not yet matured) | at cost (Pricing Terms §1.4) | model usage billed — the provider billed us for every call we made and it passes through; no per-call fee | on your invoice, plus the per-call fee |
Your own keys (byok) | your provider bills you directly | no fee from us; your provider bills you for every call | your provider bills you for all of them |
The middle row is the one to plan around. Concretely: every model call in the chain is priced at the provider’s published rate for the model, context tier and service tier that call used, and the failed attempts are in there too.
The bottom row has a matching asymmetry: our fee is charged once for a request that completed, but your provider charges for every model call we made behind it. Pricing Terms §3.2 spells out one request against an exploring task:
| your provider’s bill | our bill | |
|---|---|---|
| the model call we returned to you | charged | — |
| 4 alternative model calls | charged | — |
| 1 evaluation call comparing them | charged | — |
| the request itself | — | 1 call |
The per-call fee
One request you make is one call, however many model calls we make behind it. A batch of 10,000 lines is 10,000 calls; submitting it is not one more. Alternatives, judges and retries never add a call.
The card is identical on every plan, and the bands are marginal — crossing a threshold never raises the price of the calls below it:
| calls per month | fee |
|---|---|
| first 10,000 | included |
| 10,001 – 50,000 | $2.00 per 1,000 |
| 50,001 – 250,000 | $1.50 per 1,000 |
| 250,001+ | $1.00 per 1,000 |
Model usage on a managed task is billed on top of this: at the provider’s own rates while the task is still exploring, and at our published rate once it has matured. Under pass-through, input, output, cached input and cache-creation tokens are priced separately; so are context tier, service tier (batch is cheaper than synchronous) and, for one provider, time of day. Each appears on your invoice as its own line. See Pricing Terms §1.1.
The service is prepaid: you buy credit and usage draws it down. A 5.5% fee, minimum $0.80, applies to each credit purchase — charged on the purchase, never on your usage, which is what allows the no-markup rule to be true. Credit expires 12 months after purchase and the oldest is spent first. Automatic recharge exists, is off by default, and turning it on is how you authorise off-session charges. Full detail in Pricing Terms §2.
How a task matures
Maturity is evidence, not age or volume.
- Every model wired to the task carries a confidence band —
LOW,MEDIUM,HIGHorRANKED— derived from the judgments it has accumulated on that task. Two catalogue entries for the same underlying model (a free and a paid endpoint, say) share one band and count once. - A model counts as mature at
MEDIUM, or at the task’s confidence floor if that floor is higher. - The task is exploring while fewer than half its model groups are mature.
- For pricing there is one extra requirement: the task must have at least two model groups. A task with a single model can never leave pass-through billing, however good that one model’s band. That is the safe direction for a one-way decision.
The switch only goes one way. Once a task’s price is fixed, it stays fixed. We may keep exploring it afterwards — introducing a new model, re-checking for drift — and that exploration is ours to fund, not yours.
Your request’s mode is frozen when the request opens. A task that matures halfway through your call cannot re-rate a call already running.
Reading it off a response
A successful POST /v1/chat/completions normally carries these (also mirrored in a llmbench object in the response body, which OpenAI SDKs ignore):
| header | meaning |
|---|---|
x-llmbench-capability | the task that served it — may differ from the model you sent |
x-llmbench-model | the LLM that actually ran |
x-llmbench-provider | its provider |
x-llmbench-service-tier | standard, batch or cached |
x-llmbench-cost-usd | provider list cost of the delivered call, 8 decimal places |
x-llmbench-band | evidence band of the model that served |
x-llmbench-phase | explore, exploit or continuous |
x-llmbench-request-id | the route id — the join key for the chain |
x-llmbench-switch-in | judged calls still needed before this model’s band reaches its target, when that is estimable |
The first five are always present on a success. The last four are best-effort: absence means we could not resolve the value, never that the value is zero.
Two traps:
x-llmbench-cost-usd is the delivered call only. On an exploring request the alternatives and the judge are not in that number. It is a per-call figure, not your bill for the request. For the whole chain, use the route id.
x-llmbench-phase reports exploration behaviour, not price. A task with fan-out switched off always reports exploit regardless of how much evidence exists. The authoritative maturity read is maturity.status on GET /api/inference/v1/management/capabilities/{slug}, which is exploring or cost_optimised. maturity itself is best-effort and may be null — that means we could not compute it, and it should be read as unknown, never as matured.
x-llmbench-switch-in is omitted when it is zero and when it is not computable — absence means “no estimate”, never “no progress”. The task-level countdown is maturity.countdown_judged_calls on the capability read.
Seeing what you actually paid
The whole chain for one request
The route detail is a portal read: signed in to the dashboard, call GET /portal/api/v1/routes/{request_id} with a portal session token, passing the x-llmbench-request-id you got back on the response. There is no management-key equivalent on /api/inference/v1/.
It returns attempts (how many model calls the route made), route_cost_usd (the sum of provider list cost across every one of them), and attempts_detail — one entry per model call, oldest first, with its model, provider, service tier, status, tokens and cost, and which one was delivered.
That is the only view that shows an exploring request’s real shape. Both cost figures there are provider list price computed by us for reporting; see the note at the end of the next section.
Exploration separated from steady state
GET /api/inference/v1/usage (management key) groups your call records by capability, model, day and role, comma-separated for a compound key. role is the one you want:
| bucket | what it is |
|---|---|
delivered | the call whose output you received |
exploration | alternatives run alongside it |
judge | evaluation calls |
unattributed | calls not linked to a route — report these to us; they are a defect, not a category |
curl "https://YOUR-HOST/api/inference/v1/usage\
?from=2026-08-01&to=2026-08-24&group_by=capability,role" \
-H "Authorization: Bearer llmb_m_EXAMPLE_MANAGEMENT_KEY"
{
"rows": [
{"key": "support-triage|delivered", "key_parts": {"capability": "support-triage", "role": "delivered"},
"calls": 4120, "list_cost_usd": 6.4102, "input_tokens": 3121880, "output_tokens": 411204,
"cached_input_tokens": 0, "reasoning_tokens": 0, "actual_cost_usd": null},
{"key": "support-triage|exploration", "key_parts": {"capability": "support-triage", "role": "exploration"},
"calls": 212, "list_cost_usd": 3.8871, "input_tokens": 160644, "output_tokens": 39880,
"cached_input_tokens": 0, "reasoning_tokens": 0, "actual_cost_usd": null},
{"key": "support-triage|judge", "key_parts": {"capability": "support-triage", "role": "judge"},
"calls": 53, "list_cost_usd": 1.2044, "input_tokens": 88121, "output_tokens": 9902,
"cached_input_tokens": 0, "reasoning_tokens": 0, "actual_cost_usd": null}
],
"totals": {"calls": 4385, "list_cost_usd": 11.5017, "actual_cost_usd": null,
"input_tokens": 3370645, "output_tokens": 460986,
"cached_input_tokens": 0, "reasoning_tokens": 0}
}
Notice the shape of that illustration: exploration and judging are 6% of the calls and 44% of the spend. That is the asymmetry Terms §11 warns about, and it is why a percentage-of-calls figure alone would mislead.
from and to are required, the window is capped at 92 days, and actual_cost_usd is null for customer accounts by design.
list_cost_usd is not your invoice. It is the provider’s published list price for each call, computed by us for reporting. Pass-through billing is metered separately, from the raw provider token counts, priced when the call ran — so the two figures can differ. And under your own keys, what your provider actually charges you depends on your agreement with them.
Controlling exploration
The selection block inside extra_body.llmbench narrows a task’s routing policy for one call. Nothing is persisted; anything you omit is inherited.
client.chat.completions.create(
model="support-triage",
messages=[{"role": "user", "content": "..."}],
extra_body={"llmbench": {
"selection": {
"strategy": "relative",
"quality_threshold": 0.9
}
}},
)
quality_threshold requires strategy: "relative" — the other strategies (cost, speed, random) apply no score gate, so a threshold on them would mean nothing.
Whether alternatives run at all is yours to decide, for one request or for the task. Pricing Terms §3.2: “Exploration is a setting on the task, not something we impose: you can turn it off for a single request or for the task as a whole.”
For a single request, send the switch in the same selection block:
extra_body={"llmbench": {"selection": {"auto_live_fanout": False}}}
fan_out_strategy — bootstrap_then_organic, continuous or never — is accepted the same way.
To make it the default for a task, store the choice as a named selection policy and attach it:
curl -X POST https://YOUR-HOST/api/inference/v1/management/selection-policies \
-H "Authorization: Bearer llmb_m_EXAMPLE_MANAGEMENT_KEY" \
-d '{"slug": "no-explore", "strategy": "cost", "auto_live_fanout": false}'
curl -X PATCH https://YOUR-HOST/api/inference/v1/management/capabilities/support-triage \
-H "Authorization: Bearer llmb_m_EXAMPLE_MANAGEMENT_KEY" \
-d '{"selection_policy_slug": "no-explore"}'
Requests against that task then need send no selection block — the stored policy applies. With auto_live_fanout off, we do not run alternatives alongside the model we return. Pricing Terms §3.2 notes that even so, a retry after a provider error or a repair of malformed output can still add a model call.
Terms §11’s “We control this rate through policy; it is not something you configure per Call” is about how often a call is evaluated, not about this switch.
What a managed task will not let you set
A managed task publishes a price against a quality promise, so two fields are refused on it:
selection.min_confidence— moving the confidence floor shifts selection toward pricier, better-evidenced models at our expense.forced_model— the published price says we choose the model.
On /v1/chat/completions that refusal surfaces as HTTP 400 with code capability_config_invalid; the native invocation surface reports the more specific byok_only_field.
The fan-out switch is not among them: auto_live_fanout and fan_out_strategy are settable on either mode, per request or on a stored policy.
Two more, selection.quality_threshold and selection.model_group, are honoured while the task is still gathering evidence and go inert once its models are sufficiently evidenced — that is, once maturity.status reads cost_optimised. The request is served, the field is dropped, and you are told: the field name appears in x-llmbench-ignored-params. It is never an error. Your integration keeps working the day that happens; you did nothing, our evidence accumulated.
Note that this trigger is not the same test as the one that fixes your price. Fixing the price additionally requires at least two model groups, so on a single-model task these two fields can go inert while the task is still billed pass-through.
All four are freely usable on a byok task.
Task lifecycle: draft and active
Separately from maturity, a task carries a lifecycle of draft or active.
A task minted by your first call to an unrecognised model string starts as draft. It is immediately servable.
Promote it when you have decided to keep it:
curl -X POST \
https://YOUR-HOST/api/inference/v1/management/capabilities/support-triage/promote \
-H "Authorization: Bearer llmb_m_EXAMPLE_MANAGEMENT_KEY"
{"slug": "support-triage", "lifecycle": "active", "promoted_at": "2026-08-24T11:02:19+00:00"}
Promotion re-checks which models are wired to the task, so it picks up any provider you vaulted since the task was created. The slug, the account and the history are frozen. Promoting an already-active task returns 409.
Whether judgments on your task join the shared evidence pool is decided by Terms §8.1, not by promotion. A verdict pools only if all four of these hold when it is written: your account’s statistics scope is global (that is, free or shared_anon); the task exists and is active; the task maps to a confirmed canonical task; and the judging panel is your account’s ordinary production panel. Anything else, and the verdict stays in your account. Promotion does not create that confirmed mapping — we do. On private, verdicts aggregate only within your own account and never enter the pool.
Unknown model strings are not lazily created on the batch lane — a typo in a 10,000-line input file fails that line with model_not_found rather than minting 10,000 tasks.
What is never on your bill
- Our own benchmark work. We run comparisons of our own to produce the public benchmark. Those are paid for by us even when they sample one of your tasks, because their output is discarded and returns you nothing. They never run on your keys.
- Our internal traffic. We are a customer of our own API. That usage is billed to us, not spread across yours.
- Exploration after a task’s price is fixed. Once you are on a published rate, later alternatives and judges are ours.
Where to look when the number surprises you
| question | where |
|---|---|
| what did this request cost, end to end | GET /portal/api/v1/routes/{request_id} (portal session), keyed on x-llmbench-request-id |
| how much of last month was exploration | GET /api/inference/v1/usage?group_by=capability,role |
| is this task still exploring | GET /api/inference/v1/management/capabilities/{slug} → maturity.status |
| how much further to go | maturity.countdown_judged_calls, or x-llmbench-switch-in per model |
| which mode is this task in | same read → pricing_mode |
| what does it cost to make a call | Pricing Terms §1 and §3 |
Billing questions: llmbench@kapualabs.com