Every list of free LLM endpoints I have ever used was accurate exactly once: on the day someone wrote it. After that it is a screenshot. The endpoint quietly adds a key requirement, or the model ID changes, or the provider starts returning 402 to anonymous traffic, and the list still says "free, no key needed" because nobody re-ran it.
So I built the boring version. stillworks sends a real chat completion to every endpoint it tracks, on a schedule, and publishes what came back — including the failures, next to the successes.
Disclosure up front: I built this. It is two days old, it is MIT-licensed, and the repo is bon5co/stillworks. I am posting it because the measurement is the interesting part, not because it is finished.
What "we check" actually means
Not a HEAD request. Not a /v1/models listing. A real POST /chat/completions with {"role":"user","content":"hello"} and, for the keyless shelf, no Authorization header at all. If the completion comes back, the row is green and stamped with the time. If it 402s, that is published too.
Here is the state as of 2026-08-05 01:30 UTC:
- 75 models tracked.
- 20 of them answered with no Authorization header on the latest sweep. The other 55 need a free-tier key and are labelled as such, in the same table.
- Across the last week of keyless probes: 146 successes out of 194 attempts.
- Only 5 of those 20 answered every check we made.
-
6 of the 20 answered less than half the time.
gpt-oss:20bon llm7 answered 9 of the last 19. A directory would list that as "available".
That last number is the whole argument. "Available" is not a boolean, and a list that renders it as one is lying to you slightly.
The API is the product
The page is a table. The thing I actually use is this:
curl -s https://stillworks.supercapybara.com/api/llm/up
It returns the keyless endpoints that answered, ranked — first by how much of the last week each one answered, then by latency. Which means models[0] is the pick and the rest are your fallbacks. Each entry carries everything the next call needs:
{
"model": "minimax-m2.7",
"provider": "llm7",
"openai_base_url": "https://api.llm7.io/v1",
"auth": "none",
"latency_ms": 3862,
"answered": "18/18",
"last_ok": "2026-08-05T01:07:40Z",
"proved": ["tools", "json_schema", "json_object"],
"claimed_unproved": [],
"failed": []
}
Walking that list is the intended usage, not a workaround:
import json, urllib.request
from openai import OpenAI
shelf = json.load(urllib.request.urlopen(
"https://stillworks.supercapybara.com/api/llm/up"))
for endpoint in shelf["models"]: # already ranked, best first
client = OpenAI(base_url=endpoint["openai_base_url"], api_key="not-needed")
try:
reply = client.chat.completions.create(
model=endpoint["model"],
messages=[{"role": "user", "content": "hello"}],
)
except Exception:
continue # your IP hit its quota — next
print(endpoint["model"], reply.choices[0].message.content)
break
You want that loop because of the limitation in the next section.
There is also ?format=env if you would rather paste three lines into a project:
# stillworks: verified keyless 22 min ago
OPENAI_BASE_URL=https://text.pollinations.ai/openai
OPENAI_API_KEY=not-needed
OPENAI_MODEL=openai-fast
proved / claimed_unproved / failed / absent
Capability flags are the part I am most opinionated about, because this is where every registry I have read hand-waves. Four states, and they are not collapsible into two:
| Field | Meaning |
|---|---|
proved |
We called it and it worked. A tool call we could dispatch. A reply that parsed and matched the schema we sent. An answer about an image we sent. |
claimed_unproved |
The provider claims the feature. Our call has never demonstrated it. |
failed |
We called it and it failed. |
| absent from all three | Never probed. Not the same as failing. |
Two real rows show why the distinction earns its keep:
pollinations / openai-fast — 39 of 39 plain chat completions succeeded, 295 ms, the most reliable keyless row on the board. The provider claims tool calling. Our tools probe came back 402 Payment Required. So tools sits in claimed_unproved, not in proved, and not in failed either — we did not disprove the feature, we just never got to see it.
ovh-anonymous / Qwen3Guard-Gen-8B — 6 of 6 chat completions succeeded, 464 ms. All four capability probes failed outright: feature 'response_format with provided format' is not currently supported. Those go in failed. A row can be a perfectly healthy chat endpoint and a dead end for structured output at the same time.
Of the 20 keyless models, 8 have tools actually proved. If you filter with ?feature=tools,vision you get only models where a real call demonstrated it — unprobed models are excluded rather than optimistically included, which is the conservative direction and occasionally the annoying one.
What this cannot tell you
This section is not a disclaimer I bolted on. It is the reason I think the project is worth anything.
- Keyless quotas are commonly per-IP. Verified from our address is not verified from yours. An endpoint that answers our server can return 402 or 429 to you on the first call. We cannot measure your quota and we do not pretend to. This is why the API ranks and returns a list instead of a single winner — the fallbacks are the point.
-
Rows marked
auth: "bearer"were probed with our own free-tier key. That proves the endpoint answered our account. It says nothing about what your signup's free tier includes, or whether the provider is still handing out accounts at all. - These are other people's free services. Any of them can add a key requirement or vanish between two probes. The timestamps exist because the answer decays.
- It is small and it is new. 75 models, two days of history, one probing IP. The track record has to accumulate before "answered 39/39" means much, and right now some rows have a denominator of 5.
Directories list. We check.
That is the entire pitch and I am not going to dress it up further. If you want a green tick that says "up", plenty of pages will give you one. This one gives you "answered 9 of the last 19 attempts, last verified 22 minutes ago, from our IP, and here is the failure that made the other 10" — and then lets you check the working instead of trusting it.
Site: https://stillworks.supercapybara.com
Repo (MIT): https://github.com/bon5co/stillworks
Adding an endpoint is a PR against apps/audit/seed.go with the base URL, the chat path, and whether it needs a key. The prober verifies it on the next cycle and publishes whatever actually happens, including nothing.
It is Go, Postgres, and templ, with no JavaScript framework — the table filters and sorts server-side and the client script only enhances. Provider keys live in the environment and go out on probes only; they are never rendered, logged, written to the database, or returned by the API, and there is a test that fails if one appears in a response.
Happy to be told which endpoints I am missing, or which of my numbers you cannot reproduce from your own IP. The second one is more useful.
Top comments (0)