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.

Set your key
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.

Send a schema request
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:

Send a schema request
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:

Read and validate the result
{"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 and output_config.format shape. Simplify a schema that exceeds request limits.
  • A truncated response: increase max_tokens or 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 listing structured_outputs, or send provider.require_parameters to 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.

Esc