ModelSiteAPI

Responses (OpenAI)

POST /v1/responses — OpenAI Responses API, with complete examples by scenario

OpenAI's newer Responses API (/v1/responses). For requests whose upstream natively supports Responses, the request and response are passed through almost unchanged; for the rest, the platform converts to Chat Completions, runs the same routing pipeline, and converts the response back to Responses format. It suits code that uses the responses interface of the new OpenAI SDK.

This page is organized by scenario: start with the scenario overview, then go to the section for request, response and caveats. Every example carries an evidence label. Tested means it was called for real with a live test account (2026-10-19); response fields come from the real reply, with id, timestamps and text replaced by placeholders. Per official docs (not tested) means it was written from the OpenAI documentation and we did not verify it with a real call.

The same model can return different response shapes: a model may have both native and converted upstreams, and routing decides which one each request lands on. In testing, two requests to glm-5.3-flash got the two shapes: the native shape has many echo fields (background, tools, top_p and so on) and upstream-specific fields; the converted shape has no upstream-specific fields. The converted shape is aligned with the official one: every event carries sequence_number, id starts with resp_, the response object echoes the request parameters, thinking uses summary, and thinking comes first in output. Read both shapes the same way: use output[] and usage, and do not depend on the exact values of echo fields. Each example on this page says which shape it is.

Scenario overview

Scenarios follow OpenAI's Text generation, Streaming, Function calling, Structured outputs, Reasoning, Images and vision, Conversation state and Tools guides.

ScenarioOffered officiallyOur statusExample
Basic chat (string input, instructions)YesSupportedBasic chat
Multi-turn (array input with history, developer / user roles)YesSupportedMulti-turn
StreamingYesSupportedStreaming
Function calling (function_call / function_call_output)YesSupportedFunction calling
Structured output (json_schema in text.format)YesSupportedStructured output
Reasoning (reasoning)YesSupportedReasoning
Image input (input_image)YesPartial: needs a vision model; base64 tested, public URL not tested, file_id not supportedImage input
Stateful continuation (previous_response_id, conversation)YesNot supported: the platform does not store responses. In testing, a request with previous_response_id could not see the previous turn; send the full input yourself—
Built-in tools (web_search, file_search, code_interpreter, computer_use, mcp, image_generation)YesNot supported: the converted path keeps only function / custom and drops the other built-in tools; web_search is converted to web_search_options, which had no search effect on live models in testing—
Custom tools and grammar constraints (custom tools, CFG)YesPartial: custom is converted to a function with a single string parameter; grammar constraints are not supported; not tested—
Background tasks and webhooks (background)YesNot supported: forwarded to the upstream with no Responses semantics; it does not run in the background—
Conversation compaction (/v1/responses/compact)YesPartial: the endpoint exists; not tested—
Retrieve / delete / cancel (GET, DELETE, cancel)YesPartial: only valid for responses created by native upstreams, see "Other methods"—

Basic chat

When to use: one question, one answer; use instructions to set role and tone.

Evidence: tested (live test account, 2026-10-19). The response is the native shape.

Request

curl https://api.modelsite.ai/v1/responses \
  -H "Authorization: Bearer $MODELSITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-5.3-flash",
    "input": "Explain quantum entanglement in one sentence",
    "instructions": "Answer briefly",
    "max_output_tokens": 1500
  }'

Response

