# Best LLM API routers with free or cheap access to Claude, GPT, DeepSeek and GLM: 2026 comparison

> AI Release · @ai_release1 · https://ai-release.org/guides/luchshie-api-routery-s-besplatnym-ili-deshevym-dostupom_en.html

## TL;DR

- **Time to complete:** 30 minutes
- **Difficulty:** Intermediate
- **You need:** a terminal, `curl`, `jq`, Python 3.10+ with the `openai` package, an API key from one router, and (optionally) vendor keys for a self-hosted proxy
- **Result:** one OpenAI-compatible endpoint that answers requests to Claude, GPT, DeepSeek and GLM, plus a smoke test and a latency/cost check you can rerun any time
- **Rule for this guide:** router names, model IDs, prices and free-tier limits change monthly — every value below that depends on a vendor is a placeholder you fill from `/v1/models` and the pricing page, not from this text

## Requirements and setup
![Illustration: Requirements and setup](https://ai-release.org/guides/img/luchshie-api-routery-s-besplatnym-ili-deshevym-dostupom-en-1.jpg)


- **OS:** any Linux, macOS, or Windows 10/11 with WSL2 — the commands below are bash; on PowerShell replace `export X=Y` with `$env:X="Y"`
- **Tools:** `curl` (any modern build), `jq` 1.6+, Python 3.10+, `pip install openai`
- **Access:** an account on a hosted router, or a machine where you can run a local proxy on port `4000`
- **Keys:** one router API key, stored in an environment variable — never in a committed file
- **Budget awareness:** decide before you start whether you need a free tier or just cheap paid access; if the free route matters most, see [How to use AI models for free in 2026](https://ai-release.org/guides/kak-polzovatsya-ii-besplatno.html?utm_source=tg&utm_medium=channel&utm_campaign=guide_inline&utm_content=guide_to_guide)
- **Disk:** under 100 MB for the Python client; the self-hosted proxy adds a few hundred MB

Term check: an **API router** (also called an aggregator or gateway) is a single HTTP endpoint that forwards your request to whichever model vendor you name, so your code talks to one URL instead of four SDKs. "OpenAI-compatible" means the endpoint accepts the same request shape as OpenAI's `/v1/chat/completions`, which is why the Python snippet in Step 2 works unchanged against any router that supports it.

## Router options at a glance

There are two shapes of router. Pick one before you write code, because the credential model differs.

| Criterion | Hosted aggregator | Self-hosted proxy |
|---|---|---|
| What it is | A vendor-run API that already holds accounts with Anthropic, OpenAI, DeepSeek, Zhipu | A process you run (for example LiteLLM) that holds *your* vendor keys and exposes one local port |
| Credentials you manage | One router key | Four vendor keys plus a local proxy key |
| Free/cheap access | Depends on the router's current trial credits and per-model pricing — verify on its pricing page | You pay each vendor directly at list price; no markup and no free tier added |
| Billing visibility | One invoice, vendor-level detail varies | Per-vendor invoices, full detail |
| Data path | Prompts pass through a third party — check its retention policy | Prompts go only to the vendors you configured |
| Best for | Interns prototyping fast, one-key demos | Teams with existing vendor contracts, compliance constraints |

What each model family requires from the router:

| Model family | Endpoint contract | Verify in the docs |
|---|---|---|
| Claude (Anthropic) | OpenAI-compatible `/v1/chat/completions`, or a native Anthropic passthrough | Exact model IDs, per-1M-token input/output price, context window |
| GPT (OpenAI) | `/v1/chat/completions` | Which model IDs your key tier can call, rate limits |
| DeepSeek | `/v1/chat/completions` | Whether the free/trial quota applies, price per 1M tokens |
| GLM (Zhipu) | `/v1/chat/completions` | Provider prefix used in self-hosted configs, model IDs |

## Step 1. Collect the endpoint, the key and the model IDs

**What to do:** create a router account (or install the proxy), copy the base URL, store the key in an environment variable, and pull the live model list.

**Why:** every later step depends on three strings — base URL, key, model ID. Guessing the model ID is the single most common cause of a `404` two steps later, so read them from the API instead of from a blog post.

```bash
export ROUTER_BASE_URL="https://<router-base-url>/v1"
export ROUTER_API_KEY="<your-api-key>"

curl -s "$ROUTER_BASE_URL/models" \
  -H "Authorization: Bearer $ROUTER_API_KEY" \
  | jq -r '.data[].id' | sort | head -20
```

**Example output** (IDs are illustrative — yours will differ):

```
anthropic/<claude-model-id>
deepseek/<deepseek-model-id>
openai/<gpt-model-id>
zhipu/<glm-model-id>
```

**Why this works:** `/v1/models` is part of the OpenAI-compatible surface, so any router that claims compatibility must answer it. If you get HTML back instead of JSON, the base URL is wrong.

Write the four IDs you plan to use into a local file so the later steps stay reproducible:

```bash
cat > models.env <<'EOF'
CLAUDE_MODEL=<id-from-the-list-above>
GPT_MODEL=<id-from-the-list-above>
DEEPSEEK_MODEL=<id-from-the-list-above>
GLM_MODEL=<id-from-the-list-above>
EOF
```

**How to check:** `source models.env && echo $CLAUDE_MODEL` prints the ID, not an empty line.

Verification checklist for the router's docs page — tick all six before spending money:

- [ ] The model list contains all four families you need
- [ ] Free trial or free-tier conditions are stated explicitly, not implied
- [ ] Price per 1M input and output tokens is listed per model
- [ ] Rate limits (requests/minute, tokens/minute) are documented
- [ ] Prompt logging/retention policy is stated
- [ ] The OpenAI-compatible base path is documented (`/v1`, not `/api`)

## Step 2. Point one client at the router
![Illustration: Step 2. Point one client at the router](https://ai-release.org/guides/img/luchshie-api-routery-s-besplatnym-ili-deshevym-dostupom-en-2.jpg)


**What to do:** configure the OpenAI Python SDK with the router's base URL, then — if you chose the self-hosted proxy — describe all four models in one YAML file.

**Why:** a single client with a `base_url` override replaces four vendor SDKs. Swapping models becomes a string change, and a fallback becomes a retry, not a refactor.

```python
import os
from openai import OpenAI

client = OpenAI(
    base_url=os.environ["ROUTER_BASE_URL"],
    api_key=os.environ["ROUTER_API_KEY"],
    timeout=60.0,
)

MODELS = {
    "claude": os.environ["CLAUDE_MODEL"],
    "gpt": os.environ["GPT_MODEL"],
    "deepseek": os.environ["DEEPSEEK_MODEL"],
    "glm": os.environ["GLM_MODEL"],
}

def ask(family: str, prompt: str) -> str:
    r = client.chat.completions.create(
        model=MODELS[family],
        messages=[{"role": "user", "content": prompt}],
        max_tokens=128,
    )
    print(family, r.usage.prompt_tokens, r.usage.completion_tokens)
    return r.choices[0].message.content

print(ask("deepseek", "Reply with the single word: ready"))
```

**Example:** running it prints `deepseek 12 1` followed by `ready` — the three numbers are family, input tokens and output tokens. Those token counts are what you multiply by the per-1M prices from Step 1 to get the real cost of a call.

**Why this works:** `base_url` is the only field that changes; the request body stays in the OpenAI schema, and the router rewrites it into each vendor's native format.

If you run the self-hosted proxy instead, keep every credential on the server and give clients only a local key:

```yaml
model_list:
  - model_name: claude
    litellm_params:
      model: anthropic/<anthropic-model-id>
      api_key: os.environ/ANTHROPIC_API_KEY
  - model_name: gpt
    litellm_params:
      model: openai/<openai-model-id>
      api_key: os.environ/OPENAI_API_KEY
  - model_name: deepseek
    litellm_params:
      model: deepseek/<deepseek-model-id>
      api_key: os.environ/DEEPSEEK_API_KEY
  - model_name: glm
    litellm_params:
      model: <provider-prefix>/<glm-model-id>
      api_key: os.environ/ZHIPU_API_KEY
```

```bash
litellm --config config.yaml --port 4000
```

**Why this works:** the proxy translates the OpenAI schema into each vendor's API and maps `model_name` to a real model ID, so your application only ever sends `claude` or `glm`. The vendor prefix for GLM and the exact CLI flag are version-specific — check the proxy's documentation if startup fails.

**How to check:** `curl -s localhost:4000/v1/models -H "Authorization: Bearer <local-key>" | jq '.data | length'` returns `4`.

## Step 3. Verify answers, latency and cost
![Illustration: Step 3. Verify answers, latency and cost](https://ai-release.org/guides/img/luchshie-api-routery-s-besplatnym-ili-deshevym-dostupom-en-3.jpg)


**What to do:** run a smoke test across all four families, measure round-trip time, and confirm the router returns a usage block — then break a key on purpose to see the error shape.

**Why:** a router can list a model and still fail on call (provider outage, quota exhausted, missing permission). You want that discovered in a test, not in a demo.

```bash
for m in "$CLAUDE_MODEL" "$GPT_MODEL" "$DEEPSEEK_MODEL" "$GLM_MODEL"; do
  printf '%s ' "$m"
  curl -s -o /dev/null -w '%{http_code} %{time_total}s\n' \
    "$ROUTER_BASE_URL/chat/completions" \
    -H "Authorization: Bearer $ROUTER_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"model\":\"$m\",\"messages\":[{\"role\":\"user\",\"content\":\"Say OK\"}],\"max_tokens\":8}"
done
```

**Example output:**

```
anthropic/<claude-model-id> 200 1.842s
openai/<gpt-model-id> 200 0.914s
deepseek/<deepseek-model-id> 200 2.307s
zhipu/<glm-model-id> 200 1.115s
```

Four `200` lines mean the router is working end to end. Note the timings in a comment next to your config — they drift, and a sudden 10x jump usually means the router fell back to a slower provider silently.

**Why this works:** `-o /dev/null` throws away the body and `-w` prints only the status code and total time, so you get a clean matrix without parsing JSON.

**How to check success on screen:**
- every line starts with `200`
- `ask("claude", "hi")` from Step 2 returns text, not an exception
- the usage block prints non-zero token counts
- an intentionally wrong key returns `401` with a JSON error body, confirming errors are not masked

## How to choose

- **You need a working demo today and have no vendor accounts:** hosted aggregator — one key, one base URL, done.
- **You already pay Anthropic/OpenAI/DeepSeek/Zhipu directly, or prompts cannot leave your infrastructure:** self-hosted proxy on port `4000`.
- **Cost is the deciding factor:** price all four models with the token counts from Step 2 against the current pricing page; the cheapest model for a summarisation task is often not the one you would pick for code. For model-level trade-offs outside routing, see [Best AI models and neural networks in 2026](https://ai-release.org/guides/luchshie-nejroseti-i-modeli-2026.html?utm_source=tg&utm_medium=channel&utm_campaign=guide_inline&utm_content=guide_to_guide).
- **You are wiring the router into an IDE or CLI agent:** check that the tool accepts a custom base URL before you commit — details in [AI for programmers: coding assistants in 2026](https://ai-release.org/guides/ii-dlya-koda.html?utm_source=tg&utm_medium=channel&utm_campaign=guide_inline&utm_content=guide_to_guide).

## Troubleshooting

**Problem. Authentication fails on every model even though the key looks correct**

- Error: `Error code: 401 - {'error': {'message': 'Invalid API key', 'type': 'authentication_error'}}`
- Cause: the key was copied with a trailing newline or quotes, or it belongs to a different environment than the base URL (test key against production URL).
- Solution: `printf '%s' "$ROUTER_API_KEY" | wc -c` and compare with the key length shown in the dashboard; re-export with `export ROUTER_API_KEY="<key>"` (no spaces around `=`, no quotes inside the value), then rerun the Step 1 `curl`.

**Problem. One model returns 404 while the others answer**

- Error: `Error code: 404 - {'error': {'message': 'model not found', 'type': 'invalid_request_error'}}`
- Cause: the model ID was typed from memory or copied from an old post; routers rename IDs and vendors retire snapshots.
- Solution: re-run `curl -s "$ROUTER_BASE_URL/models" | jq -r '.data[].id' | grep -i glm` and paste the exact string into `models.env`. Never hand-write the vendor prefix in the self-hosted config.

**Problem. Long prompts time out**

- Error: `openai.APITimeoutError: Request timed out.`
- Cause: the client default timeout is short for long generations, or the router is retrying a failed provider in the background.
- Solution: raise `timeout=60.0` (or higher) in the client, cut `max_tokens` for the test call, and re-run the Step 3 timing loop to see whether the delay is one model or all four.

## Summary and next steps

You now have one OpenAI-compatible endpoint that reaches Claude, GPT, DeepSeek and GLM, plus a repeatable smoke test that reports status codes and latency per model. Next, add a fallback list in your client so a failing model retries on a second one, and re-check `/v1/models` and the pricing page before every release.

## FAQ

**What is an API router in one sentence?**
It is a single HTTP endpoint that forwards your request to different model vendors, so your code uses one URL, one key and one request format instead of four.

**Is an OpenAI-compatible router slower than calling the vendor directly?**
It adds one network hop, which is visible as extra latency in the `time_total` column of the Step 3 loop; measure your own numbers, since routing and retry behaviour differ per provider.

**Can I use a router with free-tier access for production?**
Only after reading the router's rate limits and retention policy — free tiers usually cap requests per minute and may log prompts; the tokens-per-minute figure is on the pricing or limits page.

**Why does the same prompt give different token counts on different models?**
Each vendor tokenises text differently, so `usage.prompt_tokens` varies; always multiply the returned counts by that specific model's per-1M price rather than assuming one rate.
