Structured outputs
Constrain a completion to a JSON Schema you supply, and get content that validates against it.
Send response_format: {"type": "json_schema", ...} and the returned content
parses as JSON and validates against your schema. If it does not, you get an
error — never unvalidated content presented as a success.
Supported on atlas-small-1, atlas-mid-1, and atlas-large-1. Not
supported on atlas-code-1. Check capabilities.structured_output on
GET /v1/models.
Making a request
The schema lives at response_format.json_schema.schema — the Chat Completions
nesting, not the Responses API's text.format.schema.
strict defaults to on. Omitting it, or sending strict: true, both get the
full subset treatment. Only an explicit strict: false opts out of the
strictness flag — but the schema is still validated against the subset either
way, because a schema accepted loosely is a schema nothing enforces.
Three rules your schema must follow
Beyond the keyword subset, strict mode imposes three structural rules. They are OpenAI's strict-mode rules, and they catch most first-time failures:
The root must be an object schema
Not an array, not a string. Wrap a list in an object with a single property.
Violation code: root_not_object.
Every property must be listed in `required`
There are no optional properties. To model "may be absent", give the
property a type union including null and require it. Violation code:
optional_property.
Every object must set `additionalProperties: false`
At every level, not just the root. Violation code: additional_properties.
Nesting is limited to 5 levels, and $ref must be a local
#/$defs/<name> pointer that resolves within the same document.
When a schema is rejected
A schema outside the subset is refused at validation, before the request is admitted — you are never charged for a request whose schema could not have been enforced, and you never receive unvalidated content in its place.
{
"error": {
"message": "the keyword 'pattern' is not in this subset; ...",
"type": "invalid_request_error",
"param": "response_format.json_schema.schema",
"code": "unsupported_json_schema",
"request_id": "req_01k4v9m2..."
}
}The message names the offending keyword and its RFC 6901 pointer into your schema document, so the fix is mechanical. See the subset reference for the full keyword lists and every violation code.
When the output does not validate
Content is checked against your schema after generation. Two failures are possible, and both are distinguishable from a schema you got wrong:
structured_output_not_jsonerror codeThe model's content did not parse as JSON at all.
structured_output_schema_violationerror codeThe content parsed, but did not validate against the schema you supplied.
On a streamed request, the check runs on the assembled content — so the
deltas are delivered first, and then the stream terminates with an in-band
error frame and no [DONE]. Your accumulated content is the invalid
document; do not treat it as a completed generation. See
Streaming.
Generating a schema from your types
Most schema generators emit keywords outside the subset by default. Two notes:
- Pydantic /
zod: emit$defsand$ref, which are supported. They also emit constraints likeminLength,pattern, andminimum, which are not. Strip them before sending, or express those bounds in the prompt and validate them yourself after parsing. defaultis accepted, so azod.default()does not break the schema. It is carried as an annotation and never enforced — it constrains no instance's validity.
Not the same as tool schemas
A tool's function.parameters document is not validated against this
subset — it is passed through to the backend as you send it. Only
response_format.json_schema.schema is checked. See
Tool calling.