The reply text is content[].text of the output[] item whose type is message (the SDK's output_text already joins it); status is status (completed / incomplete; when truncated incomplete_details.reason is max_output_tokens, when blocked by content safety it is content_filter); usage is usage. The reply text below is real output for a Chinese prompt (the real request was written in Chinese).

{
  "background": false,
  "created_at": 1760000000,
  "ec_transfer_params": null,
  "error": null,
  "frequency_penalty": 0.0,
  "id": "resp_xxxx",
  "incomplete_details": null,
  "input_messages": null,
  "instructions": "Answer briefly",
  "max_output_tokens": 1500,
  "max_tool_calls": null,
  "metadata": null,
  "model": "glm-5.3-flash",
  "object": "response",
  "output": [
    {
      "id": "msg_xxxx",
      "content": [
        {
          "annotations": [],
          "text": "# 量子纠缠\n\n量子纠缠是指两个或多个粒子形成一种特殊的量子关联状态,无论相距多远,测量其中一个粒子的状态会瞬间确定另一个粒子的状态。……",
          "type": "output_text",
          "logprobs": null
        }
      ],
      "role": "assistant",
      "status": "completed",
      "type": "message",
      "phase": null
    }
  ],
  "output_messages": null,
  "parallel_tool_calls": true,
  "presence_penalty": 0.0,
  "previous_response_id": null,
  "prompt": null,
  "reasoning": null,
  "service_tier": "auto",
  "status": "completed",
  "temperature": 1,
  "text": null,
  "tool_choice": "none",
  "tools": [],
  "top_logprobs": null,
  "top_p": 0.95,
  "truncation": "disabled",
  "usage": {
    "input_tokens": 23,
    "input_tokens_details": { "cached_tokens": 0 },
    "output_tokens": 91,
    "output_tokens_details": { "reasoning_tokens": 0 },
    "total_tokens": 114
  },
  "user": null
}

Notes

  • temperature, top_p, tool_choice and so on are the upstream's echo of your request or its defaults (for example tool_choice shows none when no tools were sent); they do not mean the platform rewrote your request.
  • The model in the response is the model name you requested, and id is a platform-encoded resp_ ID.
  • The API card below is rendered from the OpenAPI spec (request-body parameter table, response schema).
POST
/responses

Authorization

BearerAuth
AuthorizationBearer <token>

Authorization: Bearer $MODELSITE_API_KEY

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/responses" \  -H "Content-Type: application/json" \  -d '{    "model": "string",    "input": "string"  }'

取回复:output[] 里 type 为 message 的项。上游原生支持 Responses 时是这种带回显字段的形态;取自线上真实响应(glm-5.3-flash,2026-10-19),取值为占位。

{  "background": false,  "created_at": 1760000000,  "ec_transfer_params": null,  "error": null,  "frequency_penalty": 0,  "id": "resp_xxxx",  "incomplete_details": null,  "input_messages": null,  "instructions": "用中文回答,简洁",  "max_output_tokens": 1500,  "max_tool_calls": null,  "metadata": null,  "model": "glm-5.3-flash",  "object": "response",  "output": [    {      "id": "msg_xxxx",      "content": [        {          "annotations": [],          "text": "# 量子纠缠\n\n量子纠缠是指两个或多个粒子形成一种特殊的量子关联状态,无论相距多远,测量其中一个粒子的状态会瞬间确定另一个粒子的状态。\n\n**通俗类比**:就像一双“魔法手套”分别寄到地球两端,你打开盒子看到左手套的瞬间,就知道另一端是右手套——但量子纠缠更神奇,手套在被打开前连“左右”都还没确定。",          "type": "output_text",          "logprobs": null        }      ],      "role": "assistant",      "status": "completed",      "type": "message",      "phase": null    }  ],  "output_messages": null,  "parallel_tool_calls": true,  "presence_penalty": 0,  "previous_response_id": null,  "prompt": null,  "reasoning": null,  "service_tier": "auto",  "status": "completed",  "temperature": 1,  "text": null,  "tool_choice": "none",  "tools": [],  "top_logprobs": null,  "top_p": 0.95,  "truncation": "disabled",  "usage": {    "input_tokens": 23,    "input_tokens_details": {      "cached_tokens": 0    },    "output_tokens": 91,    "output_tokens_details": {      "reasoning_tokens": 0    },    "total_tokens": 114  },  "user": null}

Multi-turn

When to use: conversations that need context. The platform does not store responses; put the full history in the input array on every request. You can also use the developer role for instructions.

Evidence: per official docs (not tested). Multi-turn with tools (function_call returned) was tested, see Function calling.

Request

curl https://api.modelsite.ai/v1/responses \
  -H "Authorization: Bearer $MODELSITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-5.3-flash",
    "input": [
      {"role": "developer", "content": "Answer briefly"},
      {"role": "user", "content": "What is quantum entanglement?"},
      {"role": "assistant", "content": "Two particles share a state regardless of distance."},
      {"role": "user", "content": "Can it be used for faster-than-light communication?"}
    ],
    "max_output_tokens": 1500
  }'

Response: same structure as Basic chat.

