Build
Structured output
Request schema-constrained JSON through the Messages API and validate the result.
Supported models
Chat Completions response_format is enforced on models whose
supported_parameters in the public catalog
include structured_outputs (JSON Schema) or response_format (JSON mode).
MiniRouter sends the request only to providers verified to enforce it, and
streaming works the same way.
Messages output_config.format is enforced on openai/gpt-4.1-mini and
anthropic/claude-opus-5.
On any other model, or when your key excludes every verified provider, the
format is removed, the model answers in plain text, and the response carries
x-minirouter-structured-output: ignored. Responses text.format is
currently always ignored this way. A malformed format still returns 400.
To get an error instead of plain text, add "provider": {"require_parameters": true}.
The request then returns 400 naming the model whenever the format cannot be
enforced.
Structured requests go only to verified providers. When those providers are at
capacity you receive 429 where a plain request would have moved to another
provider.
minirouter/auto picks the first candidate that enforces your format and drops
the format only when none can. A models fallback list keeps the format when
the first model enforces it; fallbacks that cannot are left out of that request.
See the verification report for the tested model/provider pairs, method and results.
Set your key
Create an API key, save its recovery link, and add credits. Replace the placeholder below and run it in your terminal before running the examples on this page.
export MINIROUTER_KEY='paste-your-api-key-here'Examples use paid models. For free requests, follow the Auto Free guide.
Send a schema request
Run this in the same terminal. The schema requires both fields and rejects extra properties.
curl https://api.minirouter.sh/v1/chat/completions \
-H "Authorization: Bearer $MINIROUTER_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-5.4-mini",
"max_tokens": 256,
"messages": [
{
"role": "user",
"content": "Extract the city and country: I live in Paris, France."
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "place",
"strict": true,
"schema": {
"type": "object",
"properties": {
"city": {
"type": "string"
},
"country": {
"type": "string"
}
},
"required": [
"city",
"country"
],
"additionalProperties": false
}
}
}
}'For JSON without a schema, send "response_format": {"type": "json_object"}
and ask for JSON in the prompt.
The Messages API takes the same schema under output_config.format:
curl https://api.minirouter.sh/v1/messages \
-H "Authorization: Bearer $MINIROUTER_KEY" \
-H "Content-Type: application/json" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "openai/gpt-4.1-mini",
"max_tokens": 256,
"messages": [
{
"role": "user",
"content": "Extract the city and country: I live in Paris, France."
}
],
"output_config": {
"format": {
"type": "json_schema",
"schema": {
"type": "object",
"properties": {
"city": {
"type": "string"
},
"country": {
"type": "string"
}
},
"required": [
"city",
"country"
],
"additionalProperties": false
}
}
}
}'To extract different data, change the prompt and the properties and
required entries in the schema. Keep additionalProperties: false for an
object with only the named fields.
Read and validate the result
A Chat Completions response carries the JSON string in
choices[0].message.content; check that finish_reason is stop.
A successful Messages response contains text blocks in its content array.
Join the text values from blocks whose type is text, then parse that
string as JSON. The text for this example should have this shape:
{"city":"Paris","country":"France"}Check the response status and stop_reason before using the object. A refusal,
error or max_tokens stop is not a completed schema result. Validate the
parsed object against your schema in your application.
Stream structured output
Add "stream": true to the same request and use curl -N. On Chat
Completions, join choices[0].delta.content until data: [DONE]. On
Messages, collect text from content_block_delta events with delta.type: "text_delta". Wait for
message_stop, check the final stop reason, and then parse the complete text.
Individual chunks may contain only part of a JSON token.
Troubleshooting
400 invalid_request_error: check the model, endpoint andoutput_config.formatshape. Simplify a schema that exceeds request limits.- A truncated response: increase
max_tokensor ask for a smaller object. - A refusal: handle it separately from schema output; do not parse it as your data object.
- No eligible provider: check your key's model and provider restrictions, or try again later.
- Plain text with
x-minirouter-structured-output: ignored: the model or your allowed providers cannot enforce the format. Pick a model listingstructured_outputs, or sendprovider.require_parametersto fail fast.
Thinking and tool controls have separate model requirements. Start with the schema-only request above, then add supported controls one at a time.