Integrations: coding agents, SDKs and chat apps

Every OpenAI-compatible tool needs three values. Coding agents with their own guides, LangChain, LlamaIndex, the Vercel AI SDK, and chat apps.

Updated: 22 Sep 2026

Anything that speaks "OpenAI-compatible" works with uttapen and needs three values: the URL https://api.uttapen.ir/v1, a key that starts with sk-up-, and a model id in the form provider/model from the model list. This page is the map; each coding agent has a guide of its own.

Coding tools

ToolStatusGuide
opencodeWorksGuide
Cline (VS Code)WorksGuide
Kilo CodeWorksGuide
ContinueWorks (project no longer maintained)Guide
CursorWorks with caveatsGuide
ZedWorksGuide
VS Code chat (Custom Endpoint)WorksGuide
AiderWorksGuide
CrushWorksGuide
GooseWorks, except GPT-5 and o-series idsGuide
Qwen CodeWorksGuide
Roo CodeOnly if you already have it (discontinued)Guide
Codex CLIDoes not workWhy
Claude CodeNo direct routeWhy

Three rules that apply to every agent:

  1. Set the output ceiling yourself. uttapen reserves the cost of the full max_tokens before the request goes out and charges only real usage afterwards (pricing). Some agents send 32,000 tokens when they don't know better, and since they fire several requests at once, the holds add up and a healthy balance can still return 402.
  2. Point side jobs at a cheap model. Session titles, commit messages and summaries don't belong on your most expensive model.
  3. Give each tool its own key with a monthly cap, so their spend is separated in Dashboard → Usage (API keys).

LangChain (Python)

pip install langchain-openai
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="openai/gpt-5-mini",
    base_url="https://api.uttapen.ir/v1",
    api_key="sk-up-...",
    max_tokens=500,
)
print(llm.invoke("Name three advantages of Postgres.").content)

for chunk in llm.stream("Write one short motivational sentence."):
    print(chunk.content, end="", flush=True)

Tool calling with llm.bind_tools([...]) and structured output with llm.with_structured_output(Schema) behave exactly as they do against OpenAI. In LangChain.js the same values go to new ChatOpenAI({ model, apiKey, configuration: { baseURL } }). If you use embeddings, OpenAIEmbeddings needs check_embedding_ctx_length=False — otherwise it chunks text with OpenAI's local tokenizer — and the model id has to exist on the model list.

LlamaIndex (Python)

pip install llama-index-llms-openai-like
from llama_index.llms.openai_like import OpenAILike
from llama_index.core.llms import ChatMessage

llm = OpenAILike(
    model="openai/gpt-5-mini",
    api_base="https://api.uttapen.ir/v1",
    api_key="sk-up-...",
    is_chat_model=True,
    is_function_calling_model=True,
    context_window=128000,
)
print(llm.complete("Name three advantages of Postgres.").text)
for chunk in llm.stream_chat([ChatMessage(role="user", content="Hello")]):
    print(chunk.delta, end="", flush=True)

Use OpenAILike, not OpenAI: the latter validates the model id against a fixed list of OpenAI models and rejects anything shaped like openai/…. is_chat_model=True is mandatory.

Vercel AI SDK (Node and Next.js)

npm install ai @ai-sdk/openai-compatible
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { generateText, streamText } from "ai";

const uttapen = createOpenAICompatible({
  name: "uttapen",
  baseURL: "https://api.uttapen.ir/v1",
  apiKey: process.env.UTTAPEN_API_KEY,
  includeUsage: true,
});

const { text, usage } = await generateText({
  model: uttapen("openai/gpt-5-mini"),
  prompt: "Name three advantages of Postgres.",
  maxOutputTokens: 300,
});

const result = streamText({ model: uttapen("anthropic/claude-sonnet-5"), prompt: "Hello" });
for await (const delta of result.textStream) process.stdout.write(delta);

In a Next.js route handler, return result.toUIMessageStreamResponse() (or toTextStreamResponse()) and use useChat on the client, so the key never leaves the server. For reasoning and other provider-specific fields use providerOptions: { uttapen: { reasoning: { effort: "low" } } }. @ai-sdk/openai also accepts a baseURL, but parts of it are built on the Responses API and won't work here; openai-compatible is the safe choice.

Chat apps and automation

