The Mistral API integration path is short: one base URL, one key, and one model name are enough for a first call. What usually blocks people is not the code but three details — whether the URL is complete, whether the model name is current, and whether the key and endpoint are paired correctly.
This article starts from the official endpoint https://api.mistral.ai/v1, completes a first call with curl and Python, then covers streaming, JSON mode, tool calling, common errors, and a checklist for migrating from direct official access to ZSQH AI Gateway.
Note: Mistral, Mistral AI, and related model names are trademarks of Mistral AI. This article is independent and not affiliated with Mistral AI. Models, parameters, and quotas may change between versions; refer to the official documentation and our model pricing page.
1. Confirm three things before integration
The first is the key source. Official keys are created at https://console.mistral.ai and work only with the official endpoint; gateway keys are created in the ZSQH console and work only with the gateway endpoint.
The second is the base URL. The official endpoint is https://api.mistral.ai/v1, and the full chat completions path is https://api.mistral.ai/v1/chat/completions.
The third is the model name. Mistral offers both -latest aliases and dated, pinned version names, and they mean different things. An alias changes when the official default changes; a pinned version is better for regression comparisons in production.
Confirm these three before writing code. In reverse order, you end up cycling between 401 and 404.
2. Base URL and request path
The official API base address is:
https://api.mistral.ai/v1
Chat completions uses POST /v1/chat/completions. Two headers are required:
Authorization: Bearer <MISTRAL_API_KEY>
Content-Type: application/json
If you use the official Python SDK, you usually pass only api_key, and the SDK assembles the URL. If you use the OpenAI SDK, set base_url to https://api.mistral.ai/v1, and the SDK appends /chat/completions.
The most common mistake here is duplicate path segments: base_url already contains /v1, the request path adds /v1/chat/completions, and the result is /v1/v1/chat/completions, which returns 404. Another common mistake is mixing the official address with the gateway address, which shows up as 401.
The OpenAI-compatible endpoint of ZSQH AI Gateway is https://ai.zhongshangqihang.com/v1, with the same path rules. When switching, change only base_url and api_key, and never cross-pair them.
3. Model names: aliases vs pinned versions
As of October 2026, the official quickstart uses mistral-large-latest, and the function-calling documentation also lists aliases such as mistral-medium-latest and mistral-small-latest. The model overview page lists pinned version names including mistral-large-4 (public preview), mistral-large-2512, mistral-medium-3-5, mistral-small-2603, and specialized models such as ministral-14b-2512 and codestral-2508.
The difference between the two kinds of names:
- A
-latestalias points to the official current default version. It suits quick validation and non-critical workloads, but behavior may change when the default moves. - A dated or generation-numbered pinned name points to a specific version. It suits production because behavior is reproducible and easier to compare and roll back.
Different official pages update on different schedules, so the exact version behind an alias should be confirmed through the console or the model list at call time. Before integration, use the SDK's client.models.list() or the console to confirm currently available models; do not copy model names from old articles.
If you use ZSQH AI Gateway, model names follow the model pricing page. The gateway may map upstream model names, so official names copied directly may not work.
4. First curl: run the smallest request
Set the environment variable first, then send the shortest request. Keep max_tokens small to reduce waiting and noise.
export MISTRAL_API_KEY="your-key-here"
curl https://api.mistral.ai/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $MISTRAL_API_KEY" \
-d '{
"model": "mistral-large-latest",
"messages": [
{"role": "user", "content": "Reply with OK only"}
],
"max_tokens": 32
}'
A 200 response with content in choices[0].message.content means the key, base URL, and model name are all correct. A 401 means check the key and headers first; a 404 means check the path and model name; a 402 means check billing status.
5. Python: Mistral SDK and OpenAI SDK
The official Python SDK package is mistralai:
pip install mistralai
Minimal example:
import os
from mistralai.client import Mistral
with Mistral(api_key=os.environ["MISTRAL_API_KEY"]) as client:
response = client.chat.complete(
model="mistral-large-latest",
messages=[
{"role": "system", "content": "You are a concise technical assistant."},
{"role": "user", "content": "Explain what a vector database is in three sentences."},
],
max_tokens=256,
)
print(response.choices[0].message.content)
print(response.usage)
Mind the import path: current SDK documentation uses from mistralai.client import Mistral, while some older versions use from mistralai import Mistral. Do not mix them. If you see ModuleNotFoundError, check the installed SDK version and the official migration notes.
If you want to reuse existing OpenAI SDK code, point base_url to https://api.mistral.ai/v1 and replace api_key with a Mistral key. Mistral's request shape is close to OpenAI Chat Completions, and this pattern is common in the community. However, the official documentation does not market the Mistral API as an "OpenAI-compatible product"; parameter coverage, error shapes, and extension fields still follow the official API reference. Validate each item with real requests before launch and do not assume every OpenAI parameter works.
6. Streaming
Chat interfaces usually need token-by-token output. The Mistral SDK uses client.chat.stream(...), which returns an event stream; the text delta is in chunk.data.choices[0].delta.content:
with Mistral(api_key=os.environ["MISTRAL_API_KEY"]) as client:
stream = client.chat.stream(
model="mistral-large-latest",
messages=[{"role": "user", "content": "Write a Python example that reads a CSV file"}],
)
for chunk in stream:
delta = chunk.data.choices[0].delta.content
if delta:
print(delta, end="", flush=True)
Streaming responses use data-only SSE and end with data: [DONE]. Engineering-wise, handle three things: empty deltas, client disconnects, and timeout retries. Do not write to the database on every delta; concatenate the full text and persist it after the stream ends.
7. JSON mode, structured outputs, and tool calling
JSON mode uses response_format={"type": "json_object"}. According to the official documentation, all current models except codestral-mamba support it. When enabled, output is constrained to valid JSON, but content is a JSON string and still needs json.loads(). State "return a JSON object" and the expected fields in the prompt; do not rely on the parameter alone.
Structured outputs suit cases with fixed fields. The official SDK provides client.chat.parse(...), which accepts a Pydantic model directly and returns a parsed object. With a raw JSON Schema, set strict: true and additionalProperties: false on the object. Stricter fields leave the model less room to improvise and make downstream validation simpler.
Tool calling uses a tools array; tool_choice accepts auto, any, or none, and parallel_tool_calls controls whether parallel calls are allowed. The model only returns tool names and arguments — your backend executes the functions. After receiving tool_calls, append the assistant message unchanged to the message list, add a tool message with the matching tool_call_id, and call the model again until it produces a final answer. Multi-turn tool use must loop, not run a single round.
8. Common errors and troubleshooting
| Error | Common cause | Action |
|---|---|---|
| 400 | The body is not valid JSON, or model or messages is missing |
Validate the minimal body with curl first |
| 401 | The key is missing, wrong, expired, or does not match the endpoint | Check the Bearer header and key source |
| 402 | Billing issue: balance, spending cap, or failed payment | Check billing and quotas in the console |
| 403 | The account or workspace lacks permission for the model | Check the workspace, model permissions, and plan |
| 404 | Wrong path, or the model or resource does not exist | Confirm /v1/chat/completions and the model name |
| 422 | Valid JSON but invalid parameter values | Check types, enum values, and array lengths |
| 429 | Rate, token, or concurrency limit exceeded | Back off exponentially and read Retry-After |
| 500/503 | Server-side failure or temporary overload | Wait briefly and retry; check the status page if it persists |
Do not try to bypass 429 by creating more keys. Official quotas are counted per account, workspace, or plan, and multiple keys usually share the same limit. The right approach is to lower concurrency, use exponential backoff, stagger batch jobs, and consider a higher plan only when necessary.
9. Checklist for migrating from official to gateway
- Create an account at ZSQH AI Gateway, generate a gateway key, and store it separately from the official key.
- Change
base_urltohttps://ai.zhongshangqihang.com/v1and replaceapi_keyat the same time. - Reconfirm model names on the model pricing page; do not carry official names over unchanged.
- Keep the original request body, remove extension parameters the gateway does not support, then add them back one by one.
- Compare output, latency, and
usageon the same set of real prompts for three to seven days. - Keep direct official access as a fallback channel and implement a rollback switch.
- Monitor 401, 429, 5xx, and timeouts; switch channels before debugging during incidents.
Migration is not just "change the address." Model mapping, parameter support, streaming behavior, and billing rules can all differ. Validate with a small share of traffic before moving production.
FAQ
Does the base URL include /v1?
The official endpoint includes /v1: https://api.mistral.ai/v1. The full chat completions path is https://api.mistral.ai/v1/chat/completions. With the OpenAI SDK, set base_url to /v1 and let the SDK append /chat/completions; do not write it twice.
Should I use -latest or a pinned model version?
For quick validation, an alias such as mistral-large-latest saves looking up version numbers. For production, a dated or generation-numbered pinned version is preferable: behavior is reproducible and rollback is easier. Either way, confirm current availability in the official documentation or console before launch.
Can I use the OpenAI SDK with the Mistral API?
The request shapes are close, and pointing base_url at https://api.mistral.ai/v1 with a Mistral key often works. However, the official documentation does not market it as an OpenAI-compatible product, and some parameters and error structures may differ. Validate with a minimal request first, then check each extension parameter your project uses.
Why is JSON mode not returning an object?
JSON mode ensures the output is valid JSON, but content is a string that you must parse. Call json.loads() first, then validate against the schema. Explicitly requesting JSON and the field structure in the prompt reduces empty fields and format drift.
Can an official key be used with the ZSQH Gateway address?
No. An official key corresponds to https://api.mistral.ai/v1, and a gateway key corresponds to https://ai.zhongshangqihang.com/v1. During migration, change the key and base URL as a pair; mixing them usually returns 401.
Related reading:
