OpenCode can work with models outside its default provider list, yet a custom API connection can fail because of an incorrect base URL, an invalid model ID, or a misplaced credential. The setup is straightforward once those pieces are separated: install OpenCode on Ubuntu, store the API key in an environment variable, configure an OpenAI-compatible provider in opencode.json, and select a supported model. This tutorial walks through the configuration, checks it with a small coding task, and explains common connection errors.
What the setup does
OpenCode can work with a custom OpenAI-compatible model provider. On Ubuntu, the setup has four parts: install the CLI, export an API key, configure the provider in opencode.json, and select the model. A short coding task then confirms whether the configured endpoint accepts requests and returns usable patches.
Prerequisites
Use an Ubuntu 24.04 or 26.04 machine with curl, a shell, and a supported OpenCode installation method. The current OpenCode documentation should be consulted for the exact minimum runtime version. The example below uses the installation script and checks the installed version rather than assuming a particular release.
An account with an OpenAI-compatible service is also required. AI/ML API (https://aimlapi.com/) is one example of a service offering access to multiple models through an API key. Store the credential in the AIML_API_KEY environment variable. The key must not appear in screenshots, command history, or a committed config file.
Step 1: Install OpenCode on Ubuntu
Run the installer using the command documented by OpenCode.
curl -fsSL https://opencode.ai/install | bash
Open a new terminal if the installation changed PATH. Then run
opencode --version
If the command is not found, inspect the installation output and the shell’s PATH. Avoid running arbitrary downloaded scripts with sudo. Review the official installation documentation and the script source before using this method in a managed environment.
Step 2: Configure the API provider
OpenCode reads project or user configuration from opencode.json. A custom provider can use the OpenAI-compatible SDK package and a provider-specific base URL. The following configuration shows the required shape. Replace the placeholder URL and model identifiers with values confirmed in the provider’s current documentation.
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"aimlapi": {
"npm": "@ai-sdk/openai-compatible",
"name": "AI/ML API",
"options": {
"baseURL": "https://api.aimlapi.com/v1",
"apiKey": "{env:AIML_API_KEY}"
},
"models": {
"REPLACE_WITH_EXACT_MODEL_ID": {
"name": "Selected coding model"
}
}
}
}
}
The base URL shown above is an example to verify against the live API documentation. Provider compatibility and accepted model metadata can change with OpenCode releases. Validate the schema using the installed CLI and its current docs before publishing a production configuration.
Export the key from a secure source.
export AIML_API_KEY="value-from-secret-manager"
For a real workstation, load the variable from an approved secret manager rather than leaving a plaintext export in shell history. The available model IDs can change without changing the overall provider configuration. Check the full list of available models (https://aimlapi.com/models) before selecting one.
Step 3: Select a model
The model name in a blog post is not necessarily the API identifier required by OpenCode. Copy the exact identifier from the live model page. Context window, output limit, and pricing should be checked on the same date. Do not assume that a provider supports every advertised maximum through every API route.
| Model | Context window | Maximum output | Input price / 1M | Output price / 1M | Checked |
| DeepSeek V4 Pro | Verify current 1M claim | Verify current 384K claim | Verify live price | Verify live price | At publication |
| Qwen 3.8 Max | Verify current 1M claim | Verify current 131072 claim | Verify live price | Verify live price | At publication |
The values in the brief are targets for verification, not independently confirmed API limits. DeepSeek V4 Pro’s model page and FAQ were reported to show conflicting prices. Resolve that discrepancy with the current catalog before entering any dollar amount.
Once a model ID has been confirmed, add it to the models object and restart or reload OpenCode as required by the installed version. Use the CLI model picker to select the custom provider and the configured model. The display name is for readability. The configuration key must match the actual provider identifier.
Step 4: Verify the setup with a coding task
Use a small Python script with a known defect. A good test case is a function that removes duplicates but accidentally destroys input order.
def unique_names(names):
return list(set(names))
assert unique_names(["ana", "ben", "ana"]) == ["ana", "ben"]
The assertion may fail because sets do not preserve the input sequence as an ordered contract. Ask the selected model to preserve the order of first appearance without external packages. Require a complete corrected function and one regression test. A straightforward correct implementation tracks a seen set while appending names in original order.
Repeat the same task with a second model. Start from the same working tree each time. Do not supply one model with the other’s answer. Run python3 -m unittest or an equivalent test command after applying each patch. Record the request time, final status, and token usage when exposed by the provider or OpenCode logs.
| Model | Test outcome | Time | Input tokens | Output tokens |
| DeepSeek V4 Pro | Enter after run | Enter after run | Enter from logs | Enter from logs |
| Qwen 3.8 Max | Enter after run | Enter after run | Enter from logs | Enter from logs |
No execution logs were provided with the assignment. The table intentionally has no invented results. A valid article comparison requires the two actual terminal captures and the raw usage records.
Troubleshooting common errors
| Error | Likely reason | Next step |
| 401 | Key missing, invalid, or unauthorized | Check AIML_API_KEY and account permissions |
| 404 | Wrong base URL or model identifier | Confirm endpoint and exact catalog ID |
| 429 | Rate limit or quota reached | Check limits and Retry-After before retrying |
| Invalid config | Unsupported field or malformed JSON | Validate against current OpenCode schema |
| Model not listed | Wrong provider name or config location | Confirm config file path and reload |
| No token usage | Provider or CLI omits usage fields | Record that the metric is unavailable |
For 401 errors, do not print the key while debugging. For 404 errors, distinguish an incorrect route from a nonexistent model ID. For 429 errors, back off rather than repeatedly retrying immediately. If a model has a long context window, that does not imply the current account can submit the maximum context at once.
FAQ
Can OpenCode use a model outside its default list? Yes, when a compatible provider configuration and supported model ID are available.
Where should the API key be stored? In an environment variable or approved secret manager, not directly in opencode.json.
Does a single API key work with every listed model? Access depends on the provider account, catalog, billing, and model availability.
Why does a model return 404 when its name appears on a website? Display names and API identifiers can differ. The endpoint route may also be incorrect.
Can two models be compared fairly in OpenCode? Yes, with the same task, configuration, output constraints, and recorded logs. Results from different prompts are not comparable.
Final checks
OpenCode’s custom-provider configuration separates the CLI from a particular model vendor. The API key belongs outside the config file. Exact model identifiers matter more than display names. A working setup should be verified with a small task and a regression test. Model limits and prices must be copied from live documentation with a verification date.
A reliable setup record includes the OpenCode version, the chosen API model ID, the terminal output, and the test result. Keep the model’s published context limits and pricing alongside the date they were checked.