Connect OpenCode to a Custom OpenAI-compatible API: Provider Configuration, Model Limits, and Gateway Fallback

OpenCode Custom Provider Configuration Tutorial: Differentiate Chat Completions and Responses API, set up baseURL, model context, gateway routing, credentials and troubleshooting.

OpenCode also appears in rising queries for “AI coding”, “vibe coding”, “open source AI” and “coding agent”.

The most common access error is not the API key, but the misalignment of the protocol, provider ID, and model name.

First confirm which protocol the upstream uses

/v1/chat/completions usually uses @ai-sdk/openai-compatible.

/v1/responses uses @ai-sdk/openai.

“OpenAI compatible” does not mean that both endpoints are implemented.

First confirm with the upstream documentation and a minimal curl request.

1
2
curl -sS https://gateway.example.com/v1/models \
  -H "Authorization: Bearer $API_KEY"

Do not write the key directly into the shell history.

Separate credentials from configuration

Run /connect in OpenCode and select Other.

Enter a unique provider ID, such as corp-gateway.

This ID must be exactly the same as opencode.json.

Just executing /connect will only save the credentials and will not automatically generate the complete provider configuration.

A minimal configuration

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "corp-gateway": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "Corporate Gateway",
      "options": {
        "baseURL": "https://gateway.example.com/v1"
      },
      "models": {
        "coding-model": {
          "name": "Coding Model"
        }
      }
    }
  }
}

The model key must be a model ID that the gateway actually accepts.

The display name can be customized but does not replace the real ID.

Add context constraints to unknown models

1
2
3
4
"limit": {
  "context": 200000,
  "output": 32768
}

OpenCode uses these values ​​to estimate the remaining context.

Do not directly fill in the total token advertised by the supplier into both input and output.

Excessive output upper limit may cause the request to be rejected by the upstream.

Customize the header boundary

Tenant or gateway routing may require additional headers.

Static non-sensitive values ​​can be placed in the configuration.

The key should reference an environment variable.

Do not leave the user identity header to the Agent for free modification.

The gateway should derive tenants from trusted authentication information rather than trusting client self-reports.

Vercel AI Gateway Routing

The official example supports options such as order, only and zeroDataRetention.

order represents the supplier attempt order.

only limits available suppliers.

zeroDataRetention is used to filter routes that meet data retention requirements.

Rollback cannot just look at the HTTP status code.

Authentication failures, insufficient balance, and content policy rejections generally should not be blindly changed providers and retried.

Use three requests for acceptance

Send plain text Q&A first.

Then send tasks that require tool calls.

Finally send long input close to the context limit.

Record the model name, request ID, first token delay and total tokens.

If the gateway rewrites the model name, both the request value and the actual route value should be retained in the log.

Common mistakes

401: Credentials are not saved, environment variables are not entered into the current process, or the Header name is incorrect.

404: Write more or less /v1 in baseURL, or you may choose the wrong protocol.

400 unknown model: The configuration key is inconsistent with the upstream model ID.

Tool not working: upstream is only compatible with text formats and does not fully implement tool calls.

Context premature overflow: limit.context does not match the real model.

Troubleshooting commands

1
opencode auth list

Confirm that the credential entry exists, but do not print the actual key.

Then use /models to check if the model is present.

The same request is executed once by calling the gateway directly and once through OpenCode.

If the direct request succeeds but OpenCode fails, focus on checking the configuration and SDK protocol.

If both sides fail, check the gateway and account first.

Multiple environment configuration

Development, test, and production gateways use different provider IDs.

For example corp-dev and corp-prod.

Production IDs do not appear in personal development configurations by default.

CI uses short-term credentials and does not reuse the developer’s local token.

After switching the environment, run the read-only task first to confirm that there is no misconnection to production.

Safety and cost control

Set the budget and rate for each key on the gateway side.

Record charges by provider, model, warehouse, and user.

Log masking Authorization and credentials in prompt.

Limit the files and commands that the Agent can access.

Successful API routing does not mean that local tool execution is safe.

Acceptance Checklist

  • Confirm Chat Completions or Responses protocol.

  • /connect ID is exactly the same as configured.

  • baseURL contains /v1 only once.

  • The model ID is consistent with the gateway.

  • context/output constraints come from real documents.

  • Fallback policy differentiates between retryable and non-retryable errors.

  • Credentials not in JSON with Git.

  • All three types of requests save the request ID and real route.