Notes

  • On the converted path the input array only converts message (including the short form with just role + content), function_call, function_call_output, custom_tool_call and custom_tool_call_output; reasoning items are skipped, and other types such as item_reference and image_generation_call are dropped.
  • Do not rely on previous_response_id for continuation; see the scenario overview.

Streaming

When to use: show output token by token and lower time to first token.

Evidence: tested (live test account, 2026-10-19). The event sequence is the native shape.

Request

curl -N https://api.modelsite.ai/v1/responses \
  -H "Authorization: Bearer $MODELSITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-5.3-flash",
    "input": "Reply with one character: 好",
    "stream": true,
    "reasoning": {"effort": "low"},
    "max_output_tokens": 600
  }'

Response

Each event is an event: line plus a data: line; concatenate the delta of response.output_text.delta for the text; the stream ends with response.completed, whose response.usage holds usage. There is no [DONE]. Every event carries an increasing sequence_number.

event: response.created
data: {"response":{"id":"resp_xxxx","created_at":1760000000,"model":"glm-5.3-flash","object":"response","output":[],"status":"in_progress","usage":null, ...echo fields as in the basic response...},"sequence_number":0,"type":"response.created"}

event: response.in_progress
data: {"response":{ ...same as above... },"sequence_number":1,"type":"response.in_progress"}

event: response.output_item.added
data: {"item":{"id":"rs_xxxx","summary":[],"type":"reasoning","content":null,"encrypted_content":null,"status":"in_progress"},"output_index":0,"sequence_number":2,"type":"response.output_item.added"}

event: response.reasoning_part.added
data: {"content_index":0,"item_id":"rs_xxxx","output_index":0,"part":{"text":"","type":"reasoning_text"},"sequence_number":3,"type":"response.reasoning_part.added"}

event: response.reasoning_text.delta
data: {"content_index":0,"delta":"User wants exactly one character: \"好\".","item_id":"rs_xxxx","output_index":0,"sequence_number":4,"type":"response.reasoning_text.delta"}

event: response.reasoning_text.done
data: {"content_index":0,"item_id":"rs_xxxx","output_index":0,"sequence_number":8,"text":"User wants exactly one character: \"好\".","type":"response.reasoning_text.done"}

event: response.reasoning_part.done
data: {"content_index":0,"item_id":"rs_xxxx","output_index":0,"part":{"text":"User wants exactly one character: \"好\".","type":"reasoning_text"},"sequence_number":9,"type":"response.reasoning_part.done"}

event: response.output_item.done
data: {"item":{"id":"rs_xxxx","summary":[],"type":"reasoning","content":[{"text":"User wants exactly one character: \"好\".","type":"reasoning_text"}],"encrypted_content":null,"status":"completed"},"output_index":0,"sequence_number":10,"type":"response.output_item.done"}

event: response.output_item.added
data: {"item":{"id":"msg_xxxx","content":[],"role":"assistant","status":"in_progress","type":"message","phase":null},"output_index":1,"sequence_number":11,"type":"response.output_item.added"}

event: response.content_part.added
data: {"content_index":0,"item_id":"msg_xxxx","output_index":1,"part":{"annotations":[],"text":"","type":"output_text","logprobs":[]},"sequence_number":12,"type":"response.content_part.added"}

event: response.output_text.delta
data: {"content_index":0,"delta":"好","item_id":"msg_xxxx","logprobs":[],"output_index":1,"sequence_number":13,"type":"response.output_text.delta"}

event: response.output_text.done
data: {"content_index":0,"item_id":"msg_xxxx","logprobs":[],"output_index":1,"sequence_number":14,"text":"好","type":"response.output_text.done"}

event: response.content_part.done
data: {"content_index":0,"item_id":"msg_xxxx","output_index":1,"part":{"annotations":[],"text":"好","type":"output_text","logprobs":null},"sequence_number":15,"type":"response.content_part.done"}

event: response.output_item.done
data: {"item":{"id":"msg_xxxx","content":[{"annotations":[],"text":"好","type":"output_text","logprobs":null}],"role":"assistant","status":"completed","type":"message","phase":null,"summary":[]},"output_index":1,"sequence_number":16,"type":"response.output_item.done"}

