LangChain
MirAPI exposes an OpenAI-compatible endpoint, so LangChain’s ChatOpenAI class works with it directly and you do not need a dedicated integration package. Point base_url at MirAPI and call any chat model in the catalog, such as deepseek-chat.
What you need
Section titled “What you need”| Element | Value |
|---|---|
| Base URL | https://api.mirapi.ai/v1 |
| API key | sk-... (set as MIRAPI_API_KEY) |
| Model | deepseek-chat |
Install
Section titled “Install”pip install langchain-openainpm install @langchain/openaiConfigure
Section titled “Configure”Python:
import osfrom langchain_openai import ChatOpenAI
llm = ChatOpenAI( base_url="https://api.mirapi.ai/v1", api_key=os.environ["MIRAPI_API_KEY"], model="deepseek-chat",)TypeScript:
import { ChatOpenAI } from "@langchain/openai";
const llm = new ChatOpenAI({ model: "deepseek-chat", apiKey: process.env.MIRAPI_API_KEY, configuration: { baseURL: "https://api.mirapi.ai/v1", },});Verify with a message
Section titled “Verify with a message”response = llm.invoke("Reply with exactly: connected to MirAPI")print(response.content)The output should contain connected to MirAPI.
Stream responses
Section titled “Stream responses”for chunk in llm.stream("Count from 1 to 5."): print(chunk.content, end="")const stream = await llm.stream("Count from 1 to 5.");for await (const chunk of stream) { process.stdout.write(chunk.content as string);}Streaming uses standard SSE and ends with data: [DONE], which LangChain handles for you.
Tool calling
Section titled “Tool calling”from langchain_core.tools import tool
@tooldef add(a: int, b: int) -> int: """Add two integers.""" return a + b
llm_with_tools = llm.bind_tools([add])response = llm_with_tools.invoke("What is 3 + 5?")print(response.tool_calls)bind_tools maps to the OpenAI tools/tool_choice format. The model must support tool calling, so check its capability flag in the model catalog.
Structured output
Section titled “Structured output”from pydantic import BaseModel
class Recipe(BaseModel): name: str ingredients: list[str]
structured = llm.with_structured_output(Recipe)recipe = structured.invoke("Suggest a simple pasta recipe")print(recipe)Structured output maps to response_format (json_schema / JSON mode). The model must support JSON output.
Parameters
Section titled “Parameters”| Parameter | Purpose |
|---|---|
model |
Model ID, verbatim from GET /v1/models |
temperature |
Sampling temperature |
max_tokens |
Cap on output tokens |
streaming |
Enable SSE streaming |
reasoning_effort |
Reasoning intensity (reasoning-capable models) |
response_format |
Structured output (JSON mode / JSON Schema) |
tools / tool_choice |
Tool calling |
Reasoning tokens are billed as output. Prompt caching is automatic for OpenAI-compatible models, and cache reads are cheaper than regular input.
Errors and troubleshooting
Section titled “Errors and troubleshooting”| Status | Meaning | Action |
|---|---|---|
| 401 | Missing, invalid, or unknown key | Fix the API key |
| 403 | Key valid but rejected (empty balance, model whitelist, quota, IP allowlist) | Resolve the cause, then retry |
| 413 | Payload too large | Reduce the request size |
| 429 | Rate limited (no Retry-After header) |
Jittered exponential backoff: 1s → 2s → 4s, cap ~30s |
| 500 | Gateway or upstream failure | Idempotent requests are safe to retry |
Errors use the OpenAI envelope {"error":{"message","type","param","code"}}, with type set to new_api_error (gateway) or upstream_error (upstream). Each message ends with a request ID; include it in support tickets. The gateway does not retry for you.
Billing
Section titled “Billing”Chat usage is billed per token, with separate prices for input, output, and cache reads. Cache reads are cheaper than regular input, and reasoning tokens are billed as output. MirAPI uses a prepaid USD balance with no subscription and no monthly fee, and the balance never expires. When the balance runs out, requests return 403; top up and the same key works again immediately.
Troubleshooting
Section titled “Troubleshooting”- Keep
/v1inbase_url. LangChain appends/chat/completionsto the base URL. - Use model names verbatim from
GET /v1/models; thevendor/prefix is for Platform browsing only and is not part of the API name. - 403 with a valid key usually means the model is not whitelisted or the balance is exhausted.
- 429 has no
Retry-Afterheader, so implement backoff yourself.