Structured outputs
MirAPI supports OpenAI-style structured outputs: pass a response_format parameter and the model returns JSON that matches your schema instead of free-form text. Use it whenever your app needs machine-readable answers without parsing errors or hallucinated fields.
json_schema
Section titled “json_schema”Set response_format.type to json_schema and provide a json_schema object describing the shape the model must return:
| Parameter | Type | Description |
|---|---|---|
type |
string | json_schema (schema-enforced) or json_object (free-form JSON). |
json_schema |
object | Required when type is json_schema. |
The json_schema object takes three fields:
| Field | Type | Description |
|---|---|---|
name |
string | A label for the schema. |
strict |
boolean | When true, models with native support enforce the schema exactly. |
schema |
object | The JSON Schema the output must satisfy. |
Complete invoice-extraction example:
import osimport jsonfrom openai import OpenAI
client = OpenAI(base_url="https://api.mirapi.ai/v1", api_key=os.environ["MIRAPI_API_KEY"])
schema = { "type": "object", "properties": { "vendor": {"type": "string", "description": "Company issuing the invoice"}, "invoice_number": {"type": "string"}, "date": {"type": "string", "description": "Invoice date in YYYY-MM-DD"}, "items": { "type": "array", "items": { "type": "object", "properties": { "description": {"type": "string"}, "quantity": {"type": "number"}, "unit_price": {"type": "number"}, "total": {"type": "number"}, }, "required": ["description", "quantity", "unit_price", "total"], "additionalProperties": False, }, }, "total_amount": {"type": "number"}, "currency": {"type": "string"}, }, "required": ["vendor", "invoice_number", "date", "items", "total_amount", "currency"], "additionalProperties": False,}
response = client.chat.completions.create( model="deepseek-chat", messages=[ {"role": "system", "content": "Extract the invoice fields from the text."}, {"role": "user", "content": "Acme Corp, INV-2026-001, 2026-08-01. 12 widgets at $4.50 each ($54.00), 2 crates at $10.00 ($20.00). Total $74.00 USD."}, ], response_format={"type": "json_schema", "json_schema": {"name": "invoice", "strict": True, "schema": schema}},)
print(json.dumps(json.loads(response.choices[0].message.content), indent=2))With strict: true, models that natively support strict mode enforce the schema exactly. Enforcement varies by provider — some translate the schema into their own structured-output format or treat it as a strong hint — so validate the output in your code regardless.
json_object
Section titled “json_object”When you only need “some valid JSON” and don’t care about the exact shape, use type: "json_object":
response = client.chat.completions.create( model="deepseek-chat", messages=[{"role": "user", "content": "Return JSON: name and price of the cheapest phone"}], response_format={"type": "json_object"},)json_object guarantees valid JSON, not a specific structure. Pair it with an explicit prompt listing the keys you want.
Streaming
Section titled “Streaming”Structured outputs stream as standard SSE (data: lines, ending with data: [DONE]). Add stream: true and the model emits valid partial JSON — concatenate the deltas and parse once the stream ends:
{ "model": "deepseek-chat", "stream": true, "response_format": { "type": "json_schema", "json_schema": { "name": "invoice", "strict": true, "schema": { "type": "object" } } }}Model support
Section titled “Model support”Structured outputs require a model with JSON output capability. Check the supported_parameters field of the model catalogue (via GET /v1/models or the console at https://console.mirapi.ai). A model without the capability may reject response_format or return invalid JSON — see the Error handling section below.
Error handling
Section titled “Error handling”Errors use the OpenAI error envelope: {"error":{"message","type","param","code"}}. Every message ends with a request ID — include it in support tickets. Common situations:
- Invalid JSON Schema — the request fails with an error describing the problem.
- Model without JSON output — the request is rejected; pick a model whose
supported_parametersincludes JSON output. - 401 — missing, invalid, or unknown key; fix your credentials.
- 403 — the key is valid but rejected: insufficient balance, model whitelist, quota, or IP allowlist.
- 413 — payload too large; shrink the request.
- 429 — rate limited; retry with jittered exponential backoff (1s → 2s → 4s, capped around 30s). There is no
Retry-Afterheader. - 500 — gateway or upstream failure; idempotent requests are safe to retry.
See the errors reference for the full envelope and recovery guidance.
Troubleshooting
Section titled “Troubleshooting”The model returns invalid JSON anyway. Strict enforcement varies by provider. Parse defensively: strip markdown code fences, retry once, or re-ask with the schema embedded in the prompt. As a last resort, fall back to prompting:
Return ONLY a JSON object with exactly these keys:{"vendor": string, "invoice_number": string, "total_amount": number}Do not include markdown code fences or commentary.Extra or unexpected fields. Add "additionalProperties": false to the schema and the top-level object, and give each property a description to guide the model.
Related links
Section titled “Related links”- Model catalogue — check
supported_parametersfor JSON output - Tool calling — function calling for structured actions
- Reasoning models — reasoning controls
- Errors reference — error envelope and status codes