OP Inference

Structured output

Make a model reply with JSON that matches a schema.

Send response_format in the OpenAI format. The request is routed only to endpoints that support the level you ask for.

response_format.typeWhat you get
json_schemaJSON that should match the schema you supply
json_objectValid JSON, with no schema enforced
textThe default
curl https://api.opinference.com/v1/chat/completions \
  -H "Authorization: Bearer $OP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-oss-120b",
    "messages": [{"role": "user", "content": "Name a city and its country."}],
    "response_format": {
      "type": "json_schema",
      "json_schema": {
        "name": "place",
        "strict": true,
        "schema": {
          "type": "object",
          "properties": {
            "city": {"type": "string"},
            "country": {"type": "string"}
          },
          "required": ["city", "country"],
          "additionalProperties": false
        }
      }
    }
  }'

The reply's message.content is the JSON as a string:

{"city": "Kyoto", "country": "Japan"}

Validate the reply before you use it. Endpoints differ in how strictly they hold a model to the schema, and a reply can occasionally be malformed JSON. Parse it, and retry or fall back when parsing fails.

With the Python SDK, client.beta.chat.completions.parse and a Pydantic model build the schema for you and parse the reply. It raises an error when the reply does not parse:

import os
from openai import OpenAI
from pydantic import BaseModel

class Place(BaseModel):
    city: str
    country: str

client = OpenAI(base_url="https://api.opinference.com/v1", api_key=os.environ["OP_API_KEY"])
reply = client.beta.chat.completions.parse(
    model="openai/gpt-oss-120b",
    messages=[{"role": "user", "content": "Name a city and its country."}],
    response_format=Place,
)
print(reply.choices[0].message.parsed)

If no endpoint for the model supports the requested level, the request is refused with 404 no_endpoint_available rather than answered as plain text. The message names the filters that excluded the model's endpoints, for example model "..." has no endpoint this request can use; excluded by: capability.