Every tool that speaks OpenAI, pointed at one endpoint

Nearly every AI coding tool and framework ships one assumption: you have an OpenAI key and you talk to OpenAI. Almost all of them also expose the one setting that breaks that assumption. Change it once and every model becomes reachable. Without waiting for tool support to add the vendor you actually want to pay for.

In short: Every OpenAI-compatible tool needs the same three values: one base URL, one key, one exact model ID. Most integration failures reduce to three causes, a doubled /v1 producing 404, the wrong parameter name being silently ignored, and a static model dropdown that lacks the model you meant to call.

The three values that decide everything

Every integration on this page is the same three values wearing different clothes. Learn them once and the per-tool instructions become trivial:

ValueWhat it isWhat breaks if you get it wrong
Base URLhttps://aicomp.ai/v1Doubling the /v1 gives 404; leaving it empty sends your request to the vendor you were trying to avoid.
API keyOne gateway keyVendor keys are rejected by other vendors' models That is the whole reason the endpoint exists.
Model IDExact string from GET /modelsNo fuzzy matching anywhere. A wrong suffix is a hard 404, not a fallback.
Confirm the key works first. One command, no SDK, costs nothing:
Don't have an account yet? You need an API key from the gateway before the steps below will work — how the discount works and what you take on. Create one free → (no prepay, $1 minimum top-up)
curl https://aicomp.ai/v1/models \
  -H "Authorization: Bearer sk-your-gateway-key"

A JSON list of model IDs means the key is good. Invalid token means it was copied wrong.

The one line every tool and framework needs

curl https://aicomp.ai/v1/chat/completions \
  -H "Authorization: Bearer $GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"deepseek-v4-pro","max_tokens":256,\
       "messages":[{"role":"user","content":"Reply with the word ok."}]}'

Before touching any tool config, run that command. If it returns a completion, you have proven all three values work. Every tool-level failure from this point on is a configuration problem in the tool, not an API problem.

Tool matrix

