Point Roo Code at an OpenAI-compatible endpoint

Roo Code is a VS Code agent that reads your repository, so every request carries the in-scope files plus history. Three fields change, and the one that trips people up is not the URL — it is the model ID.

In short: Roo Code takes an OpenAI Compatible provider with Base URL, API Key and Model ID. The model ID usually needs its provider prefix or the request returns 400 invalid model format, and a model without native tool calling will chat but cannot read, edit or run anything.
Before you start: you need an endpoint root ending in /v1 and a key from that endpoint. The setting below is the only thing that changes — request and response handling stay identical. Rates checked 2026-09-26.

The setting

In the extension settings, choose OpenAI Compatible as the API provider. Three fields appear: Base URL, API Key and Model ID. The base URL needs the version segment and no trailing slash:

API Provider : OpenAI Compatible
Base URL    : https://aicomp.ai/v1
API Key     : sk-...
Model ID    : claude-sonnet-5

Take the model ID from the endpoint's own listing rather than typing it from memory — most "model not found" and "invalid model format" errors are a character-level mismatch, not a configuration problem:

curl -s https://aicomp.ai/v1/models -H "Authorization: Bearer $KEY" \
  | python3 -c "import sys,json;print('\n'.join(m['id'] for m in json.load(sys.stdin)['data']))"

One more requirement that is easy to overlook: Roo Code drives file reads, edits and commands through native OpenAI tool calling. A model that cannot do tool calls will hold a perfectly normal conversation and fail at every action that touches your project. That failure looks like a permissions issue and is not one.

What Roo Code costs

Each request carries the in-scope repository context plus conversation history, and produces relatively little back. Twenty-five requests a day on a mid-sized repository is roughly 2M input against 75k output — about 27:1.

Twenty-five requests a day: about 80k input and 3k output each, over 20 working days. Rates checked 2026-09-26.
ModelVendorRate
in / out per 1M
Per dayInput share
of the bill
Per month
gpt-5.6-lunaOpenAI$0.1 / $0.6$0.2482%$5
MiniMax-M3MiniMax$0.15 / $0.6$0.3487%$7
deepseek-v4-flashDeepSeek$0.22 / $0.66$0.4990%$10
gemini-3.7-flashGoogle$0.375 / $1.875$0.8984%$18
claude-haiku-4-5-20251001Anthropic$0.5 / $2.5$1.1984%$24
deepseek-v4-proDeepSeek$0.66 / $1.98$1.4790%$29
glm-5.3Zhipu$0.7 / $2.2$1.5689%$31
qwen3.8-maxAlibaba$1 / $3$2.2390%$44
claude-sonnet-5Anthropic$1 / $5$2.3884%$48
gpt-5.6-terraOpenAI$1 / $6$2.4582%$49
kimi-k3Moonshot$1.5 / $7.5$3.5684%$71
claude-opus-5Anthropic$2.5 / $12.5$5.9484%$119

Input is between 82% and 90% of that. The variable that moves this page more than the model choice is how much of your repository is in scope. Taking the cheapest input rate in the table ($0.1 per million), the same twenty-five requests cost $0.10 a day when a turn carries 20k of context, $0.24 at 80k, and $0.55 at 200k — a tenfold difference driven entirely by scope, with the model held constant. Narrowing what Roo reads will usually beat switching models.

Cost note. At 27:1 the input rate decides the bill, though not as absolutely as on an agent loop that resends its full history every turn. This is also why measuring your own repository matters: the prompt-token count depends on how much of the project is in scope, and that number moves the ranking.

Measure it once rather than estimating. One real request against your own project tells you the ratio you are actually paying:

import os
from openai import OpenAI

# One real request tells you what a Roo Code turn actually costs.
# Roo sends the whole in-scope context every turn, so watch prompt_tokens.
client = OpenAI(base_url="https://aicomp.ai/v1", api_key=os.environ["KEY"])
r = client.chat.completions.create(
    model="claude-sonnet-5",
    messages=[{"role": "user", "content": "Summarise this repo's entry point."}],
    max_tokens=512,
)
u = r.usage
print(f"in={u.prompt_tokens:,} out={u.completion_tokens:,} "
      f"ratio={u.prompt_tokens / max(1, u.completion_tokens):.0f}:1")

