SegmindSegmind / Docs

Structured Outputs

Constrain a chat model's reply to JSON — or to a JSON Schema you supply — with response_format, and know where the JSON arrives for each provider.

Chat models accept an OpenAI-style response_format, which turns "please reply in JSON" from a request the model may quietly ignore into a constraint the provider enforces:

{ "response_format": { "type": "json_schema", "json_schema": {
    "name": "person",
    "strict": true,
    "schema": {
      "type": "object",
      "properties": { "name": { "type": "string" }, "age": { "type": "integer" } },
      "required": ["name", "age"],
      "additionalProperties": false
    }
} } }

Leave the field out — or send { "type": "text" } — and the call behaves exactly as before, so existing integrations are unaffected.

The two modes

TypeWhat you get
json_objectValid JSON. The shape is up to the model, and it can change between calls.
json_schemaJSON that conforms to the schema you supply.

Prefer json_schema whenever you know the shape you want. json_object still leaves you writing defensive parsing code, because nothing stops the model from renaming a key or nesting the answer one level deeper next time.

Model support

Every chat model accepts both types, with these exceptions:

ModelsAccepts
claude-4.5-sonnet, claude-opus-4.7json_schema only
gpt-4, gpt-4-turbojson_object only
deepseek-chat, deepseek-reasonerjson_object only
qwq-plus, qvq-maxjson_object only
qwen3-coder-flash, qwen3-coder-plus, qwen3.5-flash, qwen3.5-plusjson_object only
claude-4-sonnetneither

Claude has no schema-less JSON mode, which is why json_object is refused there rather than approximated. The Qwen models above accept a schema upstream and then answer without enforcing it — a silently unconstrained reply is worse than a clear error, so the gateway refuses the type the model cannot honour.

Ask for an unsupported type and you get a 400 naming the one that works, before the request reaches the provider — never a surprise later.

Where the JSON arrives

The response keeps the provider's native envelope. Your JSON is a string in the usual text field, which you parse yourself:

ProviderField
OpenAI-compatible (GPT, DeepSeek, Qwen, Grok, OpenRouter)choices[0].message.content
Claudecontent[0].text
Geminicandidates[0].content.parts[0].text
{
  "choices": [
    { "message": { "role": "assistant", "content": "{\"name\":\"Mara Ellison\",\"age\":34}" } }
  ]
}

On v2

An async result carries the whole provider response as a string in output, so there are two decodes: one to get the envelope, one to get your object.

result = requests.get(poll_url, headers=headers).json()
envelope = json.loads(result["output"])                     # provider response
person = json.loads(envelope["choices"][0]["message"]["content"])  # your object

The Python SDK collapses both steps: ChatResponse.json() returns the parsed object on the sync and async paths alike.

Rules that produce a 400

OpenAI and DeepSeek require the word "json" in the conversation when you use json_object. The provider rejects the request outright:

'messages' must contain the word 'json' in some form, to use 'response_format' of type 'json_object'

Adding "Reply in json." to your prompt is enough. json_schema has no such rule.

Schemas are not portable between providers. Each enforces its own subset:

ProviderConstraint
OpenAI (strict: true)every property listed in required, and additionalProperties: false
Anthropicrejects minimum/maximum, minLength/maxLength and recursive $ref
Geminiaccepts full JSON Schema

The intersection — an object with every property required and additionalProperties: false, no numeric or length bounds — works everywhere. Write to that if one schema has to serve several models.

Errors

These come from the gateway, before the provider is called. On /v1 they are a 400; on /v2 the request lands as FAILED carrying the same message.

MessageCause
response_format must be an object with "type" one of: text, json_object, json_schemaThe field is not an object, or the type is unrecognised
response_format.json_schema.schema is required and must be a JSON schema objectjson_schema sent without a schema object
response_format type json_schema is not supported by this model; use type json_objectSee the support table above
this model does not support response_formatThe model supports neither type

A schema keyword the provider rejects surfaces as a 400 naming the keyword.

Examples

curl -X POST https://api.segmind.com/v1/gpt-5.4-mini \
  -H "x-api-key: $SEGMIND_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [{ "role": "user", "content": "Invent one person." }],
    "response_format": {
      "type": "json_schema",
      "json_schema": {
        "name": "person",
        "strict": true,
        "schema": {
          "type": "object",
          "properties": { "name": { "type": "string" }, "age": { "type": "integer" } },
          "required": ["name", "age"],
          "additionalProperties": false
        }
      }
    }
  }'

With the Python SDK, where .json() does the parsing:

import segmind

reply = segmind.chat_sync(
    "gpt-5.4-mini",
    messages=[{"role": "user", "content": "Invent one person."}],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "person",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {"name": {"type": "string"}, "age": {"type": "integer"}},
                "required": ["name", "age"],
                "additionalProperties": False,
            },
        },
    },
)

person = reply.json()   # {'name': 'Mara Ellison', 'age': 34}

.json() raises a SegmindError when the reply was not JSON — a refusal, for instance — so catch it rather than assuming the constraint always held.

Notes

  • Billing is unchanged. You pay the model's usual token rates; asking for structured output costs nothing extra.
  • No streaming. Structured replies arrive whole.
  • Schema-shaped output is also what powers fan-out from an LLM in PixelFlow, where the schema is derived from the fields your downstream nodes consume.

On this page