Field labels in these apps change between versions; if you don't see the one we name, look for the closest equivalent on the same screen.

Open WebUI — Settings → Admin → Connections → Manage OpenAI API Connections → add a connection with https://api.uttapen.ir/v1 and your key. Leave the Model IDs field empty and it pulls the list from /v1/models, which means 400+ entries in the picker; list the few ids you actually use instead. Under Settings → Admin → Interface, set External Task Model to something cheap, or title and tag generation runs on your main model. In Docker you can pass the same two values as OPENAI_API_BASE_URL and OPENAI_API_KEY (read on first start only).

LibreChat — in librechat.yaml:

endpoints:
  custom:
    - name: "uttapen"
      apiKey: "${UTTAPEN_API_KEY}"
      baseURL: "https://api.uttapen.ir/v1"
      models:
        default: ["openai/gpt-5-mini"]
        fetch: true
      titleConvo: true
      titleModel: "openai/gpt-5-nano"
      modelDisplayLabel: "uttapen"

Always set titleModel: the default points at a model that doesn't exist in our catalogue, so titling would 404. Don't reuse a built-in endpoint name such as openAI either.

LobeHub (LobeChat) — in settings, AI Providers → create a custom provider with Request Format set to OpenAI, the URL https://api.uttapen.ir/v1 and your key. If you instead repoint the built-in OpenAI provider with OPENAI_PROXY_URL, turn that provider's Responses switch off — it is on by default. For automatic titles, pick a cheap model under Settings → Service Model.

Chatbox — Settings → Model Provider → Add, and choose OpenAI API Compatible as the API mode (not the Responses one). Set API Host to https://api.uttapen.ir/v1 and leave API Path empty so it appends /chat/completions itself. The Fetch button pulls the model list. Under Default Models, pick a cheap thread-naming model.

Jan — Settings → Model Providers → Add Provider, API format OpenAI-compatible, Base URL including /v1, plus the key; without /v1 requests 404. On save it fetches models from /v1/models. Jan doesn't detect capabilities (tools, vision) for custom providers.

AnythingLLM — set the LLM provider to Generic OpenAI: Base URL with /v1, the key, the model name, and do fill in both numeric fields — the defaults (4096 context, 1024 max tokens) are small enough to truncate answers. The environment equivalents are LLM_PROVIDER='generic-openai', GENERIC_OPEN_AI_BASE_PATH, GENERIC_OPEN_AI_API_KEY and GENERIC_OPEN_AI_MODEL_PREF.

n8n — in the OpenAI credential, set Base URL to https://api.uttapen.ir/v1 and paste your sk-up-… key. Then, in the OpenAI Chat Model node, turn off "Use Responses API": recent node versions default it on and uttapen doesn't serve that path. The general OpenAI node (the "Message a Model" operation) always uses that path and can't be used with us — use the Chat Model node. Avoid ids whose name contains codex or ends in -pro in this node too; the underlying library routes those to Responses on its own.

Dify — Model Provider → install OpenAI-API-compatible → Add Model. Model Name is our id, API Base URL is the /v1 address, Completion mode is Chat. The "model context size" and "upper bound for max tokens" fields both default to 4096, so correct them. For agents and tools, set Function Call Type to Tool Call (it defaults to Not Support). Dify doesn't fetch the model list; add each model by hand. The model for system tasks is set under Default Models.

Flowise — use the OpenAI Custom Model node: type the Model Name, and under Additional Parameters set Base Path to https://api.uttapen.ir/v1; the credential is the usual OpenAI API type. The plain ChatOpenAI node has its own model catalogue, which doesn't include our ids.

Rules that apply everywhere

  • If the tool appends /v1 itself and you get a 404, give it the URL without /v1. A quick curl https://api.uttapen.ir/v1/models tells you which form is right.
  • Wherever you see a Responses API option (or an "OpenAI Responses" provider type), turn it off: uttapen serves Chat Completions, Completions and Embeddings (migration).
  • If the tool reads the model list from GET /v1/models, everything is automatic; if not, type the id exactly and in lowercase.
  • Any tool that makes background requests — titles, tags, summaries — needs its own cheap model, or it quietly adds to your bill.
  • Error codes and what each one means are in errors.
No API key yet?

Sign up with a phone number, top up your wallet from 100,000 toman and create a key. Free models work without a top-up — up to 50 requests a day. Create an API key →