Quickstart
Step 1
Create a key
Sign up and create a key from /app/keys. Start with a sandbox key: it runs the full pipeline against real models so the receipts are real, and it is clearly marked as sandbox on every request so you can filter it out later.
Step 2
Point your client at us
Two lines change in a typical OpenAI setup, and one of them is the key.
curl
curl https://www.llm11.com/v1/chat/completions \
-H "Authorization: Bearer $LLM11_KEY" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "Summarise this in one sentence."}
]
}'Using an Anthropic SDK instead, point it at https://www.llm11.com/v1/messages. Same key, same behaviour, the wire format you already speak.
Step 3
Pass context, and the groundedness check turns on
context is the one addition to the OpenAI shape. Put whatever your app already retrieved into it, and every factual claim in the answer gets held against it. Leave it out and that check does not run. Nothing else about the request changes either way.
curl
curl https://www.llm11.com/v1/chat/completions \
-H "Authorization: Bearer $LLM11_KEY" \
-H "Content-Type: application/json" \
-d '{
"context": "Refunds are issued within 5 business days of a qualifying cancellation request made within 14 days of the original charge.",
"messages": [
{"role": "user", "content": "How long does a refund take?"}
]
}'Step 4
Read the receipt
The response is a normal completion with an extra _llm11 block, and the headline figures are mirrored into x-llm11-* headers so you can log them without parsing the body.
response (trimmed)
{
"id": "5f0c…",
"object": "chat.completion",
"model": "openai/gpt-5.6-luna",
"choices": [{ "index": 0, "message": { "role": "assistant", "content": "…" } }],
"usage": { "prompt_tokens": 214, "completion_tokens": 38 },
"_llm11": {
"verdict": "pass",
"taskType": "classification_or_extraction",
"triageBackend": "jev",
"candidatePool": ["openai/gpt-5.6-luna", "google/gemini-3.8-flash", "openai/gpt-5.6-terra"],
"rungsRun": [
{ "rung": "schema", "passed": true },
{ "rung": "groundedness", "passed": true, "confidence": 0.94 }
],
"costCents": 0.0041,
"verificationCostCents": 0.0009,
"triageCostCents": 0.0000009,
"totalCostCents": 0.005,
"baselineCostCents": 0.0462,
"savingsCents": 0.0412
}
}costCents is what generating the answer cost, verificationCostCents is what checking it cost, and triageCostCents is what the routing decision itself cost. None of the three overlap. baselineCostCents prices the same tokens on the most expensive model in candidatePool, the pool this request was actually offered. When that model cannot be priced, it comes back null rather than zero.
Step 5
Pick a routing pack, or your own pool
By default a project routes over the llm11-balanced pack. Change it in project settings, to llm11-fast, llm11-smart, or a custom list of exactly the models you want eligible. Override it on any single request with model or llm11_models, without touching the project default.
Things that will trip you up
- Streaming is not implemented yet. A request with
stream: truegets a clear 501 rather than a non-streaming response pretending otherwise. Verification needs the finished answer, so streaming needs a design that holds the stream back until the checks clear. - Requests stop at a zero balance. Tokens, checks and triage all come out of prepaid credit at provider list price. At zero you get a 402, not a surprise invoice.
- An unknown id in llm11_models is refused, not ignored. A pool with a typo in it returns a 400 naming what was wrong, so your traffic never silently narrows.
Moving an existing app across? The migration guide covers rollback, dual-running and what to watch in the first week.