← All posts
JUL 2026

Kimi K3 & GLM Coding Plans in Claude Code (Flat-Rate, No Per-Token Billing)

Use Moonshot's Kimi K3 and Z.AI's GLM coding plan subscriptions in Claude Code without per-token API billing, through the open-source Ferrox LLM gateway. Full setup guide.

Abstract visualization of Claude Code routing API traffic through the Ferrox LLM gateway to the Kimi and GLM coding plan providers
On this page

A single Claude Code session can burn millions of tokens. At per-token API prices, heavy agentic use gets expensive fast. Moonshot AI (Kimi) and Z.AI (GLM) both sell flat-rate coding plan subscriptions that are far cheaper than pay-as-you-go billing. The catch: Claude Code speaks Anthropic’s API protocol, and Kimi’s coding plan is OpenAI-compatible only.

This guide shows how to use both the Kimi K3 and GLM coding plans in Claude Code with zero per-token charges, using Ferrox, a free, open-source LLM gateway written in Rust that translates between API dialects.

The protocol problem

Claude Code can talk to any Anthropic-compatible endpoint via ANTHROPIC_BASE_URL. Here’s how the two coding plans line up:

ProviderCoding plan endpointProtocolWorks with Claude Code directly?
Z.AI (GLM)https://api.z.ai/api/anthropicAnthropicYes
Moonshot (Kimi)https://api.kimi.com/coding/v1OpenAI onlyNo

Moonshot does run an Anthropic-compatible endpoint at https://api.moonshot.ai/anthropic, but coding-plan keys are rejected there; that route bills the standard pay-as-you-go account. So for Kimi you need something in the middle that speaks Anthropic on one side and OpenAI on the other.

Enter Ferrox

Ferrox is a stateless, MIT-licensed LLM API gateway written in Rust. It normalises every provider into one internal format and re-exposes it in both the OpenAI and Anthropic dialects:

One gateway, one local endpoint, one auth token in your Claude Code config. Beyond protocol translation you get multi-provider routing (failover, round-robin, weighted) across Anthropic, OpenAI, Gemini, and AWS Bedrock, virtual keys with per-model access control, rate limiting, circuit breakers, and Prometheus metrics.

Step 1: Configure Ferrox

Create config/local.yaml. Never commit API keys; reference environment variables:

providers:
  # Z.AI coding plan is served over the Anthropic-native endpoint.
  # Do NOT use https://api.z.ai/api/paas/v4; that route bills
  # the pay-as-you-go balance instead of your coding plan.
  - name: zai
    type: anthropic
    api_key: "${Z_AI_API_KEY}"
    base_url: "https://api.z.ai/api/anthropic"

  # Kimi coding plan is OpenAI-compatible only.
  # Do NOT use https://api.moonshot.ai/anthropic; coding-plan keys are rejected there.
  - name: moonshot
    type: openai
    api_key: "${MOONSHOT_API_KEY}"
    base_url: "https://api.kimi.com/coding/v1"

models:
  - alias: glm-5.2
    routing:
      strategy: failover
      targets:
        - provider: zai
          model_id: "glm-5.2"

  - alias: glm-4.5-air          # cheap/fast, good for the Haiku slot
    routing:
      strategy: failover
      targets:
        - provider: zai
          model_id: "glm-4.5-air"

  - alias: k3                   # Kimi K3, 1,048,576 token context
    routing:
      strategy: failover
      targets:
        - provider: moonshot
          model_id: "k3"

virtual_keys:
  - key: "${PROXY_KEY:-sk-local-dev}"
    name: claude-code
    allowed_models: ["*"]
    rate_limit:
      requests_per_minute: 120
      burst: 20

Two things to note. Providers point at the coding plan endpoints, not the default API endpoints; getting base_url wrong is the top cause of “insufficient balance” errors. And the virtual key is what Claude Code authenticates with, so your real provider keys never enter any Claude Code settings file.

Step 2: Run Ferrox

Gateway only, no database or Redis needed:

docker run -d --name ferrox --restart unless-stopped \
  -p 127.0.0.1:2333:8080 \
  -e Z_AI_API_KEY -e MOONSHOT_API_KEY -e PROXY_KEY \
  -v "$(pwd)/config/local.yaml:/app/config/local.yaml:ro" \
  ghcr.io/shaharia-lab/ferrox:latest --config /app/config/local.yaml

-e VAR without a value inherits the variable from your shell, so keys stay out of shell history and docker inspect output. Verify:

curl http://localhost:2333/healthz                     # {"status":"ok"}
curl http://localhost:2333/anthropic/v1/models \
  -H "Authorization: Bearer sk-local-dev"              # lists your aliases

No Docker? Binaries for macOS and Linux are on GitHub Releases, or brew install shaharia-lab/tap/ferrox.

Step 3: Point Claude Code at Ferrox

Claude Code appends /v1/messages to ANTHROPIC_BASE_URL, and Ferrox serves its Anthropic surface under /anthropic. So the base URL is http://localhost:2333/anthropic. Keep one settings file per backend:

