How to verify an LLM API serves the real model
Seven tests a buyer can run against any gateway, ranked by what they catch, then how the daily check here runs one of them in public, with a curl you can paste.
Cheap API resellers sometimes put a smaller, older or quantized model behind a flagship id. No single prompt proves which weights answered, but a handful of tests, kept over days, catch a substitute. This page is that checklist, written for any gateway, with RelaySwitch's own check as the worked example: the same canary to every model each day, a verdict per model, public at https://api.relayswitch.io/v1/proof.
- Models checked today
- 339
- Stable
- 305
- Changed
- 21
- Not reached
- 13
01The checklist
| Test | What to send | What it catches | Signal |
|---|---|---|---|
| Self-identity prompt | "Which model are you, and who made you?" | Almost nothing: a system prompt sets the answer, and distilled models repeat their teacher’s. | Weak |
| Knowledge cutoff | Three dated facts the claimed model’s training should hold, and one after its cutoff. | A model from an older or smaller family answers the early facts wrong or the late one right. | Medium |
| Long-context needle | A fact buried at 80% of the stated context window, then a question about it. | A substitute with a shorter window, or a relay that truncates, misses it. | Strong |
| Arithmetic and code canary | A fixed prompt with mixed scripts, arithmetic, a code fragment and "reply with one word", at temperature 0. | A different model, quantization or a changed system prompt moves the answer; the point is the diff over days. | Strong over time |
| Token count | The prompt through the developer’s own tokenizer, then the same prompt to the API. | usage.input_tokens far from your count means a different tokenizer, so a different model family. | Strong |
| Consistency across days | The same canary every day; keep the answers. | A route swapped behind the id shows up as a changed answer on a prompt nothing else changed. | Strong |
| Receipts | Fetch the signed receipt for a request id. | Nothing about the weights, but it binds the provider to a model name and a token count per request. | Binding, not proof |
Run the strong ones first; keep the answers; the diff over days is the evidence.
02Self-identity prompts, and why they are weak
“Which model are you?” is the first thing everyone sends and the last thing to trust. The answer is text the model was trained or prompted to produce: a relay can set it in a system prompt, a distilled model repeats its teacher's name, and most models decline to be specific about versions. Treat a wrong answer as a flag and a right answer as nothing.
03Knowledge-cutoff questions
Pick three facts dated inside the claimed model's training window and one from after it. A model from the right family and generation knows the three and declines or guesses on the fourth. An older substitute misses the later of the three; a newer one answers the fourth. Vary the facts between runs so they cannot be prompted around.
04The long-context needle
Build a prompt at about 80% of the context window on the model's page, bury one made-up fact deep inside it, and ask for the fact. A substitute with a shorter window, or a relay that silently cuts the prompt, cannot answer. The cost is the prompt itself at the input rate, so run it once per id, not daily.
05The arithmetic and code canary
A fixed prompt that mixes scripts, a date, arithmetic and a code fragment, sent at temperature 0, with one word asked for in reply. The one answer means little; the diff between today's and yesterday's means a lot, because nothing in the prompt changed. The canary the daily check uses today:
RelaySwitch canary 7f3c. The quick brown fox jumps over 13 lazy dogs at 04:52 UTC on 2026-10-12. Ελληνικά, 日本語, résumé, naïve café. function add(a, b) { return a + b; } 3.14159 * 2^10 = 3216.99. Reply with one word.Paste it against any key and keep the answer per day:
# Day 1: send the canary at temperature 0 and keep the answer.curl -s https://api.relayswitch.io/v1/chat/completions \ -H "Authorization: Bearer sk-relay-..." \ -H "Content-Type: application/json" \ -d '{"model": "claude-sonnet-5-5", "temperature": 0, "messages": [{"role": "user", "content": "RelaySwitch canary 7f3c. The quick brown fox jumps over 13 lazy dogs at 04:52 UTC on 2026-10-12. Ελληνικά, 日本語, résumé, naïve café. function add(a, b) { return a + b; } 3.14159 * 2^10 = 3216.99. Reply with one word."}]}' \ | tee canary-$(date -u +%F).json | jq -r '.choices[0].message.content, .usage.input_tokens' # Day 2 and on: the same command, then compare.diff <(jq -r '.choices[0].message.content' canary-2026-10-31.json) \ <(jq -r '.choices[0].message.content' canary-$(date -u +%F).json)06Token counts against your own tokenizer
Every model family tokenizes differently. Count the canary with the developer's own tool, then read usage.input_tokens in the gateway's answer. A difference of a few tokens is normal: Anthropic's token-counting reference (read 2026-10-31) calls its count an estimate, says the endpoint is free to use, and notes that models from Claude Opus 4.7 on tokenize about 30 percent higher than earlier ones, so count against the id you are testing. A count off by half or double is a different tokenizer, which is a different model family. OpenAI's tiktoken (read 2026-10-31) is “a fast BPE tokeniser for use with OpenAI's models”; encoding_for_model picks the encoding for an id.
# Anthropic's own count for a Claude id (free; an estimate, per its docs):curl https://api.anthropic.com/v1/messages/count_tokens \ -H "x-api-key: $ANTHROPIC_API_KEY" -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{"model": "claude-sonnet-5-5", "messages": [{"role": "user", "content": "RelaySwitch canary 7f3c. The quick brown fox jumps over 13 lazy dogs at 04:52 UTC on 2026-10-12. Ελληνικά, 日本語, résumé, naïve café. function add(a, b) { return a + b; } 3.14159 * 2^10 = 3216.99. Reply with one word."}]}' # OpenAI's tokenizer for a GPT id:python3 -c 'import tiktoken; print(len(tiktoken.encoding_for_model("gpt-4o").encode("RelaySwitch canary 7f3c. The quick brown fox jumps over 13 lazy dogs at 04:52 UTC on 2026-10-12. Ελληνικά, 日本語, résumé, naïve café. function add(a, b) { return a + b; } 3.14159 * 2^10 = 3216.99. Reply with one word.")))' # Then compare with usage.input_tokens in the gateway's answer above.07Consistency across days, and receipts
Keep the canary answers. A provider that changes the route behind an id changes the answer to a prompt that did not change, and the day it happened is in your files. Pair that with the receipt: a signed record per request naming the model and the billed tokens. It does not inspect weights, but it binds the provider to a name, and the signature can be checked on the Verify page.
curl https://api.relayswitch.io/v1/requests/REQUEST_ID/receipt \ -H "Authorization: Bearer $RELAYSWITCH_API_KEY"08How the daily check here does it
Once a day every model in the catalog gets the canary above at temperature 0, and the answer is compared with the earlier runs. Three verdicts: stable, the answer matched; changed, it moved, so what serves the id is not what served it before; not reached, no route answered the latest run, and the last verdict is history. The feed is public JSON at https://api.relayswitch.io/v1/proof, no key, cached five minutes; the Proof page renders one row per model with the time of the run.
| Changed today | Developer | Checked | Last change |
|---|---|---|---|
| Claude Fable 5 1 | Anthropic | Nov 2, 2026, 12:37 AM UTC | Nov 1, 2026, 12:37 AM UTC |
| Claude Opus 4 7 Thinking | Anthropic | Nov 2, 2026, 12:37 AM UTC | Oct 31, 2026, 12:37 AM UTC |
| Claude Opus 4 8 Thinking | Anthropic | Nov 2, 2026, 12:37 AM UTC | Nov 2, 2026, 12:37 AM UTC |
| Claude Opus 4.8 | Anthropic | Nov 2, 2026, 12:37 AM UTC | Oct 29, 2026, 12:37 AM UTC |
| Claude Sonnet 4 5 20250929 | Anthropic | Nov 2, 2026, 12:37 AM UTC | Oct 28, 2026, 12:37 AM UTC |
| Gemini 3.1 Flash Image | Nov 2, 2026, 12:37 AM UTC | Nov 2, 2026, 12:37 AM UTC | |
| Gemini 4 Argon | Nov 2, 2026, 12:37 AM UTC | Oct 31, 2026, 12:37 AM UTC | |
| Kimi K2.8 | Moonshot AI | Nov 2, 2026, 12:37 AM UTC | Oct 28, 2026, 12:37 AM UTC |
| Kimi K3 1 | Moonshot AI | Nov 2, 2026, 12:37 AM UTC | Nov 2, 2026, 12:37 AM UTC |
| Codex Auto Review | OpenAI | Nov 2, 2026, 12:37 AM UTC | Oct 30, 2026, 12:37 AM UTC |
| Qwen3.8 Flash | Qwen | Nov 2, 2026, 12:37 AM UTC | Nov 2, 2026, 12:37 AM UTC |
| Uncensored AI Assistant | RelaySwitch | Nov 2, 2026, 12:37 AM UTC | Oct 29, 2026, 12:37 AM UTC |
| Uncensored AI Chat | RelaySwitch | Nov 2, 2026, 12:37 AM UTC | Oct 29, 2026, 12:37 AM UTC |
| Uncensored Chatbot | RelaySwitch | Nov 2, 2026, 12:37 AM UTC | Oct 29, 2026, 12:37 AM UTC |
| Uncensored Code Assistant | RelaySwitch | Nov 2, 2026, 12:37 AM UTC | Oct 29, 2026, 12:37 AM UTC |
| Cu-Mai R1 70B | Steelskull | Nov 2, 2026, 12:37 AM UTC | Nov 2, 2026, 12:37 AM UTC |
| HY4 | Tencent | Nov 2, 2026, 12:37 AM UTC | Oct 28, 2026, 12:37 AM UTC |
| Grok 4.20 0309 Reasoning | xAI | Nov 2, 2026, 12:37 AM UTC | Nov 1, 2026, 12:37 AM UTC |
| MiMo-V2.5 Uncensored | Xiaomi | Nov 2, 2026, 12:37 AM UTC | Oct 29, 2026, 12:37 AM UTC |
| GLM 5.1 | Z.ai | Nov 2, 2026, 12:37 AM UTC | Oct 28, 2026, 12:37 AM UTC |
| GLM-5.3 Abliterated | Z.ai | Nov 2, 2026, 12:37 AM UTC | Oct 29, 2026, 12:37 AM UTC |
Generated 2026-11-02T08:48:18.900Z; 305 stable, 21 changed, 13 not reached of 339.
A changed verdict is a routing change to go and look at. The status page carries the hourly probes per route beside it.
Questions
- Is there an AI API model tester I can run?
- The curl above is one: a fixed canary at temperature 0, the answer kept per day, a diff. The hosted version is the daily check at https://api.relayswitch.io/v1/proof, public JSON with one verdict per model, which this site renders on the Proof page.
- How do I test an LLM API key?
- GET https://api.relayswitch.io/v1/models with the key lists what it can call; one chat completion with -i shows the request id in the headers; the receipt for that id names the model and the billed tokens. The three commands are in the docs.
- Why is asking the model its name not enough?
- Because the name in the answer comes from the system prompt or the training data, and both are easy to set. A relay that swaps a model can leave the old name in the prompt; a distilled model repeats the teacher’s. Use tests the weights cannot fake: cutoff facts, a needle at depth, token counts, and the same canary over days.
- Can a gateway serve a quantized version of the model?
- A gateway that runs its own copies can; a gateway that forwards to the developer’s API cannot change the weights. The tests that catch a changed copy are the needle at depth, the arithmetic and code canary over days, and the token count; a receipt binds the provider to the name it bills under.
- What does the daily check here prove, and what does it not?
- It proves that the answer to one fixed prompt did or did not change between runs, per model, with the time of the run. It does not inspect weights. Today: 305 of 339 models stable, 21 changed, 13 not reached (generated 2026-11-02T08:48:18.900Z).
- Is there a GitHub tool for this?
- Several, and the Reddit threads that rank for the query list them. Any of them reduces to the rows in the table: identity prompts, cutoff questions, a needle, a canary, token counts, consistency. Run them against this key the same way you would against any other; nothing here needs you to trust the page.
Call the model on the label
One key, every model, a public check each day and a receipt on every call.