Responses

POST /v1/responses creates a model response in the OpenAI Responses format. It is stateless: nothing is stored between requests, and a request that points at stored state is refused with stateless_only.

Request#

FieldTypeNotes
modelstringRequired. A model id from GET /v1/models
inputstring or arrayA string is one user message; an array is input items
instructionsstringSystem-level instructions, sent as the first system message
streambooleanDefault false. With true, Responses events
max_output_tokensintegerOutput cap. When omitted the model's maximum applies. The cap is lowered to what the balance covers when needed, and x-token-notice says so
toolsarrayFunction and custom tools. Hosted tools (web_search, file_search, code_interpreter, computer_use, mcp, local_shell) are left out and named in x-token-notice. image_generation is refused with 400 image_generation_unsupported
tool_choicestring or objectauto, none, required or a named tool
reasoningobjecteffort sets the reasoning effort; summary is ignored
text.formatobjectjson_object or a json_schema, on models that support it
prompt_cache_keystringA stable key for the prompt cache
userstringEnd-user id for attribution. safety_identifier is an alias
metadataobjectFlat tags kept with the request
conversationstring or objectNames the session for caching. Nothing is stored for it
temperature, top_pnumberSampling controls
storeanyAccepted and ignored
includearrayreasoning.encrypted_content is honoured on models that return it; other values are accepted and ignored

Two tools that resolve to one name are refused with a 400, as are input items of a type the format does not define.

Stateless#

RequestAnswer
previous_response_id400 stateless_only: send the whole conversation in input
background: true400 stateless_only: stream the response or wait for it
a stored prompt400 stateless_only: send instructions and input
an item_reference input item400 stateless_only
store: trueAccepted, nothing is stored

Input items#

A message item has a role of user, assistant, system or developer with content parts. input_image takes a URL or a data URI; a file id or an input_file part is refused. Assistant-side items in a row, an assistant message, a reasoning item and function_call items, form one assistant turn: reasoning becomes reasoning_content and calls become tool_calls. A function_call_output item becomes a tool message.

To keep reasoning across turns without stored state, ask for include: ["reasoning.encrypted_content"] and replay the reasoning item as it came. A model that cannot return the ciphertext replays the reasoning text as reasoning_content instead.

Items of hosted tools, a web_search_call for instance, degrade to an assistant note rather than failing the request:

text
[web_search_call replayed from a previous conversation: hosted tool results are not replayed]

A configuration_update item may carry reasoning.effort, which becomes the request's effort when the request sends no reasoning parameter.

cURLbash
curl -sSf https://api.zdr.sh/v1/responses \  -H "Authorization: Bearer $ZDR_API_KEY" \  -H "Content-Type: application/json" \  -d '{"model": "glm-5.3", "input": "Reply with the single word: ready."}'

Streaming#

With stream: true the answer arrives as Responses events: response.created, response.output_item.added, response.output_text.delta, response.reasoning_summary_text.delta where the model reports reasoning, then response.completed or response.incomplete, carrying the final response object with usage.

The terminal event is response.incomplete, not a completed with a status, when the model hit its token ceiling (incomplete_details.reason: max_output_tokens) or a content filter (content_filter). An error after the headers are out is a response.failed event whose response object carries the same id, the model and the failure, with status, retry_after_ms and x_should_retry.

cURLbash
curl -sSfN https://api.zdr.sh/v1/responses \  -H "Authorization: Bearer $ZDR_API_KEY" \  -H "Content-Type: application/json" \  -d '{"model": "glm-5.3", "stream": true, "input": "Count to three."}'

Response#

json
{"id":"resp_9f2f0a...","object":"response","model":"glm-5.3","status":"completed","output":[{"type":"message","role":"assistant","content":[{"type":"output_text","text":"Hello."}]}],"usage":{"input_tokens":24,"input_tokens_details":{"cached_tokens":0},"output_tokens":8,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":32},"ai_generated":true,"ai_notice":"[AI-generated content]"}

The structure follows the Responses format, with ai_generated and ai_notice added. On a stream the marker sits on the response of response.created. usage.input_tokens includes cached and written tokens, itemised in input_tokens_details; reasoning_tokens sits inside output_tokens.

Count input tokens#

POST /v1/responses/input_tokens returns {"object": "response.input_tokens", "input_tokens": N} for an input without running it. Nothing is billed.