API reference
Authentication
Every request carries an API key as a Bearer token. Anthropic clients may send it as x-api-key instead, because that is what their SDKs do.
header
Authorization: Bearer llm11_live_...Keys prefixed llm11_sandbox_ behave identically and hit real models, so their receipts are real. They are flagged as sandbox on every request, which is what lets you keep test traffic out of the figures you report.
POST /v1/chat/completions
OpenAI-compatible. Accepts messages, temperature, max_tokens and response_format, plus three additions.
request
{
"messages": [{ "role": "user", "content": "…" }],
"context": "optional source text the groundedness check holds claims against",
"model": "llm11-balanced",
"llm11_models": ["openai/gpt-5.6-luna", "anthropic/claude-opus-5"],
"response_format": { "type": "json_object" }
}model is a routing pack (llm11-fast, llm11-balanced, llm11-smart, or llm11-auto for the project default), or a specific catalogue model id, which pins the request with no routing at all. llm11_models is an explicit candidate pool that overrides both model and the project default; an id it does not recognise returns a 400 rather than silently dropping it. Sending response_format as json_object also turns the schema check from a shape test into a parse test, so malformed JSON escalates rather than reaching your parser.
POST /v1/messages
Anthropic Messages-compatible. Same engine, same receipt, translated at the edges. Point an Anthropic SDK at this origin and it works unmodified.
The receipt
Returned as _llm11 in the response body, with the headline figures mirrored into headers.
| Field | Meaning |
|---|---|
| verdict | pass, escalated or failed. |
| modelUsed | The model that produced the answer you received. |
| baselineModel | The most expensive model in the offered pool, used as the savings denominator. |
| candidatePool | Every model id triage was actually offered for this request. |
| poolSource | request_list, request_pack, project, pinned or fallback: where the pool came from. |
| taskType | What triage decided this request was. |
| criticality | low, normal or high, after blending your policy floor with the triage call. |
| triageBackend | jev or heuristic. Named on every request rather than assumed. |
| triageConfidence | Calibrated where the backend is Jev, a coarse estimate otherwise. |
| rungsRun | Each check that ran, whether it passed, and its confidence where it has one. |
| escalated | Whether a failed check sent the request to the pool's strongest remaining model. |
| escalationReason | Which check failed, in words. |
| costCents | Generating the answer: the primary call plus any escalation. |
| verificationCostCents | Checking the answer. Never overlaps costCents. |
| triageCostCents | The routing decision itself. Real for Jev, genuinely 0 on the heuristic backend. |
| triageCostEstimated | True when triageCostCents is estimated from token count rather than reported. |
| totalCostCents | The three above, summed. What this request debited. |
| baselineCostCents | The same tokens priced on baselineModel, or null if it could not be priced. |
| savingsCents | baselineCostCents minus totalCostCents, or null if the baseline was null. |
| cacheLossCents | Always null today. Provider cache telemetry is not collected yet, and we will not estimate it. |
| latencyMs | End to end, including every check. |
| triageLatencyMs | The triage call alone. |
costCents, verificationCostCents and triageCostCents are disjoint and sum to totalCostCents, which is what the request debits. Anything we could not compute comes back null, never zero, so a missing number is never mistaken for a good one.
response headers
x-llm11-request-id: 7c2f…
x-llm11-model: openai/gpt-5.6-luna
x-llm11-verdict: pass
x-llm11-escalated: false
x-llm11-cost-cents: 0.0041
x-llm11-baseline-cost-cents: 0.0462
x-llm11-savings-cents: 0.0412Errors
Structured, with a stable type you can branch on.
error
{ "error": { "message": "…", "type": "insufficient_credits" } }| 401 | invalid_request_error | Missing, malformed or revoked API key. |
| 400 | invalid_request_error | Body was not JSON, or messages was absent or empty. |
| 400 | invalid_pool | model or llm11_models named a pack or id that does not exist in the live catalogue. |
| 402 | insufficient_credits | Prepaid balance is zero. Top up to continue. |
| 429 | rate_limited | Too many demo requests from one address. Applies to the public homepage demo only. |
| 501 | not_implemented | Streaming was requested and is not built yet. |
| 502 | upstream_error | The model provider failed. The message carries their reason. |
Limits, stated plainly
There is no volume cap and no feature tier. Every request, every model, every check and every triage call runs at provider list price out of your prepaid balance, whatever that balance is. At zero, requests stop with a 402 rather than running the balance negative or quietly turning into a surprise invoice.
Streaming is not implemented. stream: true returns a 501 rather than a non-streaming response dressed up as one. Verification needs a finished answer, so streaming needs a design that holds the stream until the checks clear, and shipping it half-done would mean either lying about the format or streaming unverified tokens.
Machine-readable
- /api/v1/openapi.json for the full schema.
- /llms.txt for a summary written for an assistant to read.
- /pricing.json for the credit packs and purchase fee as data.