event: response.completed
data: {"response":{"id":"resp_xxxx","status":"completed","model":"glm-5.3-flash","output":[ ...the two items from output_item.done... ],"usage":{"input_tokens":18,"input_tokens_details":{"cached_tokens":0,"input_tokens_per_turn":[],"cached_tokens_per_turn":[]},"output_tokens":12,"output_tokens_details":{"reasoning_tokens":9,"tool_output_tokens":0,"output_tokens_per_turn":[],"tool_output_tokens_per_turn":[]},"total_tokens":30}, ...},"sequence_number":17,"type":"response.completed"}

Notes

  • In the native shape, thinking arrives as response.reasoning_text.* events at output_index: 0 and the answer at output_index: 1. On the converted path thinking arrives as the official response.reasoning_summary_part.added, response.reasoning_summary_text.delta, response.reasoning_summary_text.done and response.reasoning_summary_part.done events (per code and unit tests, not tested online). The two shapes place thinking differently; read by event type and do not hard-code indexes.
  • On the converted path output_index increases in order of appearance starting at 0: with thinking, thinking is 0; a turn that only calls tools has no message item; each item gets output_item.done before the next item starts.
  • On the converted path, streaming requests turn on include_usage automatically, and usage is in response.completed.
  • If a stream fails after output has started, the error is sent as an in-stream event; see "Errors" below.

Function calling

When to use: let the model decide to call functions you define. The flow: declare tools → the model returns a function_call item → you run it → in the next request's input put back that function_call item and a function_call_output item (matched by call_id) → the model gives the final answer.

Evidence: tested (live test account, 2026-10-19): a single call and returning the result (native shape). tool_choice values, parallel calls and the streaming function_call_arguments events are per official docs (not tested).

Request (first turn)

curl https://api.modelsite.ai/v1/responses \
  -H "Authorization: Bearer $MODELSITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-5.3-flash",
    "input": "What is the weather in Hangzhou tomorrow?",
    "tools": [{
      "type": "function",
      "name": "get_weather",
      "description": "Get the current weather for a city",
      "parameters": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"]
      }
    }],
    "max_output_tokens": 1500
  }'

Response (first turn)

A tool call is an output[] item with type function_call; arguments is a JSON string. Only output and usage are shown; the other fields are as in Basic chat (tools echoes the tools you declared and tool_choice is auto).

{
  "id": "resp_xxxx",
  "object": "response",
  "status": "completed",
  "model": "glm-5.3-flash",
  "output": [
    {
      "id": "rs_xxxx",
      "summary": [],
      "type": "reasoning",
      "content": [
        { "text": "The user is asking about the weather in Hangzhou… (omitted)", "type": "reasoning_text" }
      ],
      "encrypted_content": null,
      "status": null
    },
    {
      "arguments": "{\"city\": \"杭州\"}",
      "call_id": "chatcmpl-tool-xxxxxxxx",
      "name": "get_weather",
      "type": "function_call",
      "id": "fc_xxxx",
      "caller": null,
      "namespace": null,
      "status": "completed"
    }
  ],
  "usage": {
    "input_tokens": 160,
    "output_tokens": 95,
    "total_tokens": 255,
    "input_tokens_details": { "cached_tokens": 0 },
    "output_tokens_details": { "reasoning_tokens": 83 }
  }
}

Returning the tool result (second turn)

curl https://api.modelsite.ai/v1/responses \
  -H "Authorization: Bearer $MODELSITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-5.3-flash",
    "input": [
      {"role": "user", "content": "What is the weather in Hangzhou tomorrow?"},
      {"type": "function_call", "call_id": "chatcmpl-tool-xxxxxxxx", "name": "get_weather", "arguments": "{\"city\": \"杭州\"}"},
      {"type": "function_call_output", "call_id": "chatcmpl-tool-xxxxxxxx", "output": "Cloudy, 7-13°C"}
    ],
    "tools": [ ... same as the first turn ... ],
    "reasoning": {"effort": "low"},
    "max_output_tokens": 1500
  }'

Second-turn response (tested; output has a single message):

