LangChain
MirAPI exposes an OpenAI-compatible endpoint, so LangChain’s ChatOpenAI class works with it directly — no dedicated integration package required. Point base_url at MirAPI and call any chat model from the catalogue, 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 — check its capability flag in the model catalogue.
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 in three tiers: input, output, and cache read. 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 console 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 — implement backoff yourself.