If that prints a ratio far above 27:1, your workspace is putting more into scope than you assumed, and a smaller scope will save more than switching models.

How this fails in practice

The failures that account for most setup problems, and what each one actually means.
What you seeWhat it usually isFix
400 invalid model formatModel ID entered without its provider prefixCopy the ID from /v1/models exactly as listed
Chat works, file edits and commands failModel does not support OpenAI tool callingPick a model that does; the URL and key are not the problem
404 on every requestBase URL missing /v1 or carrying a trailing slashRoot ending in /v1, nothing after it
Context limit hit part-way through a taskRepository puts more in scope than the window allowsNarrow the workspace scope, or use a larger-window model
New setting seems ignoredProvider configured but not selected as activeConfirm the provider is the active one, then send a fresh message
Costs far above the estimateMore of the repository in scope than assumedMeasure prompt_tokens on a real request
You need a key before the code below runs. Create an account, generate a key, and copy the base URL (https://aicomp.ai/v1). Create one free →
Check current rates → Free to sign up · $1 minimum top-up · No prepayment

Confirming it took effect

Send one message and read the usage log on the endpoint. A request recorded there is the only reliable proof — an answer in the editor can come from a provider configured earlier, and nothing in the UI distinguishes them. If the log is empty, the request never left the editor: check the model ID first, then the URL, then the key.

FAQ

Where do I enter a custom endpoint in Roo Code?

In the extension's settings, by selecting OpenAI Compatible as the API provider. That reveals three fields — Base URL, API Key and Model ID — and they are the whole configuration. There is no file to edit and nothing to restart, which makes it quick to set up and equally quick to get subtly wrong, because a wrong value fails silently until the first request goes out.

Why do I get a 400 invalid model format error?

Because the model identifier was entered without its provider prefix. Many OpenAI-compatible deployments expect the form provider/model-id, and a bare identifier that works against the endpoint with curl can be rejected here. Take the identifier straight from the endpoint's /v1/models listing rather than retyping it, and check for trailing characters or line breaks if you pasted it.

Chat works but Roo cannot edit files or run commands. Why?

Roo Code drives file operations and command execution through the native OpenAI tool-calling format. If the model does not support tool calls, ordinary conversation still works perfectly while every action that touches your repository fails — which reads as a permissions problem but is not one. Confirm the model supports OpenAI-compatible tool calling before investigating anything else; changing the base URL or regenerating the key will not fix it.

What does a Roo Code turn actually cost?

Mostly input. Each request carries the in-scope repository context plus the conversation history, and typically runs tens of thousands of prompt tokens against a few thousand completion tokens. The exact number depends on how much of the repository is in scope, which is worth measuring once on your own project rather than estimating — the difference between a focused workspace and a large one is large enough to change which model is cheapest.

Is output pricing irrelevant for Roo Code?

Not irrelevant, but close to it. The ratio lands near 27:1 in favour of input on a typical day, so the input rate drives the bill and the output rate is a minor correction. The practical consequence is that a model with a low input rate and a high output rate is genuinely the cheaper choice here, even though the same model would be a poor pick for a chat-heavy tool where the ratio is far closer to even.

Do I need to restart VS Code after changing the endpoint?

Usually not — the setting applies to subsequent requests. If a change appears to have no effect, send a fresh message rather than reusing a conversation started under the previous configuration, since the earlier turn may still be holding the old context. If it still does not take, confirm the provider is actually selected: having configured a custom endpoint and not chosen it as the active provider is a common and entirely invisible mistake.

How do I check the endpoint is really being used?

Send a message and then read the usage log on the endpoint. A request recorded there is the only reliable confirmation — a plausible answer in the editor can come from a provider configured earlier, and the extension does not tell you which one replied. If the log stays empty, the request never went out; check the model identifier first, then the URL, then the key.

Related

Get API access