{
  "id": "resp_xxxx",
  "object": "response",
  "status": "completed",
  "model": "glm-5.3-flash",
  "output": [
    {
      "id": "msg_xxxx",
      "content": [
        { "annotations": [], "text": "杭州明天天气:多云,气温 7~13°C。早晚偏凉,建议适当添衣保暖。", "type": "output_text", "logprobs": null }
      ],
      "role": "assistant",
      "status": "completed",
      "type": "message",
      "phase": null
    }
  ],
  "usage": {
    "input_tokens": 182,
    "input_tokens_details": { "cached_tokens": 0 },
    "output_tokens": 25,
    "output_tokens_details": { "reasoning_tokens": 0 },
    "total_tokens": 207
  }
}

Notes

  • On the converted path a custom tool is converted to a function with a single string parameter and restored in the response; allowed_tools in tool_choice is approximated as required (when mode is required) or auto, and hosted-tool forms degrade to auto.
  • The format of call_id depends on the upstream; send it back unchanged.
  • When streaming, the event sequence for tool calls follows the official docs: response.output_item.added (function_call) → several response.function_call_arguments.delta → response.function_call_arguments.done → response.output_item.done.

Structured output (text.format)

When to use: the reply must strictly match a JSON Schema you provide (in Responses this is text.format, not response_format).

Evidence: tested (live test account, 2026-10-19, native shape).

Request

curl https://api.modelsite.ai/v1/responses \
  -H "Authorization: Bearer $MODELSITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-5.3-flash",
    "input": "Extract: Zhang San, 28 years old, lives in Shanghai",
    "reasoning": {"effort": "low"},
    "max_output_tokens": 1500,
    "text": {
      "format": {
        "type": "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
        }
      }
    }
  }'

Response (output only; text.format is echoed in the response)

"output": [
  {
    "id": "rs_xxxx",
    "summary": [],
    "type": "reasoning",
    "content": [ { "text": "Simple extraction task.", "type": "reasoning_text" } ]
  },
  {
    "id": "msg_xxxx",
    "content": [
      { "annotations": [], "text": "{\n  \"age\": 28,\n  \"city\": \"上海\",\n  \"name\": \"张三\"\n}", "type": "output_text", "logprobs": null }
    ],
    "role": "assistant",
    "status": "completed",
    "type": "message"
  }
]

Notes

  • In this run the output matched the schema; key order is not guaranteed. The platform does not validate output server-side, so still validate the result yourself; when status is incomplete the output may be truncated.
  • On the converted path, text.format of json_schema / json_object is converted to response_format, verbosity is converted to verbosity, and other sub-fields are dropped.

Reasoning

When to use: you want the model to reason before answering, or you want to control reasoning effort.

Evidence: tested (live test account, 2026-10-19): reasoning.effort: "low", streaming and non-streaming (native shape).

Request

curl https://api.modelsite.ai/v1/responses \
  -H "Authorization: Bearer $MODELSITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-5.3-flash",
    "input": "What is the weather in Hangzhou tomorrow?",
    "reasoning": {"effort": "low"},
    "max_output_tokens": 1500
  }'

Response: thinking is the output[] item with type reasoning (before the message); non-streaming it is in content[].text (type reasoning_text); the thinking token count is usage.output_tokens_details.reasoning_tokens; cache hits are usage.input_tokens_details.cached_tokens. Real reasoning items are in the responses under Function calling and Structured output; streaming events are under Streaming.

Notes

  • Without reasoning, glm-5.3-flash in the native shape returned no reasoning item in testing (reasoning_tokens was 0); whether it thinks and the strength values are decided by the model and upstream; see the vendor pages for per-model values.
  • On the converted path reasoning.effort is converted to reasoning_effort, and max_tokens, enabled, exclude are normalized by the thinking rules of Chat Completions; summary and generate_summary have no counterpart and do nothing (the reasoning in the response only echoes what you sent). On the converted path thinking is always returned as summary (summary_text), identically for streaming and non-streaming.

Image input

When to use: have a vision model answer questions about an image. Choose a model that accepts image input (such as qwen3-vl-plus).

Evidence: base64 images tested (live test account, 2026-10-19, qwen3-vl-plus, converted shape); public URL per official docs (not tested).

Request

