runaiicloud
ModelsAppsGPUsServerless GPUPricingReserveDocsConnectCompareEnterprise
Log inGet started
runaiicloud docs
status →
⌘⌘K
Get started
Quickstart
API reference
Authentication & API keysStreamingErrorsModels catalogFunction calling & tool useStructured outputs
Billing & limits
Pricing, metering & prompt cachingRate limits & tiers
Bring your own model →Blog ←Get an API key →Changelog
Authentication & API keysPricing, metering & prompt cachingQuickstartRate limits & tiersStreamingErrorsModels catalogFunction calling & tool useStructured outputs
docs/API reference/Structured outputs
On this page▸
Two shapesWhich models support itRunnable requestWhat comes backResponses API (/v1/responses)Limits
API reference

Structured outputs

Constrain replies to valid JSON with response_format — json_object and json_schema, on chat completions and the Responses API.


Two shapes

/v1/chat/completions accepts response_format and forwards it to the engine as sent:

response_format What you get
{ "type": "json_object" } the reply is a JSON object — no schema, just valid JSON
{ "type": "json_schema", "json_schema": { "name": "…", "schema": { … }, "strict": true } } guided decoding against your schema — strict is optional

This is guided decoding (a grammar constraint on the sampler). It is independent of the tool-call parser, so it works on models that cannot call tools.

Which models support it

The live catalog declares structured_outputs: { "type": "boolean" } and response_format: { "type": "boolean" } on every text model it lists — today that is glm-5.3, deepseek-v4-flash and qwen3.8-flash.

Read the flags from the catalog rather than hardcoding the list, and check the entry's is_ready flag before putting a model on a production path:

curl https://api.runaii.cloud/v1/models

Runnable request

curl https://api.runaii.cloud/v1/chat/completions \
  -H "Authorization: Bearer $RUNAII_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4-flash",
    "messages": [
      {"role": "system", "content": "Extract the invoice fields."},
      {"role": "user", "content": "Invoice #A-1024, due 2026-11-01, total 420.00 USD."}
    ],
    "response_format": {
      "type": "json_schema",
      "json_schema": {
        "name": "invoice",
        "strict": true,
        "schema": {
          "type": "object",
          "properties": {
            "invoice_number": {"type": "string"},
            "due_date": {"type": "string"},
            "total": {"type": "number"},
            "currency": {"type": "string"}
          },
          "required": ["invoice_number", "due_date", "total", "currency"],
          "additionalProperties": false
        }
      }
    }
  }'

What comes back

message.content is a string containing the JSON object — JSON.parse it before using it. finish_reason is "stop" on a complete answer ("length" if max_tokens cut it short), and usage reports the real token counts and the exact cost you were charged (see pricing):

{
  "id": "rq-...",
  "object": "chat.completion",
  "model": "deepseek-v4-flash",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "{\"invoice_number\":\"A-1024\",\"due_date\":\"2026-11-01\",\"total\":420,\"currency\":\"USD\"}"
      },
      "finish_reason": "stop"
    }
  ]
}

Responses API (/v1/responses)

The Responses dialect carries the same two modes under text.format, and it is translated onto response_format for you:

text.format response_format sent to the engine
{ "type": "text" } none — the default, unconstrained
{ "type": "json_object" } { "type": "json_object" }
{ "type": "json_schema", "name": "…", "schema": { … }, "strict": true } { "type": "json_schema", "json_schema": { "name": "…", "schema": { … }, "strict": true } }
curl https://api.runaii.cloud/v1/responses \
  -H "Authorization: Bearer $RUNAII_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4-flash",
    "input": "Invoice #A-1024, due 2026-11-01, total 420.00 USD.",
    "text": {
      "format": {
        "type": "json_schema",
        "name": "invoice",
        "strict": true,
        "schema": {
          "type": "object",
          "properties": {
            "invoice_number": {"type": "string"},
            "due_date": {"type": "string"},
            "total": {"type": "number"},
            "currency": {"type": "string"}
          },
          "required": ["invoice_number", "due_date", "total", "currency"],
          "additionalProperties": false
        }
      }
    }
  }'

The answer arrives in the message output item's output_text content part, and usage carries input_tokens, output_tokens, total_tokens and cost — the same metering as chat completions.

Limits

  • json_schema needs a name and a schema. On the Responses path a text.format that is not text, json_object or json_schema + name + schema is rejected with 400 invalid_request (param: "text.format").
  • A schema the engine rejects is a 400, not a bill. The upstream refusal comes back as 400 upstream_rejected with no credits spent — check messages, tools, response_format and max_tokens when you see it.
  • Constrained shape, not constrained content. The schema fixes the output structure; the values still come from the model, so keep validating business rules on your side.
  • Not a tool substitute. response_format shapes the answer text; to have the model ask you to run code, use function calling instead.

On this page

Two shapesWhich models support itRunnable requestWhat comes backResponses API (/v1/responses)Limits

← Previous

Function calling & tool use

runaiicloud

Serverless inference, dedicated GPUs, and training for open models. OpenAI- and Anthropic-compatible APIs.

© 2026 runaii

Platform

Model libraryAppsGPUsServerless GPUPricingToken-Max coding plansCompare providersDocs

Developers

ConnectCookbookCLIAgents / MCPUse casesTutorialsBlogFAQ

Company

EnterpriseStartupsAboutCareersTrust centerStatusSupportTermsPrivacySitemap