Provider configuration document

First use a separate script to verify the gateway protocol

Before connecting to OpenCode, confirm the gateway’s authentication, model name, and response format with minimal requests. Here’s an example of the Chat Completions endpoint:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$headers = @{
  Authorization = "Bearer $env:AI_GATEWAY_KEY"
  "Content-Type" = "application/json"
}
$body = @{
  model = "coding-model"
  messages = @(
    @{ role = "user"; content = "Reply with OK" }
  )
  max_tokens = 16
} | ConvertTo-Json -Depth 5
Invoke-RestMethod `
  -Uri "https://gateway.example.com/v1/chat/completions" `
  -Method Post `
  -Headers $headers `
  -Body $body

If this request fails, resolve the gateway issue first. It succeeds and OpenCode fails before checking the provider configuration and AI SDK package.

Responses API cannot just replace the URL

The inputs, tool definitions, and streaming events of the Responses API are not identical to Chat Completions. When the upstream only provides /v1/responses, replace the npm package of the provider with @ai-sdk/openai, and check whether the gateway transparently transmits the protocol.

Do not forward two request bodies directly to the same handler in a reverse proxy. While seemingly simple text requests may succeed, tool calls and multimodal requests become corrupted on the fly.

Use environment variables to reference the API key

Before submitting the project configuration to Git, search whether it contains real credentials:

1
git grep -n -E "sk-[A-Za-z0-9]|Bearer [A-Za-z0-9]"

The name of the local environment variable should reflect its purpose, such as CORP_GATEWAY_KEY, and do not reuse the ambiguous API_KEY. CI, PC and VPS use different keys respectively.

Verify streaming output

After the normal response is successful, test longer answers and tool calls. Check whether the first event, increment text, end reason and final usage are complete.

The proxy server needs to turn off unnecessary response buffering and set the read timeout to be longer than the model task timeout. Otherwise OpenCode will show a disconnection while the model is still running.

What will happen if the context upper limit is written incorrectly?

When the configuration value is higher than the real upper limit, OpenCode thinks there is still space, but the upstream returns that the context is too long. When the configuration value is too low, the client compresses or discards useful content prematurely.

Use fixed token samples to increase input step by step and record the actual rejection points of the gateway. System prompts, tool definitions, and reserved outputs are also deducted, rather than just user files.

Model aliases require version management

Gateways often point the coding-model to a continuously updated backend. This facilitates switching, but will produce different results for the same configuration.

Production workflows use versioned aliases, such as coding-model-2026-07. Create a new alias when upgrading, and switch to the default route after running the test warehouse and returning it.

Maintain capability compatibility when rolling back

The main model supports tool calls and long contexts, and the fallback model must also meet the minimum capabilities of the task. If the fallback model only supports text, it should fail explicitly and not return tool JSON to the Agent as normal text.

Document supports_tools, supports_vision, context, output and data retention policy for each route. When choosing to go back, filter by ability and try in order.

Desensitization rules for agent logs

Retain request ID, tenant, model, status code, token and elapsed time. Delete Authorization, and the prompt text will not be included in the centralized log by default.

If you must sample text during debugging, use a dedicated test account, short retention period, and limited storage. After debugging, close sampling and delete temporary data.

Close connection and retry strategy

Connection timeouts can be retried in a limited manner; authentication failures, parameter errors, and content policy rejections are not retried. 429 decides whether to wait based on Retry-After and the budget.

When the writing tool is already executing and the model response is interrupted, the entire task is not rerun. Restore interaction or check the working tree first to avoid repeated modifications.

Five-minute smoke test after configuration changes

Run /models, a short text question and answer task, a read-only file task, and a small task that requires a tool call in sequence. Confirm that the model displayed on the interface is consistent with the actual model in the gateway log.

Then deliberately enter a model name that does not exist. The system should return explicit configuration errors rather than silently routing to expensive default models.

Finally, open a new terminal and retest to eliminate false success caused by temporary environment variables of the current session. Test results are saved with the configuration diff for easy rollback.

If the smoke test fails, restore the previous opencode.json and locked model aliases, and do not continue to superimpose configuration modifications in the fault state.