curl https://api.modelsite.ai/v1/responses \
  -H "Authorization: Bearer $MODELSITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3-vl-plus",
    "max_output_tokens": 300,
    "input": [{
      "role": "user",
      "content": [
        {"type": "input_text", "text": "What is in this image? One sentence."},
        {"type": "input_image", "image_url": "data:image/png;base64,iVBORw0KGgo..."}
      ]
    }]
  }'

Response (converted shape; only the main fields are listed, the other echo fields are described under "Unsupported or different parameters" above)

{
  "id": "resp_xxxx",
  "object": "response",
  "created_at": 1760000000,
  "status": "completed",
  "max_output_tokens": 300,
  "model": "qwen3-vl-plus",
  "output": [
    {
      "type": "message",
      "id": "msg_xxxx",
      "status": "completed",
      "role": "assistant",
      "content": [
        { "type": "output_text", "text": "图中是一个红色的实心圆,背景为白色。" }
      ]
    }
  ],
  "usage": {
    "input_tokens": 82,
    "input_tokens_details": { "cached_tokens": 0 },
    "output_tokens": 14,
    "output_tokens_details": { "reasoning_tokens": 0 },
    "total_tokens": 96
  }
}

Notes

  • Images are billed as input tokens. Per-model limits on image size and count are on the vendor pages.
  • OpenAI's file_id (Files API) is not supported.

Errors

401 invalid or missing key

{"error":{"type":"authentication_error","message":"invalid API key"}}

When the Authorization header is missing, message is missing or invalid authorization header.

402 insufficient balance

{"error":{"type":"insufficient_quota","message":"insufficient balance"}}

429 rate limited

{"error":{"type":"rate_limit_error","message":"too many requests"}}

The response carries Retry-After (seconds); back off accordingly.

403 no access to this model

{"error":{"type":"model_access_error","message":"model 'glm-5.3-flash' is not allowed for this API key"}}

503 gateway at capacity

{"error":{"type":"overloaded_error","message":"gateway at capacity, retry later"}}

Also carries Retry-After: 5.

400 unknown model

{"error":{"type":"invalid_request_error","message":"unknown model: not-a-model"}}

A wrong or not-yet-live model is a 400 (not 404).

400 invalid parameters

{"error":{"message":"<validation message>","type":"invalid_request_error","code":"invalid_request_error"}}

Errors from the routing layer have an extra code field (same value as type).

When an upstream is temporarily unavailable the response may be 502 (server_error) or 503 (error.code is no_upstream_available); retry shortly. If a streaming request fails after output has started, the HTTP status is already 200 and the error is sent as an in-stream event. Full error codes and handling advice: Errors.

Other methods

MethodPathNotes
GET/v1/responsesList endpoint; the platform does not store responses and always returns an empty list
GET/v1/responses/:idGet response details (only valid for responses created through upstreams that natively support Responses)
DELETE/v1/responses/:idDelete a response (same as above)
POST/v1/responses/:id/cancelCancel an in-progress response (same as above)
POST/v1/responses/compactCompact response context

None of these methods was tested.

For most cases Chat Completions is enough; use this endpoint only when existing code depends heavily on the Responses API request/response format. Note: requests converted by the platform do not support continuation with previous_response_id or built-in tools (file_search, code_interpreter, mcp and so on); for multi-turn conversations put the full history in input yourself.

Unsupported or different parameters

This endpoint has two paths, and parameter behavior differs between them. The platform does not drop parameters against a parameter allowlist and does not clamp values: apart from the hard-coded behavior listed below, parameters go to the upstream as-is, and whether they take effect, are ignored or are rejected (4xx) is up to the upstream.

  • Requests to upstreams that natively support Responses: the request body is forwarded as-is and all official fields are kept, including fields the platform has not modeled. When the upstream returns 4xx pointing at a top-level parameter it does not support, the platform removes that parameter and retries, up to 2 rounds (input, model, instructions, stream, tools, tool_choice, previous_response_id are never removed); if it still fails it may fall back to the converted path below.
  • Requests converted by the platform: the request is converted to Chat Completions and the response is converted back to Responses format. The table below is this path's behavior. Which path a model uses is decided by the upstream, and one model can have both.