ToolWhere the setting livesExact nameWalkthrough
Claude CodeEnvironment variablesANTHROPIC_BASE_URLGuide
CursorSettings → ModelsOverride OpenAI base URLGuide
OpenAI SDK (Python)Constructor argumentbase_urlGuide
OpenAI SDK (Node)Constructor argumentbaseURL (capitalised)Guide
LangChainChat model constructorconfiguration.baseURLGuide
LiteLLMPer-call argument or proxy YAMLapi_baseGuide
Vercel AI SDKProvider factorycreateOpenAI({ baseURL })Guide
ClineSettings → API ProviderBase URL fieldGuide
Aider.aider.conf.yml or env varopenai-api-base + openai/ prefixGuide
Continue~/.continue/config.yamlapiBase with provider: openaiGuide
Open WebUIContainer environmentOPENAI_API_BASE_URLGuide
Zedsettings.jsonlanguage_models.openai_compatibleGuide
WindsurfCascade provider settingsOpenAI Compatible provider + base URLGuide
DifyConsole → Model ProviderOpenAI-API-compatible entryGuide
Pydantic AIProvider objectOpenAIProvider(base_url=…)Guide
n8nOpenAI credentialBase URL (additional fields)Guide
OpenHandsconfig.toml or LLM_ varsbase_url + openai/ model prefixGuide
LibreChatlibrechat.yamlendpoints.custom[].baseURLGuide
Roo CodeSettings → API ProviderOpenAI Compatible + provider/model IDGuide
AnythingLLMEnvironment fileGENERIC_OPEN_AI_BASE_PATHGuide
Codex CLI~/.codex/config.toml or envOPENAI_BASE_URL + wire_api = "responses"Guide
Gemini CLI~/.gemini/settings.jsonapi.baseUrl + /auth selectionGuide
CrewAIConstructor argumentLLM(base_url=…, custom_openai=True)Guide
DSPyConstructor argumentdspy.LM("openai/…", api_base=…)Guide
LangChainConstructor argument (Python / TS)ChatOpenAI(base_url=…) — TS: configuration.baseURLGuide
LlamaIndexSettings.llm + Settings.embed_modelOpenAILike(api_base=…, is_chat_model=True)Guide
AutoGenConstructor argumentOpenAIChatCompletionClient(base_url=…, model_info=…)Guide
OpenAI Agents SDKAsyncOpenAI clientbase_url=… + set_tracing_disabled()Guide
OpenCodeopencode.json at the project rootsettings.baseURL (v2) / options.baseURL (v1)Guide
Kilo CodeSettings → Providers → Custom providerBase URL (accepts a full endpoint URL) + flat provider IDGuide
CodeCompanion.nvimadapters + four strategiesenv.url (defaults to Ollama) + per-strategy adapterGuide
avante.nvimopts.providers table__inherited_from = "openai" + version-prefix endpointGuide
GooseEnv vars or ~/.config/goose/GOOSE_MODEL + OPENAI_HOST (not _BASE_URL)Guide
Crush~/.config/crush/crush.jsontype is openai in the README, openai-compat elsewhereGuide
Semantic KernelAddOpenAIChatCompletion / async_client.NET needs SKEXP0010 suppressed; Python has no base-URL argumentGuide
LobeChatSettings panel or OPENAI_PROXY_URLOPENAI_PROXY_URL (not _BASE_URL) + OPENAI_MODEL_LISTGuide
gptel (Emacs)gptel-make-openai in init.elURL is protocol://host + endpoint; :host takes no schemeGuide
Spring AIspring.ai.openai.* propertiesbase-url has no /v1; completions-path supplies itGuide
Cherry StudioSettings → Model Services → Add providerAddress field appends /v1/chat/completions; trailing # stops itGuide
Plandexplandex models custom JSON fileapiKeyEnvVar holds a variable name, not a key; baseUrl ends in /v1Guide
AgnoOpenAILike(id=, base_url=) in Pythonid and api_key default to not-provided; embedder is separateGuide
Open Interpreter--api_base / interpreter.llm.api_baseapi_key is mandatory (fake_key); context limits are not inferredGuide
Codycody.dev.models array in VS Code settingsinputTokens defaults to 7000; entry needs an editor restartGuide
MastracreateOpenAI({ baseURL })baseURL on the model call is ignored; model id carries a gateway prefixGuide
JanSettings → Model Providers → Add ProviderAPI format is chosen before the URL; base URL must carry /v1Guide
SmolagentsLiteLLMModel or OpenAIServerModelWhich class you built decides whether the model id takes an openai/ prefixGuide
Bolt.diyOPENAI_LIKE_API_BASE_URL in .env.localProvider ships disabled; ids come from your /models route, never typedGuide
Prism PHPproviders.openai.url in config/prism.phpDefault already ends in /v1; Laravel config cache hides .env editsGuide
FlowiseBase Path on the ChatOpenAI Custom nodePlain ChatOpenAI has no Base Path field; Base Path is stored per nodeGuide
VoidSettings → Providers → OpenAI CompatibleOne URL, three model slots; adding a model is not the same as selecting itGuide
LangChain4jOpenAiChatModel.builder().baseUrl()apiKey is mandatory at build time; Spring prefix is open-aiGuide
LangflowSettings → Model Providers → OpenAI CompatibleProvider exists from 1.11 only; SSRF blocks localhost until allowlistedGuide
RAGFlowModel providers → OpenAI-API-Compatible instanceMax tokens never reaches the request; /v1 auto-append is version-boundGuide
Tabby[model.completion.http] / [model.chat.http]Completion needs a prompt_template; /v1 rule flips by connectorGuide
aichatclients: list in config.yamlThree tools share the name; forks want api_url not api_baseGuide
claude-code-routerProviders[] in config.jsonTwo schema layouts circulate; transformers gate tool callingGuide
MaxKBModel providers → OpenAIBase model is validated at save; application API is the opposite directionGuide
TraeSettings → Models → Custom ConfigURL field is base or full by a toggle; /v1 ownership flips with itGuide
Zencoderproviders in settings.jsonUI key screen is Anthropic/OpenAI only; the generic key has two underscoresGuide
Twinnytwinny.apiUrl / twinny.fimApiUrlChat and completion are separate routes; completion fails with silenceGuide
Haystackapi_base_url on the LLM componentsThe component appends the route; the embedder is a second endpointGuide
Raycast AIproviders.yamlbase_url excludes the route; the abilities block is a promiseGuide
Ellamaellama-provider (the llm package)Two constructors differ by one word and target different hostsGuide

