Capabilities
Structured outputs
Get JSON that matches your schema from any model on LLM Router with response_format, and know how JSON mode differs.
Structured outputs make the model return JSON that follows a JSON Schema you supply. Set response_format on a chat completion, and LLM Router translates it to the structured output feature of the provider that serves the request.
There are two modes:
| Mode | response_format | What you get |
|---|---|---|
| Structured outputs | {"type": "json_schema", "json_schema": {...}} | JSON that follows your schema. |
| JSON mode | {"type": "json_object"} | Valid JSON, with no schema. Not available on every provider. |
Prefer structured outputs. They work on more providers and tell the model exactly which fields you expect.
Request a schema
curl --request POST \
--url https://api.inworld.ai/v1/chat/completions \
--header "Authorization: Basic $INWORLD_API_KEY" \
--header 'Content-Type: application/json' \
--data '{
"model": "openai/gpt-5",
"messages": [
{"role": "user", "content": "Extract the event: Alice and Bob meet for lunch on Friday."}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "calendar_event",
"strict": true,
"schema": {
"type": "object",
"properties": {
"title": {"type": "string"},
"day": {"type": "string"},
"participants": {"type": "array", "items": {"type": "string"}}
},
"required": ["title", "day", "participants"],
"additionalProperties": false
}
}
}
}'import json
import os
from openai import OpenAI
api_key = os.environ["INWORLD_API_KEY"]
client = OpenAI(
base_url="https://api.inworld.ai/v1",
api_key=api_key,
default_headers={"Authorization": f"Basic {api_key}"},
)
response = client.chat.completions.create(
model="openai/gpt-5",
messages=[
{"role": "user", "content": "Extract the event: Alice and Bob meet for lunch on Friday."}
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "calendar_event",
"strict": True,
"schema": {
"type": "object",
"properties": {
"title": {"type": "string"},
"day": {"type": "string"},
"participants": {"type": "array", "items": {"type": "string"}},
},
"required": ["title", "day", "participants"],
"additionalProperties": False,
},
},
},
)
event = json.loads(response.choices[0].message.content)The JSON arrives as a string in message.content. Parse it, and handle a response cut short by finish_reason: "length", which can leave the JSON incomplete.
json_schema fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | A name for the schema. |
schema | object | No | The JSON Schema the output must follow. |
strict | boolean | No | Ask the provider to enforce the schema exactly. Defaults to false. |
description | string | No | What the output is for. |
A json_schema format without a json_schema object, without a name, or with a schema that is not a JSON object returns 400.
Provider behavior
The router sends the format the provider understands. Support differs by provider:
| Provider | json_schema | json_object |
|---|---|---|
| OpenAI | Sent as is. | Sent as is. |
| Other OpenAI-compatible providers | Sent in OpenAI's format. Support depends on the provider and model. | Sent in OpenAI's format. Support depends on the provider and model. |
| Anthropic | Uses Anthropic's structured outputs. Only the schema is sent; name, description and strict are not. | Not supported. The format is dropped and the model answers normally. |
| Uses Gemini's JSON response schema. | Uses Gemini's JSON response type. |
On Gemini models earlier than Gemini 3, the response format is dropped when the request also includes tools, because those models do not accept both.
Each provider supports its own subset of JSON Schema. If you route across providers or use fallbacks, keep schemas simple (objects, arrays, strings, numbers, booleans and enums) so they work everywhere.
JSON mode
{"type": "json_object"} asks for valid JSON without a schema:
{
"model": "openai/gpt-5",
"messages": [
{"role": "system", "content": "Reply in JSON with the keys \"title\" and \"day\"."},
{"role": "user", "content": "Alice and Bob meet for lunch on Friday."}
],
"response_format": {"type": "json_object"}
}Describe the JSON you want in the prompt, because the model has no schema to follow. Anthropic models have no JSON mode, so a request routed to one returns ordinary text. Use json_schema when a request can reach Anthropic.
An unrecognized response_format.type is treated as text rather than rejected.