Core
Structured output
JSON mode and json_schema on the chat completions endpoint, the models that accept response_format, and the error for a model that does not.
On /v1/chat/completions, send response_format in one of the two OpenAI forms.
import json
reply = client.chat.completions.create(
model="gemini-3.5-flash",
messages=[{"role": "user", "content": "Nairobi, Kenya. Population about 5.5 million."}],
response_format={
"type": "json_schema",
"json_schema": {
"name": "city",
"strict": True,
"schema": {
"type": "object",
"properties": {
"city": {"type": "string"},
"country": {"type": "string"},
"population": {"type": "integer"},
},
"required": ["city", "country", "population"],
"additionalProperties": False,
},
},
},
)
print(json.loads(reply.choices[0].message.content))reply = client.chat.completions.create(
model="gemini-3.5-flash",
messages=[
{"role": "system", "content": "Reply with JSON only."},
{"role": "user", "content": "Nairobi, Kenya. Population about 5.5 million."},
],
response_format={"type": "json_object"},
)With json_object, put the word JSON in your messages, as with OpenAI. Use json_schema when you
can, because it controls the shape of the answer.
Models that accept response_format
Look for structured-output in supported_parameters of GET /v1/models, or for json in the
table on Models. At this time, the GPT and Gemini models show it, and the Claude
models do not.
If you send response_format to a model that does not show it, you get a 400 error. We do not
charge for that request:
{
"error": {
"message": "Model \"claude-sonnet-5-5\" does not support `response_format`. See supported_parameters on GET /v1/models for a model that does.",
"type": "invalid_request_error",
"param": "response_format",
"code": "unsupported_parameter"
}
}
Models that think first
GPT and Gemini models think before they write the JSON, and we charge for the thought tokens. If
max_tokens is only large enough for the JSON, the model can use all of it before it writes the
answer. Then you get an empty string. See Models.