Menu labels move between versions; the configuration key or environment variable does not. Where the two disagree in our guides, trust the variable.

The three failures behind most support tickets

SymptomCauseFix
404 on every requestDoubled path — the SDK appends /chat/completions to your base URLStrip the trailing path so the URL ends at /v1
Setting appears to do nothingWrong casing or wrong key name (baseUrl is silently ignored by the Node SDK, which wants baseURL)Copy the exact name from the matrix above; several tools also only re-read it on a cold start
401 with a key you just createdTrailing whitespace, or the tool is still using its own pooled quotaRe-copy the key, restart the tool, then confirm the request shows up in your usage log

What it costs to run an agent all day

Coding agents are output-heavy: short prompts in, long diffs out. That is why the output column matters more than the input column everyone compares. The table below prices one heavy day of agent work, 200k input, 60k output, across twelve models that people actually route to from these tools.

Cost of one heavy coding day (200k input / 60k output tokens) and a 20-day month. Rates checked 2026-11-09.
ModelVendorRate
in / out per 1M
Per dayPer month
gpt-5.6-lunaOpenAI$0.1 / $0.6$0.06$1
deepseek-v4-flashDeepSeek$0.15 / $0.6$0.07$1
MiniMax-M3MiniMax$0.15 / $0.6$0.07$1
gemini-3.7-flashGoogle$0.375 / $1.875$0.19$4
claude-haiku-4-5-20251001Anthropic$0.5 / $2.5$0.25$5
deepseek-v4-proDeepSeek$0.66 / $1.98$0.25$5
glm-5.3Zhipu$0.7 / $2.2$0.27$5
qwen3.8-maxAlibaba$1 / $3$0.38$8
claude-sonnet-5Anthropic$1 / $5$0.50$10
gpt-5.6-terraOpenAI$1 / $6$0.56$11
kimi-k3Moonshot$1.5 / $7.5$0.75$15
claude-opus-5Anthropic$2.5 / $12.5$1.25$25
Cost note. The spread between the cheapest and the most expensive row is large enough to decide architecture, not just budgets. If your tool lets you route different tasks to different models (cheap model for autocomplete, strong model for refactors) that split is usually worth more than any single-model optimisation.

When it is configured but still not working

Every page above ends with a working setup. This is where to go when one does not — the ten diagnostics below cover the failures that show up after the configuration looks correct, which is where most of the time actually goes.

SymptomGo here
Requests still go to the default host with no errorBase URL not working, seven causes, in order
A status code you cannot interpret, or a 200 with nothing in itEndpoint error codes: 401 vs 404
429s, or retries that quietly multiply the billLiteLLM retries and timeouts
A coding agent that rate-limits mid-sessionClaude Code 429 — which limit you hit
Agents or frameworks whose tools silently stop workingAutoGen — declare capabilities or tools fail
A model id that resolves somewhere you did not intendLiteLLM model names — the prefix is a routing instruction
Token counts that vanish the moment you turn streaming onStreaming and the usage chunk you are not getting
An empty model picker with a key and URL that both workRead /v1/models before you trust the dropdown
A context error, or responses that come back quietly shortcontext_length_exceeded — and the cap nobody mentions
A 401 that survives regenerating the key, or a 404 that appears once you doCline 401 vs 404 — the code names the field

