opencode is a terminal-native coding agent that speaks the OpenAI chat completions protocol. The opencode OpenAI-compatible API setup boils down to pointing it at a base_url, supplying an API key, and declaring which model identifiers the endpoint exposes. This post walks through a working configuration that targets any OpenAI-compatible backend, including a multi-provider gateway, and shows how to verify the connection before you trust it with a refactor.
Step 1: Install opencode
Use the official install script or build from source. The binary lands in your PATH and reads config from ~/.config/opencode/ by default.
curl -fsSL https://opencode.ai/install | bash
# or, if you have Go 1.22+:
go install github.com/opencode-ai/opencode@latest
Verify the install:
opencode --version
If that prints a semver, you are ready to configure.
Step 2: Create the config file
opencode looks for opencode.json in the current directory or under $XDG_CONFIG_HOME/opencode/. I prefer a user-global file so every project inherits the same provider definitions.
mkdir -p ~/.config/opencode
touch ~/.config/opencode/opencode.json
Start with an empty object. We will populate the providers map.
{
"providers": {}
}
Step 3: Define an OpenAI-compatible provider
The opencode OpenAI-compatible API setup requires a provider entry of "type": "openai". opencode treats any such entry as speaking the /v1/chat/completions contract. Specify base_url without a trailing slash, pull the key from the environment, and list the models you intend to use. Avoid relying on model auto-discovery; explicit models prevent a failed GET /v1/models call from breaking startup.
{
"providers": {
"local-gateway": {
"type": "openai",
"base_url": "https://api.your-gateway.com/v1",
"api_key": "$OPENCODE_API_KEY",
"models": {
"gpt-4o-mini": {},
"claude-3-5-sonnet": {}
}
}
}
}
If you run a local vLLM or Ollama instance, swap base_url for http://localhost:8000/v1 and set api_key to a dummy string if the server does not enforce auth.
Step 4: Use a gateway for broad model access
Managing 10 provider keys is busywork. If you point opencode at a single OpenAI-compatible endpoint like n4n.ai, you get one base URL that addresses 240+ models and automatic fallback when a provider is rate-limited or degraded. The config does not change shape—only the base_url and the model identifiers.
{
"providers": {
"n4n": {
"type": "openai",
"base_url": "https://api.n4n.ai/v1",
"api_key": "$OPENCODE_API_KEY",
"models": {
"openai/gpt-4o-mini": {},
"anthropic/claude-3-5-sonnet": {},
"meta-llama/llama-3.1-70b-instruct": {}
}
}
}
}
Gateways such as n4n.ai forward provider cache-control hints and meter per-token usage, which keeps costs observable when opencode fires dozens of tool calls per session.
Step 5: Set environment variables
Never hardcode secrets in JSON. Export the key the provider expects:
export OPENCODE_API_KEY="sk-your-real-key"
For project-local overrides, drop the same line in a .env file and prefix your launch command with env or use a wrapper. opencode does not auto-load .env, so do it yourself:
set -a; source .env; set +a
opencode
Step 6: Select a model and start a session
You can set a default model inside the provider block, or pass it on the CLI. I recommend the CLI for experimentation.
opencode --provider n4n --model anthropic/claude-3-5-sonnet
The TUI launches. Type a trivial prompt: write a hello world in rust. If the model responds, the opencode OpenAI-compatible API setup is functional. Exit with Ctrl-C or the /exit command.
To make it permanent, add a default field:
{
"providers": {
"n4n": {
"type": "openai",
"base_url": "https://api.n4n.ai/v1",
"api_key": "$OPENCODE_API_KEY",
"models": {
"anthropic/claude-3-5-sonnet": {}
},
"default": "anthropic/claude-3-5-sonnet"
}
}
}
Then opencode alone uses that provider and model.
Step 7: Verify the endpoint independently
Before blaming opencode for a silent failure, reproduce the request with a raw client. This Python snippet mirrors what opencode sends for a non-streaming chat completion:
import os, requests
url = "https://api.n4n.ai/v1/chat/completions"
headers = {
"Authorization": f"Bearer {os.environ['OPENCODE_API_KEY']}",
"Content-Type": "application/json",
}
payload = {
"model": "anthropic/claude-3-5-sonnet",
"messages": [{"role": "user", "content": "reply with the word OK"}],
"max_tokens": 10,
}
r = requests.post(url, headers=headers, json=payload)
print(r.status_code, r.json())
A 200 with a choices array confirms the contract. If this works but opencode fails, the mismatch is usually the model name string or a missing max_tokens default in your config.
Check opencode debug logs
Run with DEBUG=1 (or --debug if your build supports it) to see the exact URL and payload:
DEBUG=1 opencode --provider n4n --model openai/gpt-4o-mini
Look for the line containing POST /v1/chat/completions. If you see 401, your env var did not propagate. If you see 404, the base_url has a trailing slash or the model ID is unknown to the gateway.
Troubleshooting common failures
401 Unauthorized — The api_key field in JSON references $OPENCODE_API_KEY but the shell variable is empty. Export it in the same shell that launches opencode.
404 on completions — opencode appends /chat/completions to base_url. If you set base_url: "https://api.example.com/v1/" the result is //chat/completions. Strip the trailing slash.
Model not found — The gateway may expect a prefixed slug like openai/gpt-4o-mini. Open the gateway’s model list and copy the exact ID.
Streaming stalls — Some minimal OpenAI-compatible servers do not implement SSE correctly. Set "stream": false in the model options if the provider block allows it, or use a gateway that normalizes streaming.
"models": {
"openai/gpt-4o-mini": {
"stream": false
}
}
Why this matters for coding assistants
A coding agent issues many short, tool-augmented requests. Provider outages or per-minute rate limits will stall your session mid-edit. The opencode OpenAI-compatible API setup is portable precisely because it decouples the agent from the model vendor. Point it at a gateway that honors client routing directives and you can shift models per task without editing code: cheap model for file reads, strong model for planning.
When you run this in CI or a shared dev container, the single config file becomes the only artifact to review. No vendor SDK, no conditional imports. That is the practical payoff of sticking to the OpenAI-compatible surface.
Final verification checklist
opencode --versionsucceeds.opencode.jsonparses as valid JSON.echo $OPENCODE_API_KEYprints a non-empty string.- Raw
curlor Python post to/v1/chat/completionsreturns200. - opencode TUI responds to a test prompt without error lines in debug log.
Follow those steps and your opencode OpenAI-compatible API setup is production-ready, whether the backend is a laptop Ollama or a global inference gateway.