# ZCode Custom Provider Setup (Desktop & CLI)

> **Last verified**: 2026-11-10 · 📄 Per official docs (ZCode desktop v3.17.2, dated 2026-11-03 in the README and changelog) · ✅ QCode connection tested with ZCode CLI 0.17.1 (2026-11-10)

Yes, ZCode can use your own API key and endpoint. In the desktop app you add it under **Add Provider**; the open-source ZCode CLI reads it from `~/.zcode/v2/provider_config.json`. As of 2026-11-10, tested with ZCode CLI 0.17.1: QCode works on all three protocols (Anthropic Messages, OpenAI Chat Completions, OpenAI Responses), and no Z.ai or BigModel sign-in is needed. The desktop steps follow the official docs.

## At a glance

| Item | Details |
|---|---|
| What it is | In its README's words, "an AI coding workspace with desktop, browser, and terminal interfaces". Apache-2.0, from Z.ai (Zhipu); repository [zai-org/ZCode](https://github.com/zai-org/ZCode) |
| Models you can use | Claude ✅ · GPT ✅ · GLM / Kimi / DeepSeek / Qwen ✅ · Gemini ❌ (QCode does not offer Gemini models for now) |
| Anthropic Messages | `https://api.qcode.cc/api` (ZCode appends `/v1/messages`) · ✅ CLI tested |
| OpenAI Chat Completions | `https://api.qcode.cc/openai/v1` · ✅ CLI tested |
| OpenAI Responses | `https://api.qcode.cc/openai/v1` · ✅ CLI tested; the desktop docs do not list this protocol |
| Desktop app | **Manage Models** → **Settings -> Model Settings** → **Add Provider**; file `~/.zcode/v2/config.json` |
| ZCode CLI | built from source; file `~/.zcode/v2/provider_config.json` (`access.apiKey`, `api.type`, `api.baseUrl`) |
| Official docs | [Connect Models](https://zcode.z.ai/en/docs/configuration) · [Install](https://zcode.z.ai/en/docs/install) · [FAQ](https://zcode.z.ai/en/docs/qa) · [CLI guide](https://github.com/zai-org/ZCode/blob/main/apps/zcode-cli/docs/usage/README.md) |

## Which protocol

ZCode has three ways to get a model, and they differ in where the quota comes from:

| Way | What you do | Where usage is counted |
|---|---|---|
| Sign in with an account | Choose Z.ai or BigModel on the welcome screen | The account's plan: "If your account has a GLM Coding Plan, ZCode uses the plan and quota from that account directly." |
| API Key on the Z.ai / BigModel provider page | Switch that page to API Key mode; it shows an **OpenAI Base URL** and an **Anthropic Base URL** field | The Z.ai or BigModel key you enter |
| Custom provider | **Add Provider** (desktop) or `provider_config.json` (CLI) with your own endpoint and key | The service you point it at, here QCode |

This page covers the third way. QCode serves Claude only on the Anthropic protocol and GPT only on the OpenAI protocols; GLM, Kimi, DeepSeek and Qwen work on Anthropic and OpenAI Chat (see [Endpoints & API Paths](/docs/getting-started/endpoints-and-api-paths)):

| Protocol | QCode Base URL | Models | CLI `api.type` |
|---|---|---|---|
| Anthropic Messages | `https://api.qcode.cc/api` | Claude, GLM / Kimi / DeepSeek / Qwen | `anthropic-messages` |
| OpenAI Chat Completions | `https://api.qcode.cc/openai/v1` | GPT, GLM / Kimi / DeepSeek / Qwen | `openai-chat-completions` |
| OpenAI Responses | `https://api.qcode.cc/openai/v1` | GPT | `openai-responses` |

ZCode adds the API path itself. In the CLI source (`normalizeAnthropicBaseURL`), an Anthropic Base URL that does not end in `/v1` gets `/v1`, and the SDK then appends `/messages`, so `https://api.qcode.cc/api` reaches `/api/v1/messages`. For the two OpenAI types it appends `/chat/completions` or `/responses` to the Base URL, which is why both values end in `/openai/v1`. Do not add a trailing `/`. The same key works on `us.qcode.cc` and `asia.qcode.cc`; swap the host and keep the path.

## Desktop app (📄 per official docs)

The steps below follow the official docs for v3.17.2. The same QCode addresses passed the ZCode CLI test; in the desktop app, your first test message confirms the connection.

### Install

The official install page says ZCode "Supports macOS (Apple Silicon / Intel), Windows (x64 / ARM64), and Linux (x64, ARM64, AppImage, DEB, RPM)." and marks v3.17.2 as the latest version.

- macOS: open the downloaded `ZCode.dmg` and drag ZCode.app into the Applications folder. If macOS says the app is damaged, the official fix is `xattr -dr com.apple.quarantine /Applications/ZCode.app`.
- Windows: download the installer, double-click it and follow the wizard.
- Linux: download the `.AppImage`, `.deb` or `.rpm`; for an AppImage run `chmod +x ZCode-*.AppImage`.

Download the installers from [zcode.z.ai](https://zcode.z.ai/en/docs/install).

### Add QCode as a provider

The docs show providers that fill one endpoint and a DeepSeek example that fills both, but they do not say how ZCode chooses between two endpoints of one provider. This page therefore uses one provider per protocol:

| Provider name | Endpoint field | Value | Model IDs (examples) |
|---|---|---|---|
| `QCode Claude` | Anthropic endpoint | `https://api.qcode.cc/api` | `claude-sonnet-5-5`, `claude-opus-5-5`, `claude-haiku-5-5` |
| `QCode OpenAI` | OpenAI endpoint | `https://api.qcode.cc/openai/v1` | `gpt-6.1-sol`, `deepseek-v4-flash`, `glm-5.3`, `kimi-k3`, `qwen3.8-max` |

1. Open ZCode, click the model name in the chat box, then **Manage Models** at the bottom of the list. This opens **Settings -> Model Settings**. On a first launch without a usable model, the welcome screen's **Use API Key** also leads to the model provider settings.
2. Click **Add Provider** at the bottom of the provider list on the left.
3. For the first provider:
   - Name: `QCode Claude` (the name is yours to choose; the official page suggests names such as claude or deepseek)
   - Anthropic endpoint: `https://api.qcode.cc/api` (the official wording is "Choose the vendor Base URL from the dropdown, or enter the API base URL manually"; enter it manually)
   - API Key: your QCode key (starts with `cr_`)
4. Click **Add Model** and enter each model ID, for example `claude-sonnet-5-5`. The official text: "click Add Model and enter the model IDs supported by that service".
5. Turn on the enable switch ("Turn on the enable switch to start using it") and save.
6. Repeat with Name `QCode OpenAI`, OpenAI endpoint `https://api.qcode.cc/openai/v1`, the same key and models such as `gpt-6.1-sol` and `deepseek-v4-flash`.

Use the model IDs listed on [qcode.cc/models](https://qcode.cc/models), character for character; per-model rates are listed there too. The Chinese models also work on the Anthropic endpoint if you prefer to keep them in `QCode Claude`. The desktop docs name the Anthropic and OpenAI endpoints; they do not list a separate Responses option, so for Responses use the CLI below.

### The desktop config file

The official FAQ lists `~/.zcode/v2/config.json` as the file that holds "Model provider setup (API keys, base URLs, model lists)", so treat it as a secret and do not commit it. The page documents one rule about it: "a provider's options only recognizes connection settings such as apiKey, baseURL, apiKeyRequired, and headers; any other keys added by hand (e.g. reasoning_effort, vl_high_resolution_images) are silently ignored and never written into the request body." Set up providers in the UI rather than editing the file by hand. The FAQ also says terminal environment variables and the desktop model setup are separate entry points, and configuration is not synced automatically.

## ZCode CLI (✅ tested 2026-11-10)

As of 2026-11-10, tested with ZCode CLI 0.17.1: all three QCode protocols work through `~/.zcode/v2/provider_config.json`, without running `zcode login`.

### Build from source

The CLI is distributed as source code: the [quick start](https://github.com/zai-org/ZCode/blob/main/apps/zcode-cli/docs/usage/01-quickstart.md) builds it from the repository. It asks for Git, Node.js 24.14.0 and pnpm 10.33.2 (the repository's `mise.toml` is authoritative). Run the commands in the repository root:

```sh
git clone https://github.com/zai-org/ZCode.git
cd ZCode
pnpm install --frozen-lockfile
pnpm --filter @zcode/cli... build
node apps/zcode-cli/packages/cli/dist/zcode.cjs --version
node apps/zcode-cli/packages/cli/dist/zcode.cjs doctor --json
```

In the commands below, `zcode` stands for `node /absolute/path/to/zcode.cjs`; keep the files the build puts next to it.

### Write provider_config.json

Save this as `~/.zcode/v2/provider_config.json` and replace `cr_xxx` with your QCode key. It is the Anthropic setup from the test:

```json
{
  "schemaVersion": 1,
  "config": {
    "providerConfigRules": {
      "providerRules": [
        {
          "providerId": "qcode",
          "providerName": "QCode",
          "config": {
            "group": "standard-personal",
            "access": { "type": "api-key", "apiKey": "cr_xxx" },
            "api": {
              "type": "anthropic-messages",
              "baseUrl": "https://api.qcode.cc/api"
            },
            "personalModelIds": ["claude-haiku-5-5"]
          }
        }
      ]
    },
    "modelConfigRules": {
      "providerModelRules": [],
      "manualProviderModelRules": []
    },
    "defaultModelSelection": {
      "providerId": "qcode",
      "modelId": "claude-haiku-5-5"
    }
  }
}
```

For another protocol, change `api.type`, `api.baseUrl` and the model ID (in both `personalModelIds` and `defaultModelSelection.modelId`):

| Protocol | `api.type` | `api.baseUrl` | Tested model |
|---|---|---|---|
| Anthropic Messages | `anthropic-messages` | `https://api.qcode.cc/api` | `claude-haiku-5-5` ✅ |
| OpenAI Chat Completions | `openai-chat-completions` | `https://api.qcode.cc/openai/v1` | `deepseek-v4-flash` ✅ |
| OpenAI Responses | `openai-responses` | `https://api.qcode.cc/openai/v1` | `gpt-6.1-terra` ✅ |

Two points from the official CLI guide:

- The field is `api.baseUrl`, spelled differently from `options.baseURL` in the desktop file; the CLI reads `provider_config.json`, not `~/.zcode/v2/config.json`.
- The guide does not promise `${ENV}` substitution in `apiKey`, so the key sits in the file in plain text. Restrict the file and keep it out of Git:

```sh
chmod 600 ~/.zcode/v2/provider_config.json
```

### Run a non-interactive check

```sh
zcode --prompt "Reply with one word: ready. Do not call tools." \
  --cwd /path/to/project --mode plan --json --no-color
```

`--json` returns `sessionId`, `response` and run details; a `response` of `ready` means the provider works. Always pass `--mode`: without it, `--prompt` runs in `yolo` mode, which executes commands and edits files. Running `zcode` with no arguments starts the interactive TUI.

## Verify

1. Desktop: choose the new provider's model from the model selector in the chat box and send a short test instruction, as the official page advises ("send a short test instruction").
2. CLI: run the `--prompt` check above.
3. Open [probe.qcode.cc](https://probe.qcode.cc), enter your QCode key and check that the request appears with that model.
4. To test the key and path without ZCode:

```bash
KEY="cr_your_key"

# Anthropic Messages
curl -sS https://api.qcode.cc/api/v1/messages \
  -H "x-api-key: $KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{"model":"claude-haiku-5-5","max_tokens":32,
       "messages":[{"role":"user","content":"ping"}]}'

# OpenAI Chat Completions
curl -sS https://api.qcode.cc/openai/v1/chat/completions \
  -H "Authorization: Bearer $KEY" \
  -H "content-type: application/json" \
  -d '{"model":"deepseek-v4-flash","max_tokens":32,
       "messages":[{"role":"user","content":"ping"}]}'
```

## Troubleshooting

| Symptom | Cause | Fix |
|---|---|---|
| Desktop: Connect keeps loading | Official FAQ: the machine cannot reach the model service, or the key has no quota or model access | Check the network, then the key and the model ID |
| `model_not_available_on_endpoint` | A `claude-...` ID was added on an OpenAI endpoint or OpenAI `api.type` | Put Claude IDs on the Anthropic endpoint (`anthropic-messages` in the CLI) |
| 404 | Trailing `/`, or an OpenAI Base URL without `/v1` | Use the values above exactly and compare with the curl commands |
| CLI ignores your key or address | It reads `provider_config.json` with `api.baseUrl`, not the desktop `config.json` | Edit `~/.zcode/v2/provider_config.json` |
| CLI: a QCode address in `ZCODE_BASE_URL` has no effect | Official: `ZCODE_BASE_URL` concerns the product service endpoint, not the model API | Put the address in `api.baseUrl` |
| CLI: `${QCODE_API_KEY}` in `apiKey` is not resolved | Official: `${ENV}` substitution in `apiKey` is not promised | Write the key itself and `chmod 600` the file |
| CLI first run prints a notice that the "ZCode Built-in" refresh failed | Seen with 0.17.1; calls through your own provider still succeed, and later runs report it as skipped | No action needed |
| The top thinking level returns a 400 parameter error | Official: some third-party deployments only accept up to `xhigh` while ZCode sends `max` for DeepSeek V4 | Pick `high` instead: "Picking high instead works fine." |
| No fine-grained thinking levels for a model | Official: ZCode has no known level mapping for that model; "the setting has not been lost" | Use the simple on/off toggle |
| Desktop: `reasoning_effort` in `options` has no effect | Official: other keys are "silently ignored" | Use the levels in the UI |
| Images are dropped | Official example: GLM-5.2 on an OpenAI Chat-compatible endpoint "is treated as not supporting image input"; another endpoint or protocol can differ | Declare the model's image capability in its model configuration, or avoid images with that model |

ZCode converts the chosen thinking level for the endpoint: "OpenAI-compatible endpoints use the top-level reasoning_effort field, while Anthropic-compatible endpoints use thinking / effort."

## Known limitations

- The desktop part follows the official docs for v3.17.2; menu names can change between versions. The CLI part was tested with 0.17.1 and one model per protocol.
- The official page says that adding custom request parameters for third-party models is not supported yet.
- The desktop docs name the Anthropic and OpenAI endpoints; Responses is available through the CLI's `openai-responses`. QCode does not offer Gemini models for now.
- CLI: the key is stored in plain text in `provider_config.json`, and `--prompt` without `--mode` runs in `yolo` mode.

## Related

- [Endpoints & API Paths](/docs/getting-started/endpoints-and-api-paths) — protocol × model-family table
- [Tool Compatibility Overview](/docs/ide/tool-compatibility) — which tools speak which protocol
- [Kimi Code CLI](/docs/ide/kimi-code) — another terminal agent with Anthropic, OpenAI Chat and Responses providers
- [MiniMax Code](/docs/ide/minimax-code) — desktop app and `mcode` CLI with the same three API formats
- [DeepSeek Harness (dsh)](/docs/ide/deepseek-harness) — another agent harness with a custom model form
- [Chinese Models](/docs/usage/cn-models) — GLM / Kimi / DeepSeek / Qwen IDs and paths