# Structured outputs in FastAPI via responses.parse
Structured Outputs guarantees the model returns JSON matching your schema. In
Python the shortest correct path is the parse helper, verified 2026-09-26.
## The call
```python
from pydantic import BaseModel
from openai import OpenAI
client = OpenAI()
class CalendarEvent(BaseModel):
name: str
date: str
participants: list[str]
response = client.responses.parse(
model="...",
input=[{"role": "user", "content": "Alice and Bob are going to a science fair on Friday."}],
text_format=CalendarEvent,
)
event = response.output_parsed # a CalendarEvent, not a string
```
FastAPI can return `event` directly; it is already a Pydantic model.
## Schema rules that 400
- Strict mode is the default posture: every field must be required or nullable.
`Optional[str]` without a default still needs handling; make truly-optional
fields `str | None = None` so the schema is total.
- The parse helper raises on refusal or schema mismatch instead of returning
half-JSON. Catch it and return a 502/429-style retryable error, not a 200 with
an empty body.
- Do not `json.loads(response.output_text)` yourself when you used parse. You get
a typed object; re-parsing the text throws away the guarantee.
## Check before you ship
- Send input that forces a refusal-adjacent edge (empty prompt) and confirm your
error path, not a 500.
- Log `response.usage` on parse calls; structured outputs do not change pricing,
but retries on 400s do change the bill.