FreeLLMAPI is an open-source gateway (MIT license) that runs on your own machine. It speaks two dialects: the OpenAI API and the Anthropic Messages API. That is why it connects to almost any tool you already use, Claude Code included.
Here is what happens behind it: you store free API keys from the providers, for example Google, Groq or Mistral. For every request, a router picks the best available model. If a provider's quota runs out (HTTP 429) or the server errors, it tries the next model.
It counts usage per key so you stay under the limits. Your keys sit encrypted (AES-256-GCM) in a local SQLite database. Your apps only ever see a single key with the prefix freellmapi-.
The numbers from the README, as of October 29, 2026: 34 providers, 635 free model endpoints (584 of them for chat) and about 7.4 billion tokens per month of listed free capacity in total. That is the sum of the providers' limits according to the catalog.
How much of it reaches you depends on the keys you add. The repo now has over 40,000 stars on GitHub.
curl -fsSL https://freellmapi.co/install.sh | bash
The script creates ~/freellmapi, generates an encryption key, pulls the Docker image and starts the container. You can read the script first: freellmapi.co/install.sh. Running it again is safe, your .env and the key stay in place and only the container updates.
Then open http://localhost:3001. Server installs (Docker, one-line script) are protected by an account with email and password. The desktop app signs itself in.
Two alternatives if you do not like piping a script into bash:
ENCRYPTION_KEY with openssl rand -hex 32, write it into a .env (together with PORT=3001) and run docker compose up -d..dmg (macOS) or .exe (Windows) from the GitHub Releases. The only credential is the unified key in the tray popover.freellmapi- and is the only key your tools ever see.Start with three providers. More keys mean more free quota and more fallbacks, but also more terms of service you have accepted (more on that below).
curl -i http://localhost:3001/v1/chat/completions \
-H "Authorization: Bearer freellmapi-your-key" \
-H "Content-Type: application/json" \
-d '{"model": "auto", "messages": [{"role": "user", "content": "Say hello in one sentence."}]}'
"model": "auto" leaves the choice to the router. The response headers carry X-Routed-Via: provider/model, so you can see who actually answered. If the router had to fall back, X-Fallback-Attempts appears too.
Claude Code expects the server's root URL, without /v1, because it appends the Anthropic API path itself. There are three ways.
Option A: the setup command. It reads the models from your live catalog, backs up your configuration and merges the change into the existing one:
npx freellmapi setup-claude --url http://localhost:3001 --api-key freellmapi-your-key --dry-run
npx freellmapi setup-claude --url http://localhost:3001 --api-key freellmapi-your-key
The first call only shows you the diff, the second writes it.
Option B: launch. Starts Claude Code with the credentials for that one run only, nothing lands in a config file:
export FREELLMAPI_API_KEY=freellmapi-your-key
npx freellmapi launch
For bridging an empty limit, this is my way: you start the free variant on purpose and your normal setup stays as it is.
Option C: by hand.
export ANTHROPIC_BASE_URL=http://localhost:3001
export ANTHROPIC_AUTH_TOKEN=freellmapi-your-key
claude
Use ANTHROPIC_AUTH_TOKEN, not ANTHROPIC_API_KEY. Claude Code treats a set ANTHROPIC_API_KEY as a conflicting login and refuses to start.
Which free models sit behind the Claude names is controlled in the dashboard under Keys, tab Anthropic: each family (default, opus, sonnet, haiku) runs on auto or on a model you pin.
This is the reason I am showing the tool at all. Your limit is empty, the reset is hours away and you want to keep moving. You start Claude Code through FreeLLMAPI (option B) and hand it tasks small enough for a weaker model:
My rule of thumb: for grunt work this is enough, for demanding coding you are better off waiting until your limit is back. Architecture decisions do not belong on a free model that is already half used up by the afternoon (more under the limits below). If you want different behavior for code than for chat, set the header X-FreeLLM-Task-Type: code. It shifts the router's weighting slightly toward intelligence over speed.
The same gateway serves any OpenAI-compatible script. You only swap the base URL. An example: sorting customer messages by sentiment.
from openai import OpenAI
client = OpenAI(base_url="http://localhost:3001/v1", api_key="freellmapi-your-key")
texts = ["Shipping takes forever.", "Great support, thanks!", "How do I cancel?"]
for text in texts:
reply = client.chat.completions.create(
model="auto:fast",
messages=[
{"role": "system", "content": "Answer with exactly one word: positive, negative or neutral."},
{"role": "user", "content": text},
],
)
print(text, "->", reply.choices[0].message.content.strip())
auto:fast ranks models by measured speed. There are more strategies: auto:smart (highest intelligence), auto:reliable (recent success rate) and auto:balanced (the default mix). With hundreds of texts, a single provider's quota will run out at some point, the router falls back, and your script does not notice. The gateway also covers embeddings (/v1/embeddings), transcription and image generation, as far as a provider on your list offers them for free.
With the virtual model fusion, the router sends your question in parallel to several different free models. A judge model builds one answer from the drafts. That helps where a single answer would be too random: checking a decision, probing a plan for gaps, or reading code for weaknesses.
curl http://localhost:3001/v1/chat/completions \
-H "Authorization: Bearer freellmapi-your-key" \
-H "Content-Type: application/json" \
-d '{"model": "fusion", "messages": [{"role": "user", "content": "Check this plan for weaknesses: ..."}]}'
Which models sit on the panel and which one judges, you set in the dashboard under Fusion or per request through the fusion field. Every sub-call goes through normal routing and uses quota. A fusion request therefore costs you a multiple of a normal one.
ANTHROPIC_API_KEY. Use ANTHROPIC_AUTH_TOKEN.http://localhost:3001, OpenAI-compatible tools get http://localhost:3001/v1.127.0.0.1. Start it with HOST_BIND=0.0.0.0, but only on your home network.127.0.0.1 does not apply inside the container. Set PROXY_URL=socks5h://host.docker.internal:7890 (adjust the port) and let the proxy accept connections from outside loopback.docker compose logs -f freellmapi) and is valid for 15 minutes.The limits are stated in the repo itself, I pass them on unvarnished:
On the catalog: free installs pull it from a monthly snapshot. A new model arrives there 30 days later than on the paid tier (19 US dollars a year, according to the README). Everything works without it. According to the README, prompts, responses and provider keys stay with you.
coding in the dashboard and address it with auto:coding.npx freellmapi setup-<agent>.No spam, unsubscribe at any time
