Guides · Structured outputs
Structured outputs: JSON that matches your schema
Structured outputs make a model answer with JSON that follows a schema you define, instead of free text you have to parse. Use them whenever a program reads the result: extracting fields from documents, classifying tickets, routing requests or filling a form. The request format is the OpenAI `response_format` field, and the output is constrained while it is generated.
- 01API format: OpenAI
- 02EU data centres
- 03Covered by one DPA
import json, os
from openai import OpenAI
client = OpenAI(base_url="https://api.inference.eu/v1", api_key=os.environ["INFERENCE_EU_API_KEY"])
schema = {
"type": "object",
"properties": {
"supplier": {"type": "string"},
"invoice_number": {"type": "string"},
"issue_date": {"type": "string", "description": "ISO 8601 date"},
"currency": {"type": "string", "enum": ["EUR", "GBP", "CHF", "PLN", "SEK"]},
"total": {"type": "number"},
"vat_id": {"type": ["string", "null"]},
},
"required": ["supplier", "invoice_number", "issue_date", "currency", "total", "vat_id"],
"additionalProperties": False,
}
reply = client.chat.completions.create(
model="gpt-oss-120b",
messages=[
{"role": "system", "content": "Extract invoice fields. Use null when a field is missing."},
{"role": "user", "content": open("invoice.md").read()},
],
response_format={
"type": "json_schema",
"json_schema": {"name": "invoice", "schema": schema, "strict": True},
},
)
invoice = json.loads(reply.choices[0].message.content)How structured outputs work
Add response_format with type: "json_schema" and a json_schema object containing a name, your schema written as JSON Schema, and strict: true. While the model generates, the API restricts each token to those that keep the output valid against the schema. The result in message.content is a JSON string you can parse directly.
This is more reliable than asking for JSON in the prompt. The model cannot add a sentence before the opening brace, leave out a required field or invent a property you did not define. You still describe the task in the prompt; the schema controls the shape, the prompt controls the content.
JSON mode and schema design
response_format: {"type": "json_object"} is the looser option, called JSON mode. The output is guaranteed to be valid JSON, but not to follow any particular structure, so mention the expected fields in the prompt. Prefer json_schema whenever you know the shape.
Keep schemas simple and explicit. List every property in required and set additionalProperties to false, which strict mode expects. Represent optional values as a type that allows null, as with vat_id in the example, so the model can say "not found" instead of guessing. Use enum for fixed categories, and add a description to fields whose meaning is not obvious from the name.
A practical extraction pipeline
A common pattern turns documents into data. Convert each PDF to Markdown with the document conversion tool, send the text with a short system prompt and your schema, and parse the result. Validate the parsed object with the same schema in your code, then check business rules the schema cannot express, such as totals adding up.
For thousands of documents, put the same requests into a batch job. Keep a field for the model's confidence or a short notes string if reviewers need to know why a value was chosen. With the Responses API, the same schema goes into text.format instead of response_format.
Errors and edge cases
Very large or deeply nested schemas, and unusual keywords such as complex pattern expressions or oneOf with overlapping branches, may be rejected with a 400 error that names the unsupported part. Split such schemas or simplify them.
The schema guarantees the format, not the facts. A model can still put a wrong date in a valid date field, so check important values. If generation stops at max_tokens, the JSON is cut off and will not parse; check finish_reason and raise the limit. Reasoning models think before they write the JSON, so leave room for both. Refusals for unsafe requests are returned as text, not as schema output.
Structured outputs: common questions
The questions buyers, developers and legal teams ask us most. Something missing? Ask us directly.
Related
- Tool callingLet open models call your functions and APIs with OpenAI-compatible tool calling. Define tools, run the loop, handle arguments, processed in the EU.Guides
- Document conversionConvert PDF, Word, PowerPoint and Excel files to clean Markdown for RAG and LLM prompts. Tables, headings and scanned pages, processed in the EU.Tools
- Chat completionsSend chat messages to open-weight models with the OpenAI chat completions format. Requests are processed in EU data centres and never used for training.Endpoints
- BatchesRun thousands of chat or embedding requests as one asynchronous job with an OpenAI-compatible batch API. Upload JSONL, collect results, all in the EU.Endpoints
Move your AI workloads to EU infrastructure
Tell us which models you use and roughly how much traffic you have. We reply within one working day with pricing and next steps.
- Reply within one working day
- Pricing for your volume
- DPA ready to sign