hamro.site — Free AI Gateway · Full Documentation
A single, OpenAI-compatible API that gives you free access to multiple frontier models through one key and one URL. It aggregates ten providers — Groq, OpenRouter, OpenCode Zen, Ollama Cloud, Naga AI, ZenMux, LLM7, Cerebras, Chutes and HuggingFace — into a smart routing layer with automatic failover, so coding agents (Claude Code, Cursor, Aider, OpenCode, custom CLIs) never see a broken connection.
bashYour agent / script
│ OpenAI-compatible calls, one key
▼
┌───────────────────┐
│ hamro.site │ /v1/chat/completions, /v1/models
│ smart router │ sticky success + auto-failover
│ random mode │ model: "random" → pinned per session
└─────────┬─────────┘
│
┌────────┼────────────┬──────────┬───────────┬───────────┐
▼ ▼ ▼ ▼ ▼ ▼
Groq OpenRouter OpenCode Ollama Naga AI HuggingFace
(llama) (nemotron) (deepseek) (nemotron) (nemotron) (llama, deepseek)
+ ZenMux · LLM7 · Cerebras · Chutes
Table of contents
- The free models
- Quick start — 2 minutes
- API reference
- Using it with coding agents
- Getting free API keys
- Self-hosting & deployment
- Data, telemetry & the status page
- Security notes
- Troubleshooting
The free models
Nearly every model is 100% free (the router also tracks estimated cost for the paid fallback entries). The full catalog is always available from
GET /v1/models| Model id (use this in text | Provider | Context | Notes |
|---|---|---|---|
text | Groq | 131k | Very fast, great general coding |
text | Ollama Cloud | 262k | Nemotron 3 Ultra, free cloud tier |
text | Ollama Cloud | 131k | GPT-OSS 120B, free |
text | Naga AI | 1M | Nemotron 3 Ultra, free |
text | Naga AI | 1M | Nemotron 3 Super, free |
text | Naga AI | 131k | Llama 3.3 70B, free |
text | Naga AI | 1M | Llama 4 Scout, free |
text | LLM7 | 128k | GPT-OSS 20B, free turbo tier |
text | HuggingFace | 131k | Llama 3.3 70B |
text | HuggingFace | 1M | DeepSeek V4 Flash |
text | HuggingFace | 1M | GLM 5.2 |
text | ZenMux | 131k | DeepSeek V4 Flash, free |
text | ZenMux | 131k | GLM 4.7 Flash, free |
text | Cerebras | 131k | GLM 4.7 on Cerebras |
text | OpenRouter | 200k | Auto-routes to OpenRouter's best free model |
text | OpenCode Zen | 131k | DeepSeek V4 Flash, free, shows reasoning |
text | any | — | Picks a random model, pinned per session (see below) |
You can also pass a bare model id (
llama-3.3-70b-versatileThe canonical id is
. Because the OpenRouter model id is itselftextprovider/model, its canonical id istextopenrouter/free.textopenrouter/openrouter/free
Random model mode
Set
"model": "random""auto"- the session goes idle past (default 1 hour), ortext
RANDOM_SESSION_TTL_SECONDS - the pinned model returns an error (401/402/403/404/429/5xx, timeout, network failure) — the request then fails over to other random models and the next request picks a fresh random one.
Sessions are identified by (API key +
x-session-iduserX-Gateway-Session-ModelQuick start — 2 minutes
bash# 1. Check the models
curl http://localhost:3000/v1/models \
-H "Authorization: Bearer nishan-bajagain"
# 2. Ask a question (non-streaming)
curl http://localhost:3000/v1/chat/completions \
-H "Authorization: Bearer nishan-bajagain" \
-H "Content-Type: application/json" \
-d '{
"model": "groq/llama-3.3-70b-versatile",
"messages": [{"role": "user", "content": "Explain monads in one sentence."}]
}'
# 3. Stream a reply
curl -N http://localhost:3000/v1/chat/completions \
-H "Authorization: Bearer nishan-bajagain" \
-H "Content-Type: application/json" \
-d '{
"model": "opencode/deepseek-v4-flash-free",
"messages": [{"role": "user", "content": "Write a bubble sort in Python."}],
"stream": true
}'
Replace
http://localhost:3000API reference
Base URL
| Env | Value |
|---|---|
| Local | text |
| Deployed | text |
All endpoints live under
/v1baseURLapiKeyAuthentication
Every
/v1/*makefileAuthorization: Bearer nishan-bajagain
- Missing or wrong key → text
401 {"error": {"message": "Invalid API key", ...}} - The check is timing-safe and works for browser clients (CORS enabled).
- ,text
GET /v1/modelsboth require it.textPOST /v1/chat/completions - You can change the key in (text
.env).textPUBLIC_API_KEY
POST /v1/chat/completions
OpenAI-compatible chat completions with optional streaming.
Request body (all standard OpenAI fields are passed through):
jsonc{
"model": "groq/llama-3.3-70b-versatile", // any model id from /v1/models
"messages": [
{ "role": "system", "content": "You are a terse coding assistant." },
{ "role": "user", "content": "Refactor this function..." }
],
"stream": false, // true → SSE events (see below)
"temperature": 0.3, // optional
"max_tokens": 1024, // optional
"top_p": 1, // optional
"tools": [...], // optional — tool calling passes through verbatim
"tool_choice": "auto",
"stream_options": { "include_usage": true } // optional — usage in final chunk
}
Non-streaming response (200):
jsonc{
"id": "chatcmpl-...",
"object": "chat.completion",
"created": 1754700000,
"model": "groq/llama-3.3-70b-versatile",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "...",
"tool_calls": null // present when the model calls tools
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 25,
"completion_tokens": 40,
"total_tokens": 65
}
}
Streaming (SSE)
Set
"stream": truetext/event-streamkotlindata: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: [DONE]
- Reasoning models (e.g. DeepSeek) stream their reasoning in /text
delta.reasoning— pass it through if your client understands it.textdelta.reasoning_content - If is supported by the upstream provider, the final chunk beforetext
stream_options.include_usageincludestext[DONE].textusage - If an upstream provider fails mid-stream, the gateway emits an error chunk
and so your client's stream parser never hangs.text
[DONE]
GET /v1/models
Lists every configured, operational model:
jsonc{
"object": "list",
"data": [
{
"id": "groq/llama-3.3-70b-versatile",
"object": "model",
"created": 1735689600,
"owned_by": "groq",
"context_length": 131072,
"pricing": { "input": "0.5900", "output": "0.7900" }
}
// ...
]
}
Response headers
Every completion response carries routing telemetry:
| Header | Meaning |
|---|---|
text | Provider that actually served the request ( text text text |
text | Model id used upstream (after rewriting) |
text | Number of failed attempts before success ( text |
text | Total gateway latency in ms |
text | text text |
text | Requests-per-minute cap for your key |
text | Requests left in the current window |
Errors
| Status | Meaning |
|---|---|
text | Missing / invalid API key |
text | Malformed request (bad JSON, no messages) |
text | Unknown model id |
text | Rate limit exceeded (client or upstream), no fallback succeeded — includes text |
text | All providers failed (offline / timeout / server error) |
text | Upstream timeout |
text | Client disconnected mid-stream |
Error bodies follow the OpenAI shape:
{"error": {"message", "type", "code"}}Failover & routing
The router implements sticky success:
- Requested model → try it first (if its provider has been healthy recently).
- On 401 / 403 / 404 / 429 / 5xx / timeout / network error, it falls back
to the next entry in without breaking the connection (streaming fails over before the first token).text
MODEL_FALLBACK_CHAIN - Providers that fail get a 30-second cooldown; providers that succeed stay prioritized.
- Every attempt is logged; shows failover events with arrows.text
/status
Chat history database (text/api/chats
)
/api/chatsThe web client saves its chat history to the gateway's own database (
data.json| Endpoint | Description |
|---|---|
text | Chat summaries — add text |
text | One full chat (404 when missing) |
text | Create/update — text text |
text | Delete one chat (204 / 404) |
text | Delete every chat for this key |
bash# Save a chat
curl http://localhost:3000/api/chats \
-H "Authorization: Bearer nishan-bajagain" \
-H "Content-Type: application/json" \
-d '{"id":"chat_1","title":"Refactor","messages":[{"role":"user","content":"hi"}]}'
# List summaries
curl http://localhost:3000/api/chats -H "Authorization: Bearer nishan-bajagain"
Enforced limits (400 on violation): 50 chats per key, 200 messages per chat, 200 KB per chat, 8 KB per message, 100-char titles. Chats persist to
data.jsonRate limiting
Every API key gets a sliding-window rate limit (default 120 requests/minute). When exceeded you get
429Retry-AfterenvRATE_LIMIT_RPM=120 # requests per minute per key — set 0 to disable
Deterministic response cache
Identical non-streaming requests with
temperature: 0x-gateway-cache: HITenvCACHE_TTL_SECONDS=60 # seconds a cached response lives — set 0 to disable CACHE_MAX_ENTRIES=200 # LRU cap
Default chain (edit
MODEL_FALLBACK_CHAIN.envbashgroq/llama-3.3-70b-versatile → ollama/nemotron-3-ultra → naga/nemotron-3-ultra-550b-a55b:free → llm7/gpt-oss:20b → huggingface/meta-llama/Llama-3.3-70B-Instruct → openrouter/nvidia/nemotron-3-ultra-550b-a55b:free → zenmux/deepseek/deepseek-v4-flash-free → cerebras/zai-glm-4.7 → chutes/deepseek-ai/DeepSeek-V4-Flash-0731-TEE → opencode/nemotron-3-ultra-free → opencode/deepseek-v4-flash-free
Using it with coding agents
Claude Code
The gateway speaks the Anthropic Messages protocol natively (
POST /v1/messages/v1/messages/count_tokensrandomOne command (recommended):
bashcd hamro.ai
npm run claude # starts the gateway if needed + opens Claude Code
What it does:
- Starts the gateway on port 3000 if it isn't already running (builds it on
first run, logs to ).text
.freebuff/hamro-server.log - Writes an isolated settings file () that points Claude Code at the gateway — your globaltext
.freebuff/claude-settings.jsonis never modified. This matters because a global settings-filetext~/.claude/settings.jsonblock overrides shell environment variables.textenv - Sets (defaulttext
ANTHROPIC_MODEL— a model is picked once per session and pinned until it errors) andtextrandomfor background tasks.textANTHROPIC_SMALL_FAST_MODEL - Opens the Claude Code TUI.
Useful variants:
bashnpm run claude -- --check # verify gateway + config, don't open
npm run claude -- --model groq/llama-3.3-70b-versatile # pin a specific model
npm run claude -- --restart # force-restart a stale gateway build
npm run claude -- --port 4000 # different port
Manual equivalent (if you don't want to use the launcher): create
~/.claude/settings.jsonjsonc{
"env": {
"ANTHROPIC_BASE_URL": "http://localhost:3000", // no /v1 — Claude Code appends it
"ANTHROPIC_AUTH_TOKEN": "nishan-bajagain", // your gateway key
"ANTHROPIC_MODEL": "random", // or any model id from /v1/models
"ANTHROPIC_SMALL_FAST_MODEL": "groq/llama-3.3-70b-versatile"
}
}
(If you prefer a proxy instead, Claude Code Router (CCR) still works: install
npm install -g @musistudio/claude-code-routerhttp://localhost:3000/v1nishan-bajagainhttp://127.0.0.1:3456Cursor
- Cursor Settings → Models → OpenAI API Key: enter .text
nishan-bajagain - Override OpenAI Base URL: .text
http://localhost:3000/v1 - Add the model ids (e.g. ) and enable them.text
groq/llama-3.3-70b-versatile - Pick one in the model picker and chat.
Cursor sends OpenAI-format requests, so it works directly — no proxy needed.
Aider
bashaider \ --openai-api-base http://localhost:3000/v1 \ --openai-api-key nishan-bajagain \ --model openai/groq/llama-3.3-70b-versatile
Aider's model name is
— thetextopenai/<id>prefix tells Aider "this is an OpenAI-compatible chat model", it does not send requests to OpenAI.textopenai/
OpenCode / Continue / other agents
Anything that supports a custom OpenAI-compatible endpoint works directly:
| Setting | Value |
|---|---|
| Base URL / API base | text |
| API key | text |
| Model | any id from text |
This includes OpenCode (the CLI), Continue, Roo Code, Cline, Windsurf, Zed, Raycast AI, and custom scripts.
Getting free API keys
The gateway ships with working keys, but if you deploy your own instance you need your own (all free):
| Provider | Where | Free tier |
|---|---|---|
| Groq | https://console.groq.com/keys | Free tier with generous rate limits; text |
| OpenRouter | https://openrouter.ai/keys | Free models ( text text |
| OpenCode Zen | https://opencode.ai (sign in → API keys) | Free models: text text |
| Ollama Cloud | https://ollama.com (sign in → API keys) | Free cloud models ( text text |
| Naga AI | https://naga.ac | Free models with text |
| ZenMux | https://zenmux.ai | Free models with text |
| LLM7 | https://llm7.io | Free turbo tier ( text text |
| Cerebras | https://cloud.cerebras.ai | Free tier models ( text |
| Chutes | https://chutes.ai | TEE-hosted open models |
| HuggingFace | https://huggingface.co/settings/tokens | Free inference with monthly credits |
Copy them into
.env.env.exampleenvPUBLIC_API_KEY="nishan-bajagain" GROQ_API_KEY="gsk_..." OPENROUTER_API_KEY="sk-or-..." OPENCODE_API_KEY="sk-..." OPENCODE_BASE_URL="https://opencode.ai/zen/v1" OLLAMA_API_KEY="..." NAGA_API_KEY="ng-..." ZENMUX_API_KEY="sk-mg-v1-..." LLM7_API_KEY="..." CEREBRAS_API_KEY="csk-..." CHUTES_API_KEY="cpk_..." HUGGINGFACE_API_KEY="hf_..." MODEL_FALLBACK_CHAIN="groq/llama-3.3-70b-versatile,ollama/nemotron-3-ultra,naga/nemotron-3-ultra-550b-a55b:free,llm7/gpt-oss:20b,huggingface/meta-llama/Llama-3.3-70B-Instruct,openrouter/nvidia/nemotron-3-ultra-550b-a55b:free,zenmux/deepseek/deepseek-v4-flash-free,cerebras/zai-glm-4.7,chutes/deepseek-ai/DeepSeek-V4-Flash-0731-TEE,opencode/nemotron-3-ultra-free,opencode/deepseek-v4-flash-free"
Self-hosting & deployment
Local
bashnpm install
npm run dev # http://localhost:3000
# or production:
npm run build && npm start
Vercel / Netlify / any serverless host
No database needed. The gateway stores telemetry in a JSON file (
data.jsonbashvercel
# set the env vars above in the Vercel dashboard (or `vercel env add`)
To keep /status
Option 1 — free remote JSON (zero setup). The gateway auto-creates a free jsonblob.com blob on first write, remembers its URL in
data.jsonenv# optional — durable endpoint you control (any JSON service speaking GET/PUT): # REMOTE_JSON_URL="https://jsonblob.com/api/jsonBlob/<id>"
Paste a
https://jsonblob.com/<id>REMOTE_JSON_URLOption 2 — Vercel KV / Upstash. Add a free Vercel KV / Upstash Redis store and set its two env vars. The gateway persists telemetry to the shared KV (via plain
fetchenvKV_REST_API_URL="https://your-kv.upstash.io" KV_REST_API_TOKEN="AUpX..."
Without any of the above:
- Set to a writable absolute path if you have a mounted volume (e.g.text
DATA_FILE) to persist telemetry across cold starts.text/data/hamro-data.json - Otherwise still works — data just resets when the instance recycles (Vercel'stext
/statusis per-instance and ephemeral).text/tmp
OpenCode Zen and free OpenRouter models can be slow on first token (5–20 s). Raise your platform's function timeout if you see
504VPS / Docker-friendly hosts
data.jsonData, telemetry & the status page
- — live dashboard: provider health grid, aggregate + per-model usage (requests, prompt/completion tokens, estimated cost, avg latency), color-coded event log with failover arrows. Auto-refreshes health checks.text
/status - — the same data as JSON.text
/api/status - — pings every provider and updates status.text
POST /api/healthcheck - — lightweight unauthenticated probe (provider status, uptime, request count) for uptime monitors and Vercel Cron;text
GET /api/healthwhen all providers are online,text200when degraded.text503 - — all request logs + provider status (max 5,000 recent records; oldest pruned) plus the chat-history database (text
data.jsonsection, namespaced per key). Plain JSON, no database engine.textchats
Storage resolution order: shared KV (
KV_REST_API_URLKV_REST_API_TOKENDATA_FILE./data.json/tmp/hamro-data.jsonSecurity notes
- is the public shared key — anyone with it can use your gateway. Changetext
nishan-bajagainintextPUBLIC_API_KEYif you want to restrict access, and treat anything pasted into chat/forums as compromised (rotate provider keys too if they were shared publicly).text.env - is gitignored. Never commit provider keys.text
.env - CORS is wide open () ontext
*so browser-based agents work. Lock it down intext/v1/*if you deploy publicly.textnext.config.ts
Troubleshooting
| Symptom | Fix |
|---|---|
text | Check text |
text | Groq free tier is rate-limited — the router auto-falls back to OpenRouter/OpenCode; watch text |
| Slow first token on OpenCode models | Normal for free reasoning models (5–20 s). Streaming shows partial reasoning as it arrives. |
text | Check each provider key in text text text |
text | You exceeded text text |
text | Vercel instances are ephemeral — add a free Vercel KV / Upstash store and set text text text |
| Claude Code won't connect | The gateway speaks Anthropic natively — run text |
Last updated: August 2026 · hamro.site free AI gateway.