API Intermediate medium · 6 min

response_format with JSON schema

What you will learn
Force Claude or GPT to return structured JSON matching your exact schema instead of free-form text.

Why this matters

Production systems need predictable output formats for parsing, validation, and downstream processing. Without response_format, you're parsing fragile text and building error handlers for hallucinations. JSON schema gives you guarantees.

Skip if: When you need flexibility in the response structure, when the task is pure reasoning without a defined output shape, or when you're building conversational UX where freeform text is the goal. Also avoid if your schema is so complex it confuses the model: break it into smaller schemas instead.

Explanation

What it does: The response_format parameter constrains the model to return JSON that conforms to a schema you define. You pass a JSON schema object, and the model's output is guaranteed to parse as valid JSON matching that schema. The model will refuse to deviate.

How it works: OpenAI's API uses grammar-constrained decoding on their servers. The model generates tokens, but the sampling layer rejects any token sequence that would violate your schema. This happens at inference time: the model learns what tokens are "legal" given your constraints. It does NOT use a separate validation step; the constraint is baked into token generation.

When to use it: Use response_format whenever your downstream code expects a specific JSON shape: extracting entities, generating structured API payloads, populating database records, or returning function arguments. If you're calling the API from another LLM or system expecting JSON, this is non-negotiable.

Request code

python
from openai import OpenAI
import json

client = OpenAI()

schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age": {"type": "integer"},
        "email": {"type": "string", "format": "email"},
        "skills": {
            "type": "array",
            "items": {"type": "string"}
        },
        "is_senior": {"type": "boolean"}
    },
    "required": ["name", "age", "email"]
}

response = client.chat.completions.create(
    model="gpt-4o-2024-11-20",
    messages=[
        {
            "role": "user",
            "content": "Extract structured info: 'Alice Johnson, 34 years old, alice@example.com, expert in Python and Kubernetes, senior engineer'"
        }
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "person_profile",
            "schema": schema,
            "strict": True
        }
    }
)

result = json.loads(response.choices[0].message.content)
print(json.dumps(result, indent=2))

Authentication

Set your OpenAI API key as an environment variable before running code: export OPENAI_API_KEY='sk-...'. The OpenAI client reads this at instantiation time. No explicit authentication method is needed in the code: the SDK handles it.

Response shape

FieldDescription
choices[0].message.content Valid JSON string matching your schema
choices[0].message.role Always 'assistant'
usage.prompt_tokens Tokens in your prompt and schema
usage.completion_tokens Tokens in the JSON response
model The model identifier you requested

Field guide

choices[0].message.content

This is a JSON string: you must parse it with json.loads(). The structure matches your schema exactly. All required fields are present.

usage.completion_tokens

Slightly higher than free-form responses because the model is constrained. Budget for this in rate-limit calculations.

function_call or tool_use fields

NOT present when using response_format. The schema parameter replaces function calling for structured output. If you need both, use tools instead.

Setup trap

If you set os.environ['OPENAI_API_KEY'] in your script but call OpenAI() before that line, the client initialization fails silently and later API calls error with 'invalid_api_key'. Always set environment variables before importing and instantiating OpenAI(). Alternatively, pass the key explicitly: OpenAI(api_key='sk-...').

Cost

JSON schema constraining does not incur extra cost per se, but the schema definition itself adds tokens to your prompt if it's large. A 500-field schema counts as ~200 tokens. Reuse schema objects across requests rather than inlining them repeatedly.

Rate limits

Responses with strict JSON schema conformance do not trigger additional rate limits, but they may take slightly longer to generate (a few extra milliseconds). This is negligible unless you're calling at 1000+ req/s, at which point you should batch.

Common gotcha

Passing an invalid schema (missing 'required' key, circular references, or unsupported types like 'null') causes the API to reject the request silently or return an error about schema validation. Always validate your schema JSON against the JSON Schema draft 2020-12 spec before shipping. Also: the model will refuse to answer if it cannot produce output matching your schema: a schema that's too strict for the task causes evasive responses like 'I cannot complete this task.'

Error recovery

BadRequestError 'invalid json schema'
Your schema violates JSON Schema spec. Check for circular $ref, undefined type values, or missing 'properties' on objects. Use a JSON schema validator tool online.
APIError 'Invalid response format'
The model cannot generate output matching your schema given the task. Loosen constraints, make fields optional, or simplify the schema.
json.JSONDecodeError when parsing response
The schema was not strict enough and the model output non-JSON. Add 'strict': True to json_schema config and ensure all enum/const values are explicitly typed.
ValidationError 'schema must have a name'
You forgot to set the 'name' field inside json_schema. This field is required and must be a string like 'person_extractor'.

Experienced dev note

Most developers think strict JSON schema only validates output: but it actually shapes model behavior during generation. A well-designed schema (with 'required' fields, clear descriptions, and realistic enums) guides the model toward correct answers faster than a loose schema. Invest in schema design. Also: 'strict': True is not the default in older SDKs: always set it explicitly to catch schema violations early. And one more thing: response_format guarantees the JSON is valid, but NOT that the values are semantically correct. A schema validates structure, not truth. Add post-parsing validation for business logic.

Check your understanding

You define a schema with 'required': ['email'] and the user's input contains no email address. What does the model do, and why doesn't it just return null for email?

Show answer hint

The constraint is enforced at token generation time. The model cannot output a JSON object missing 'email' because the grammar forbids it. Instead, the model will either (1) fabricate a plausible email based on context, or (2) refuse the task. There is no 'null' option unless your schema explicitly allows 'type: ["string", "null"]'.

VERSION JSON schema with strict mode was introduced in openai 1.3.0 (May 2024). Older versions use 'type': 'json_object' without schema validation. If you're on openai < 1.3.0, upgrade: pip install --upgrade openai. The 'strict': True parameter is available in gpt-4o-2024-11-20, gpt-4-turbo, and later. It is NOT supported in gpt-3.5-turbo.

Community Notes

No notes yetBe the first to share a version-specific fix or tip.