The shared idea across all ten: a URL that is never read and a URL that is wrong look identical, and authentication happens before routing So a 401 localises to the credential and a 404 to the path. The same logic runs one layer down: a name that routes and a name that resolves are different things, and only one of them tells you when it failed.

Change models without touching credentials

The reason to keep one endpoint is that switching models stops being a project. Nothing about the key or the URL changes — only the string you send:

# Same key, same URL, different partner:
# change this one line and the entire bill changes shape
export MODEL=deepseek-v4-flash

curl "$GATEWAY_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{{\"model\":\"$MODEL\",\"max_tokens\":128,\
       \"messages\":[{{\"role\":\"user\",\"content\":\"ok?\"}}]}}"

Put that environment variable somewhere every tool reads from and you can promote a failing call to a stronger model, or demote an expensive one to a cheaper tier, without opening a single settings panel. In practice this is how teams end up running three models at once: a strong one for anything touching production code, a mid-priced one for the daily grind, and an inexpensive one for summaries and autocomplete.

What "OpenAI-compatible" does not promise

The phrase is narrower than it sounds. It describes a request shape, not a guarantee that every feature survives the trip:

Guaranteed by the wire formatNot guaranteed
/chat/completions with messages and streamingIdentical tokenisation — the same prompt costs different amounts on different models
Tool / function calling messagesThe same tool schemas being equally reliable across model families
Usage reporting and error codesIdentical rate limits, context windows or safety behaviour
Model discovery via GET /modelsEmbeddings, image or audio routes being present at all

Read that as: switching models through one endpoint is cheap, but it is not free. Budget ten minutes per new model to re-check tool reliability and cost behaviour rather than assuming the previous model's results transfer.

Rollout checklist

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

FAQ

Which base URL do I use for all of these tools?

https://aicomp.ai/v1, the same value everywhere. What changes per tool is only where you paste it: an environment variable, a constructor argument, or a settings field.

Why do my requests 404 after I paste the base URL?

Almost always a doubled path. The OpenAI SDKs append /chat/completions to whatever you give them, so if your base URL already ends in /v1 do not add another one. Watch for the opposite failure too: an empty base URL silently goes to the vendor's own endpoint.

The tool has a model dropdown and my model is not in it.

Dropdowns are usually a static list shipped with the tool, not a call to /models. Pick the manual or 'custom model' option and type the exact ID from GET /models. Vendor APIs reject model names they do not recognise There is no fuzzy matching.

Can I switch models without reconfiguring the tool?

Yes, that is the point of one endpoint: only the model ID changes. Keep the base URL in an environment variable so reverting is instant, and keep one key instead of one per vendor.

How do I know the override actually took effect?

Send one request, then check your gateway usage log. A request appearing there is the only reliable proof. A 200 response can also come from the tool's own pooled quota if the setting was ignored.

Which tools accept an OpenAI-compatible endpoint?

Broadly four groups: coding agents (Claude Code, Cursor, Cline, Aider, Continue), SDKs and routers (OpenAI and Anthropic SDKs, LiteLLM, Vercel AI SDK, LangChain), chat front-ends (Open WebUI), and automation platforms (n8n). The mechanism differs per group (some expose a base URL field, some only read an environment variable), and a few need a provider selection before the field appears at all. The matrix above maps each one to its setting.

Do I need a separate API key for each tool?

No, one key works across all of them, which is the point of routing them through a shared endpoint. Issuing separate keys per tool is still worth doing, though: it lets you see per-tool spend in the usage log and revoke one integration without disturbing the rest. Cost attribution is the reason to split keys, never compatibility.

Related

Get API access

Rate cards: GPT, Claude and DeepSeek