# How do you use DeepSeek V4.1 Flash and Kimi K3 in opencode through a custom OpenAI-compatible provider?

Adapted from our opencode custom-provider tutorial [on dev.to](https://dev.to/cloudgpu_app/use-deepseek-v41-flash-and-kimi-in-opencode-via-a-custom-openai-compatible-provider-5co4).

# How do you use DeepSeek V4.1 Flash and Kimi K3 in opencode through a custom OpenAI-compatible provider?

You add a `provider` block to `opencode.json` that uses the `@ai-sdk/openai-compatible` package, set its `baseURL` to `https://cloudgpu.app/v1`, read the key from `{env:CGW_API_KEY}`, and list `deepseek-v4.1-flash` and `kimi-k3` under `models`; opencode then offers them as `cloudgpu/deepseek-v4.1-flash` and `cloudgpu/kimi-k3`.

The rest of this post is the copy-paste version of that sentence, with each opencode behaviour traced to the opencode docs.

Disclosure: I work on CloudGPU.

## What this is based on

We ran this provider block in opencode on 2026-10-26 and both headline models replied. Everything else below about opencode itself (the `/models` screen, `/connect`, the `limit` block, the default model) follows the opencode docs, so read "according to the opencode docs" literally.

## The four values at a glance

| What | Value |
|---|---|
| npm package | `@ai-sdk/openai-compatible` |
| Base URL | `https://cloudgpu.app/v1` (keep the `/v1`) |
| API key | a `cgw-sk-...` key, exported as `CGW_API_KEY` |
| Model IDs | `deepseek-v4.1-flash`, `kimi-k3`, `kimi-k2.6`, `glm-5.3-flash` |

The model IDs were checked against the model table on the live API page on 2026-10-27.

## Step 1: Export the key

According to the opencode docs, config files support `{env:VARIABLE_NAME}` substitution, so the key can stay out of the JSON file:

```bash
export CGW_API_KEY="cgw-sk-..."   # put this in ~/.bashrc or ~/.zshrc to keep it
```

## Step 2: Add the custom provider to opencode.json

Put this in `opencode.json` in your project root. According to the opencode docs, the global file lives at `~/.config/opencode/opencode.json`, the project file overrides it, and "configuration files are merged together, not replaced", so the same block also works globally.

```json
{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "cloudgpu": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "CloudGPU",
      "options": {
        "baseURL": "https://cloudgpu.app/v1",
        "apiKey": "{env:CGW_API_KEY}"
      },
      "models": {
        "deepseek-v4.1-flash": { "name": "DeepSeek V4.1 Flash" },
        "kimi-k3": { "name": "Kimi K3" },
        "kimi-k2.6": { "name": "Kimi K2.6" },
        "glm-5.3-flash": { "name": "GLM-5.3 Flash" }
      }
    }
  }
}
```

Field guide, according to the opencode docs (Providers → Custom provider):

- **`cloudgpu`** is the provider ID. You choose it, and it becomes the prefix in `cloudgpu/<model>`.
- **`npm`**: "`@ai-sdk/openai-compatible` for OpenAI-compatible providers (for `/v1/chat/completions`)".
- **`options.baseURL`** is the API endpoint; **`options.apiKey`** is optional "if not using auth".
- **`models`**: each key must be the exact ID the endpoint serves. `name` is only the label in the UI.

Only want the two headline models? Delete the `kimi-k2.6` and `glm-5.3-flash` lines.

### Alternative: `/connect` instead of `apiKey`

According to the opencode docs, you can run `/connect`, scroll to **Other**, enter the provider ID (`cloudgpu`), and paste the key. The docs warn that this "only stores a credential", so you still need the `provider` block, just without the `apiKey` line.

## Step 3: Choose a model

Check from the command line that opencode sees the provider. According to the opencode CLI docs, `opencode models [provider]` lists models in `provider/model` form:

```bash
opencode models cloudgpu
```

The output should look like this (illustrative, not a captured run):

```text
cloudgpu/deepseek-v4.1-flash
cloudgpu/glm-5.3-flash
cloudgpu/kimi-k2.6
cloudgpu/kimi-k3
```

Then pick one with `-m` in `provider/model` form. The dot in `v4.1` is part of the ID:

```bash
opencode -m cloudgpu/deepseek-v4.1-flash
opencode run -m cloudgpu/kimi-k3 "Explain what this repo's main entry point does"
```

Inside the TUI, according to the opencode docs, you "run the `/models` command and your custom provider and models will appear in the selection list". To make one the default, the opencode models docs use a top-level `"model"` key in `provider_id/model_id` form, here `"model": "cloudgpu/deepseek-v4.1-flash"`.

**Which one for what?** There are no benchmarks here, so try them on your own repo. All four are in the config, so comparing them takes one switch.

## Step 4: Sanity-check the endpoint outside opencode

If opencode misbehaves, take it out of the loop. First, list the IDs your key can use:

```bash
curl https://cloudgpu.app/v1/models \
  -H "Authorization: Bearer $CGW_API_KEY"
```

Without the header this returns `401` with `missing_authorization`, which is expected. The API docs list it as "No Authorization header." (As of 2026-10-27, see [/api/docs](https://cloudgpu.app/api/docs).)

Then send one chat request with the `openai` Python package:

```python
# pip install openai
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://cloudgpu.app/v1",
    api_key=os.environ["CGW_API_KEY"],
)

for model in ["deepseek-v4.1-flash", "kimi-k3"]:
    resp = client.chat.completions.create(
        model=model,
        messages=[{"role": "user", "content": "Reply with: ok"}],
    )
    print(model, resp.choices[0].finish_reason, repr(resp.choices[0].message.content))
```

If a model comes back with empty or `None` content and `finish_reason` is `"length"`, the reply ran out of output tokens: leave `max_tokens` unset or set it higher.

## Troubleshooting

**1. The model doesn't show up, or you get `400 model_not_found`.** The keys under `models` must match the IDs from `GET /v1/models` character for character. Watch for short aliases (`deepseek-flash`), a missing version segment (`deepseek-v4-flash` vs `deepseek-v4.1-flash`) and capital letters. Also check that the provider ID is the same in all three places: the `provider` key, the ID typed into `/connect` (if you used it), and the `cloudgpu/` prefix. According to the opencode docs, `opencode auth list` shows which credentials are stored.

**2. The base URL is wrong.** The AI SDK docs describe `baseURL` as the URL prefix for API calls, and their example sends chat requests to `<baseURL>/chat/completions`:

```text
https://cloudgpu.app/v1                     correct
https://cloudgpu.app                        missing /v1
https://cloudgpu.app/v1/chat/completions    too specific
```

**3. An error asking for an `Authorization: Bearer` header.** According to the opencode docs, an unset `{env:...}` variable "will be replaced with an empty string", so the request goes out without a key. Check the variable in the shell you launch opencode from:

```bash
echo "${CGW_API_KEY:+set}"   # prints "set" if the variable is present
```

After editing `~/.bashrc` or `~/.zshrc`, open a new terminal or `source` the file. IDE terminals and desktop launchers may not read your shell profile.

**4. Empty replies.** Check `finish_reason` as in Step 4. In opencode, the per-model knob the docs describe is the optional `limit` block (`limit.context` = "maximum input tokens the model accepts", `limit.output` = "maximum tokens the model can generate"). If you add it, use real values from the model provider's docs, not guesses.

**5. `401 invalid_api_key`, `402 insufficient_balance` or `429 rate_limit_exceeded`.** The CloudGPU API docs describe them like this (As of 2026-10-27, see [/api/docs](https://cloudgpu.app/api/docs)):

- `401` `invalid_api_key`: "Key unknown or revoked."
- `402` `insufficient_balance`: "Top up."
- `429` `rate_limit_exceeded`: "Per-minute or per-day limit hit."

The documented rate limits are "Per API key, per minute: 100 requests" and "Per account, per day: 10,000 requests", and the docs add: "These defaults exist to stop abuse during the public beta. Contact us if you need them raised — happy to do it for any genuine workload, just need to know the use case."

## Paying for it

Usage is billed per token from a prepaid balance (card, Alipay, Google Pay, Apple Pay or USDT). Keys, the model table and per-model rates are on the [CloudGPU API page](https://cloudgpu.app/api?utm_source=hashnode&utm_medium=article&utm_campaign=202611_seg04_codingagent&utm_content=hashnode_opencode).

## FAQ

**Which npm package does an OpenAI-compatible custom provider use in opencode?**
`@ai-sdk/openai-compatible`. According to the opencode docs, it's the package for providers that use `/v1/chat/completions`.

**What base URL goes in `options.baseURL`?**
`https://cloudgpu.app/v1`, with `/v1` and nothing after it.

**Can the model ID contain a dot, like `deepseek-v4.1-flash`?**
Yes. Use it exactly as listed, in `provider/model` form: `-m cloudgpu/deepseek-v4.1-flash`.

**Why does a model sometimes return an empty answer?**
Check `finish_reason`. If it is `"length"`, the reply ran out of output tokens; raise `max_tokens` or leave it unset.

**Do I have to put the API key in `opencode.json`?**
No. Use `"apiKey": "{env:CGW_API_KEY}"` so the file only holds a reference. According to the opencode docs, `/connect` can store the credential instead.

**Are there rate limits?**
Yes. The API docs list "Per API key, per minute: 100 requests" and "Per account, per day: 10,000 requests", and say: "These defaults exist to stop abuse during the public beta. Contact us if you need them raised — happy to do it for any genuine workload, just need to know the use case." As of 2026-10-27, see [/api/docs](https://cloudgpu.app/api/docs).
