Skip to content

Structured outputs

Force the model to return valid JSON with response_format.

POST/v1/chat/completions

The response_format parameter constrains the model output to structured JSON. {"type": "json_object"} forces the response to be valid JSON, while {"type": "json_schema", ...} constrains it to a schema you supply. This value is an opaque passthrough to OpenAI-compatible providers; the backend performs no schema validation.

Request#

ParameterTypeRequiredDescription
response_formatobjectOptional{"type": "json_object"} (force valid JSON) or {"type": "json_schema", "json_schema": {...}} (schema-constrained). The format you specify is forwarded as-is to the routed provider.

When using {"type": "json_object"}, instruct the model to reply with JSON in your messages (typically the system prompt). Without guidance on the JSON shape you expect, output may be inconsistent.

json_object request
curl https://apirouter.pleum.ai/v1/chat/completions \
  -H "Authorization: Bearer plm_..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [
      {"role": "system", "content": "Extract the user info. Reply with JSON only."},
      {"role": "user", "content": "Jane Doe is 31 and lives in Seoul."}
    ],
    "response_format": {"type": "json_object"}
  }'

json_schema support#

json_schema support depends on the routed model — not every provider or model supports schema-constrained output. PleumRouter forwards response_format to the provider without validating or modifying it, so sending it to an unsupported model may cause the provider to return an error or ignore the field.

json_schema request body
{
  "model": "gpt-4o-mini",
  "messages": [
    {"role": "user", "content": "Jane Doe is 31 and lives in Seoul."}
  ],
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "person",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "name": {"type": "string"},
          "age": {"type": "integer"},
          "city": {"type": "string"}
        },
        "required": ["name", "age", "city"],
        "additionalProperties": false
      }
    }
  }
}

Anthropic (Claude) caveat#

response_format is not translated for Anthropic (Claude) models — it is silently ignored there. To force JSON on Claude, use tool calling with tools and tool_choice to define the schema instead.

Define the JSON shape you want as the function's parameters and force that tool with tool_choice, as shown below. The model then calls the tool with arguments matching the schema, and the structured output appears in the arguments (a JSON string) of tool_calls.

tool calling on Claude
{
  "model": "claude-sonnet-4-6",
  "messages": [
    {"role": "user", "content": "Jane Doe is 31 and lives in Seoul."}
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "save_person",
        "description": "Save the extracted person record.",
        "parameters": {
          "type": "object",
          "properties": {
            "name": {"type": "string"},
            "age": {"type": "integer"},
            "city": {"type": "string"}
          },
          "required": ["name", "age", "city"]
        }
      }
    }
  ],
  "tool_choice": {"type": "function", "function": {"name": "save_person"}}
}

Response#

The structured output is returned as a JSON string in choices[0].message.content and must be parsed before use. On normal completion, finish_reason is "stop".

200 OK
{
  "id": "chatcmpl-gpt-4o-mini-512ms",
  "object": "chat.completion",
  "model": "gpt-4o-mini",
  "provider": "openai",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "{\"name\":\"Jane Doe\",\"age\":31,\"city\":\"Seoul\"}"
      },
      "finish_reason": "stop"
    }
  ]
}