Skip to main content
When you want a response you can parse rather than a sentence, set response_format to a JSON Schema. The model produces JSON that matches it, and the gateway validates the response against the schema before returning it. This is the standard OpenAI-compatible parameter, so it works from any SDK you point at Opper. Reach for structured output to parse a receipt, extract fields from a contract, classify a support ticket, or any job where you describe the shape you want back.

A working example

import os, json
from openai import OpenAI

client = OpenAI(
    base_url="https://api.opper.ai/v3/compat",
    api_key=os.environ["OPPER_API_KEY"],
)

r = client.chat.completions.create(
    model="openai/gpt-5-mini",
    messages=[
        {"role": "user", "content": "Pick a category for: 'My reset link is broken.'"}
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "ticket",
            "schema": {
                "type": "object",
                "properties": {
                    "category":   {"type": "string"},
                    "priority":   {"type": "string"},
                    "confidence": {"type": "number"},
                },
                "required": ["category", "priority", "confidence"],
            },
        },
    },
)

result = json.loads(r.choices[0].message.content)
print(result["category"], result["priority"])
The content field comes back as a JSON string. Parse it once to get a typed object. If the model can’t produce something that matches the schema, the call fails with a validation error rather than silently returning malformed JSON.
The Anthropic and Google AI SDKs reach the same behaviour through their own structured-output options. Whichever SDK you use, the gateway validates the result against your schema. See Drop-in SDKs.

Writing the schema

The schema is plain JSON Schema. A handful of patterns cover almost everything you’ll need.

Enums (one of a fixed set)

When the answer is one of a fixed set of values, use an enum. The model is far more reliable on these than on free strings.
"priority": { "type": "string", "enum": ["low", "medium", "high"] }

Optional fields

List required fields in the required array. Anything left out can come back as null.
{
  "type": "object",
  "properties": {
    "name":  { "type": "string" },
    "email": { "type": "string" }
  },
  "required": ["name"]
}

Arrays

"items": { "type": "array", "items": { "type": "string" } }

Nested objects

{
  "type": "object",
  "properties": {
    "merchant": { "type": "string" },
    "items": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "description": { "type": "string" },
          "price":       { "type": "number" }
        },
        "required": ["description", "price"]
      }
    },
    "total": { "type": "number" }
  },
  "required": ["merchant", "items", "total"]
}

Field descriptions

Describe ambiguous fields. The model reads descriptions as guidance.
"priority": {
  "type": "string",
  "enum": ["low", "medium", "high"],
  "description": "Use 'high' when the user can't access their account."
}

Structured output from images, PDFs, and audio

Structured output composes with multimodal input. Put the image, PDF, or audio in the message content and set response_format to the shape you want back. See Vision & PDFs for how to attach media.

When to use what

NeedReach for
Typed JSON from a modelresponse_format: json_schema (this page)
Model that calls your code mid-conversationTool calling
Multimodal input with structured outputVision & PDFs + response_format

What’s next

Tool calling

When the model should call your code, not just answer.

Vision & PDFs

Send images and documents, get structure back.

Streaming

Stream the response as it’s generated.

Control Plane

Govern, score, and improve every call.