~/.claude/settings_kimi.json

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "env": {
    "ANTHROPIC_BASE_URL": "http://localhost:2333/anthropic",
    "ANTHROPIC_AUTH_TOKEN": "sk-local-dev",
    "API_TIMEOUT_MS": "3000000",
    "ANTHROPIC_MODEL": "k3",
    "ANTHROPIC_DEFAULT_OPUS_MODEL": "k3",
    "ANTHROPIC_DEFAULT_SONNET_MODEL": "k3",
    "ANTHROPIC_DEFAULT_HAIKU_MODEL": "k3",
    "CLAUDE_CODE_SUBAGENT_MODEL": "k3",
    "CLAUDE_CODE_AUTO_COMPACT_WINDOW": "1048576"
  }
}

~/.claude/settings_glm.json

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "env": {
    "ANTHROPIC_BASE_URL": "http://localhost:2333/anthropic",
    "ANTHROPIC_AUTH_TOKEN": "sk-local-dev",
    "API_TIMEOUT_MS": "3000000",
    "ANTHROPIC_DEFAULT_OPUS_MODEL": "glm-5.2",
    "ANTHROPIC_DEFAULT_SONNET_MODEL": "glm-5.2",
    "ANTHROPIC_DEFAULT_HAIKU_MODEL": "glm-4.5-air"
  }
}

ANTHROPIC_AUTH_TOKEN is the Ferrox virtual key, not a provider key. CLAUDE_CODE_AUTO_COMPACT_WINDOW sets how much context Claude Code uses before auto-compacting; set it to the model’s real window (K3 is 1,048,576 tokens).

Run it:

claude --settings ~/.claude/settings_kimi.json
claude --settings ~/.claude/settings_glm.json

Every request now flows through Ferrox and bills against your flat-rate subscription.

Mixing both plans in one session

Ferrox routes per model alias, so one settings file can spread Claude Code’s model slots across both subscriptions. For example, K3’s huge context for the main loop and cheap GLM 4.5 Air for the background slot:

"ANTHROPIC_DEFAULT_OPUS_MODEL": "k3",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "k3",
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "glm-4.5-air"

You can also give an alias multiple targets so one plan falls back to the other:

  - alias: primary
    routing:
      strategy: failover
      targets:
        - provider: moonshot
          model_id: "k3"
        - provider: zai
          model_id: "glm-5.2"

Clients only ever see your aliases, so you can repoint primary at a different vendor without touching any Claude Code settings file.

Troubleshooting

Insufficient balance or no resource package (Z.AI, HTTP 429, code 1113): you’re on the pay-as-you-go route, not the coding plan. base_url must be https://api.z.ai/api/anthropic with type: anthropic, not /api/paas/v4.

Invalid Authentication from Moonshot: coding-plan keys only work against https://api.kimi.com/coding/v1. They are rejected by api.moonshot.ai and api.moonshot.cn on both routes.

There's an issue with the selected model (…) in Claude Code: the model name was rejected locally before reaching Ferrox. Use plain alias names; Claude Code strips its [1m] suffix before sending, so set the window with CLAUDE_CODE_AUTO_COMPACT_WINDOW instead.

Model alias '…' is not configured (HTTP 404): Ferrox matches aliases exactly. Check GET /anthropic/v1/models for what it actually serves.

Empty responses with finish_reason: "length": K3 is a reasoning-heavy model; a small max_tokens can be consumed entirely by reasoning. Allow a few hundred tokens.

When in doubt, docker logs ferrox shows every routed request with the resolved alias, provider, upstream model ID, and status.

Ferrox for teams and organizations

The same setup scales to a whole team:

  • Centralized credentials. Provider keys live in one deployment, not fifty settings files. Rotate in one place.
  • Scoped access. Each developer or CI job gets a virtual key with per-model access and its own rate limit. Revoke one key without touching anyone else.
  • Provider independence. Clients only see aliases, so you can swap or add providers (Gemini, Bedrock, a self-hosted model) behind the same endpoint with zero client changes.
  • Production-grade ops. Stateless and horizontally scalable, with Prometheus metrics, structured logs, and OpenTelemetry tracing built in.

Ferrox is MIT-licensed, single-binary Rust, and runs anywhere Docker does. If it’s useful to you, a star on GitHub goes a long way.

FAQ

Can I use the Kimi K3 coding plan in Claude Code? Not directly. Kimi’s coding plan is OpenAI-compatible only, and Claude Code speaks the Anthropic protocol. Ferrox bridges the two.

Can I use the Z.AI GLM coding plan in Claude Code? Yes, directly via https://api.z.ai/api/anthropic. Running it through Ferrox adds virtual keys, rate limiting, failover, and unified metrics.

Does Claude Code usage tracking still work through Ferrox? Yes. Claude Code receives normal Anthropic-style responses with token counts, so /cost and /usage work. Ferrox adds server-side Prometheus metrics across all keys and models.

Is Ferrox free? Yes, open source under the MIT license, with binaries, a Homebrew tap, and a Docker image.

Wrapping up

Flat-rate coding plans are the pricing model agentic coding needed. With Ferrox in the middle, Claude Code isn’t locked out of them just because a provider chose a different API dialect. One YAML file, one Docker container, one settings file per plan, and Kimi K3’s million-token context and GLM 5.2 become everyday model slots in Claude Code. The full configuration reference is in the Ferrox docs.