ParameterBehavior on the converted pathNotes
instructionsRewrittenConverted to a leading system message
inputPartialA string, or an array of message (including the short form with only role + content), function_call, function_call_output, custom_tool_call, custom_tool_call_output. reasoning items are skipped; other types such as item_reference and image_generation_call are dropped
max_output_tokensRewrittenConverted to max_tokens
toolsPartialfunction as usual; custom is converted to a function with a single string parameter and restored in the response; web_search / web_search_preview is converted to web_search_options (no search effect on live models in testing); other built-in tools such as file_search, computer_use, mcp, code_interpreter, image_generation are dropped
tool_choiceRewrittenauto / none / required as-is; a specific function / custom becomes a specific function; allowed_tools is approximated as required (when mode is required) or auto; other built-in tool forms degrade to auto
reasoningPartialeffort is converted to reasoning_effort; max_tokens, enabled, exclude are normalized by the thinking rules of Chat Completions; summary and generate_summary have no counterpart and do nothing (echoed only)
textPartialWhen format.type is json_schema / json_object it is converted to response_format and text itself is no longer forwarded; verbosity is converted to verbosity; other sub-fields are dropped
previous_response_idDroppedThe platform does not store responses, so it cannot continue; send the full input for multi-turn; the response object only echoes the value you sent
truncation include max_tool_callsDroppedNo Chat Completions counterpart
store service_tier user metadata parallel_tool_callsMappedMapped to the same-named Chat fields and forwarded; metadata keeps only string values
streamUsage added automaticallyWith stream: true, include_usage is turned on automatically and usage is in response.completed
background conversation prompt top_logprobs stream_options context_management safety_identifier prompt_cache_key prompt_cache_retention moderationNo Responses semanticsForwarded to the upstream as unknown top-level fields and do not produce Responses behavior (for example background does not make the request run in the background)

Common to both paths: the model in the response is the model name you requested, and id is a platform-encoded resp_ ID (identical for streaming and non-streaming on the converted path).

On the converted path the response object echoes the request parameters in the official shape: instructions, tools, tool_choice, temperature, top_p, max_output_tokens, parallel_tool_calls, metadata, reasoning, store, text, truncation, user, previous_response_id, max_tool_calls. Parameters you did not send are echoed with the official defaults (tool_choice auto, tools [], parallel_tool_calls true, store true, truncation disabled, metadata {}); temperature and top_p are null when not sent. These are request echoes and do not mean the upstream used those values (for example store, truncation and previous_response_id are dropped on the converted path, see the table above). Converted responses carry no upstream-specific fields (ec_transfer_params, input_messages, output_messages and so on).

Platform extensions

What follows is defined by the platform and does not exist in the official OpenAI API.

Request headers: the gateway only lets Authorization, Content-Type, Accept, Accept-Encoding, Origin, User-Agent, Anthropic-Beta, OpenAI-Beta through and drops all others. A value you send in X-Request-ID is kept and echoed; if absent, the platform generates one.

Response headers

HeaderNotes
X-Request-IDRequest ID; give it to us when troubleshooting
Retry-AfterSuggested back-off seconds on 429; at gateway capacity it returns 503 with Retry-After: 5
Content-Type: text/event-stream, Cache-Control: no-cacheStreaming responses; when a stream is idle the gateway sends a : heartbeat comment frame every 15 seconds, which SSE clients ignore automatically

The platform does not return X-RateLimit-* quota headers.

Response fields

FieldNotes
usage.cost, usage.cost_detailsCost fields on non-streaming responses. Not returned by default; they appear only when your organization is set to total or detailed, and callers cannot turn them on with a request parameter. Amounts are exact decimal strings; requests that cannot be priced omit them. The component names differ from Chat Completions: input_cost, output_cost, reasoning_cost, prompt_cache_read_cost and so on, only components greater than 0
output[].content[].reasoning_text (non-streaming), response.reasoning_text.* / reasoning_summary_* events (streaming)Thinking; the location depends on path and mode, see each scenario

Automatic behavior

  • When the balance runs out during streaming, the stream is cut and you then receive a data: {"error":{"type":"insufficient_quota","message":"balance exhausted"}} frame and data: [DONE].
  • Automatic retry and upstream switching on upstream failure follow the same rules as Chat Completions.
  • GET /v1/responses/:id, DELETE and cancel are only valid for responses created on the native path; see "Other methods" above.

On this page