Responses API
POST /v1/responses: the OpenAI Responses format with stored state, background runs and enforced tool rules.
Responses API compatibility
POST /v1/responses follows the OpenAI Responses API: the same request fields, output items, streaming events, error shapes and stored state, so OpenAI SDKs (responses.create, responses.stream, responses.parse, responses.retrieve, conversations) and the Agents SDKs work by changing the base URL. As on OpenAI, responses are stored by default, so you can continue a conversation with previous_response_id or a conversation, run a response in the background and retrieve it later. Send store: false to store nothing and send the whole conversation as input each turn instead. What is stored, for how long, and how to turn storage off for your account: see Data retention below.
Tool rules are guaranteed. When a request sets strict: true on a function tool, uses tool_choice (required, a named tool or allowed_tools) or sets parallel_tool_calls: false, OpenScale checks every tool call before you see it: arguments match the JSON schema (types, required, additionalProperties: false, enum, format, pattern), only allowed tools are called, and at most one call comes back when parallel calls are off. A reply that breaks a rule is stopped and retried, and never returned; if no valid reply arrives within three attempts the request fails with 500 and code: tool_call_validation_failed (in a stream: an error event, then response.failed). Failed attempts are not billed. Streams with tool rules send reasoning as it is generated, and text and tool calls once they have been checked. A strict: true schema must follow the Structured Outputs rules (every object sets additionalProperties: false and lists all properties in required; no allOf, not or if), or the request is refused with 400 naming the parameter. Function tools without strict are not checked and read back as strict: false.
| Field or tool | Status |
|---|---|
input (messages, function, custom, shell, local shell, apply patch and tool search items, reasoning items), instructions, stream, temperature, top_p, max_output_tokens (16 to the model limit), text.format, reasoning | Supported |
tools: function (with strict), custom, namespace, shell, local_shell, apply_patch, tool_search with execution: "client", defer_loading | Supported (all run by your client) |
tool_choice: auto, none, required, a named tool, allowed_tools; parallel_tool_calls | Supported and enforced |
top_logprobs, include: ["message.output_text.logprobs"] | Supported |
phase on assistant messages | Supported: every assistant message in the output has phase: commentary for text the model wrote before a tool call in the same response (always, when tool_choice forces a call), final_answer otherwise. In a stream it is on response.output_item.done (and already on response.output_item.added when tool_choice forces a call). Assistant messages you send back in input may keep it |
include: ["reasoning.encrypted_content"] | Supported (reasoning always comes back with encrypted_content, readable reasoning_text content, and a summary when reasoning.summary is set) |
Images (input_image with a URL or data URL, detail), including images returned in function_call_output | Supported |
POST /v1/responses/input_tokens | Supported (exact counts for text and tools; images and models whose tokenizer we do not carry are estimated) |
prompt_cache_options.prewarm | Supported (fills the prompt cache and returns a completed response with no output) |
metadata, user, safety_identifier, prompt_cache_key, max_tool_calls | Accepted and echoed in the response |
service_tier | priority runs the request in fast mode when it is available (see Fast mode); any other value runs at the standard tier. The response reports the tier that served it |
store | Supported. Defaults to true: the response is stored for 30 days. false stores nothing |
previous_response_id | Supported: the earlier responses' input and output items come before your input (their instructions do not carry over). An id that is unknown, deleted, past its 30 days or another account's is a 400 with code: previous_response_not_found |
conversation and the Conversations API (/v1/conversations and its items) | Supported: the conversation's items come before your input, and the input and output are added to it when the response finishes. Cannot be combined with previous_response_id |
background: true | Supported: answered at once with a queued response that runs to the end whether or not you stay connected (up to 29 minutes). Poll GET /v1/responses/{id}, resume its stream with ?stream=true&starting_after=, or cancel it with POST /v1/responses/{id}/cancel |
item_reference items | Supported for items of your stored responses and conversations |
GET and DELETE /v1/responses/{id}, GET /v1/responses/{id}/input_items | Supported |
web_search, web_search_preview, a hosted tool_search | Left out of the request and named in the x-openscale-ignored-tools response header (deferred tools are then loaded directly) |
file_search, code_interpreter, image_generation, computer, computer_use_preview, mcp, programmatic_tool_calling | Refused with 400 (param: tools[i].type); define the capability as a function tool instead |
input_file with file_data (a base64 data URL) or file_url (public https URLs) | Supported for PDFs (their text, page by page), images (read as input_image) and text files (txt, md, csv, json, html, xml, yaml, code). Up to 20 MB and 500 pages a file, 20 files and 50 MB a request. Other types (Word, Excel, audio) are a 400 naming the parameter. Stored responses keep the text read from a file, not the file |
prompt (id, version, variables) | Supported with prompts you save through /v1/prompts (see Prompts below). Variables fill {{name}} placeholders with text, or with an input_image or input_file in user messages. An unknown prompt or version, a missing variable or one the prompt does not use is a 400 |
POST /v1/responses/compact, compaction items | Supported: returns response.compaction with your user messages and a compaction item that stands for the rest; send that output as the next input. A compaction item that OpenScale did not create, or that was changed, is a 400 |
context_management: [{"type": "compaction", "compact_threshold": n}], compaction_trigger items | Supported: past n input tokens the conversation is summarized first; the response starts with a compaction item (streamed with response.compaction.compacting) that replaces everything before it in later turns, and its usage includes the summary. A final compaction_trigger item returns just the compaction |
truncation: "auto" | Supported: when the input does not fit the context window, the oldest items are dropped (a tool call is always dropped with its output, reasoning with its turn); your instructions and newest item are kept. disabled (the default) answers 400 with code: context_length_exceeded |
WebSocket mode (response.create over wss://) | Not available yet; use HTTP streaming (stream: true) |
Images and files by file_id | Refused with 400 naming the parameter; send them by URL or as data |
Every refusal uses the OpenAI error shape {"error": {"message", "type", "param", "code"}} with param set to the field at fault.
Endpoints
- Count input tokens:
POST https://api.openscale.so/v1/responses/input_tokens - Create a response:
POST https://api.openscale.so/v1/responses - Retrieve a response:
GET https://api.openscale.so/v1/responses/{response_id} - Delete a response:
DELETE https://api.openscale.so/v1/responses/{response_id} - Cancel a background response:
POST https://api.openscale.so/v1/responses/{response_id}/cancel - List input items:
GET https://api.openscale.so/v1/responses/{response_id}/input_items - Compact a conversation:
POST https://api.openscale.so/v1/responses/compact
Count input tokens
POST https://api.openscale.so/v1/responses/input_tokens
Count the input tokens a Responses request would use, without running the model. Takes the same body as Create a response and counts it with the model tokenizer: exact for text and tools, estimated for images and for models whose tokenizer we do not carry. Free.
Example request
curl https://api.openscale.so/v1/responses/input_tokens \
-H "Authorization: Bearer $OPENSCALE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek/deepseek-v4.1-flash",
"input": "Hello from OpenScale"
}'Response
200: The input token count.
| Field | Type | Description |
|---|---|---|
object | string | Always response.input_tokens. |
input_tokens | integer |
Errors
| Status | Meaning |
|---|---|
| 400 | The request cannot be served; param names the field. |
| 401 | Missing or invalid API key. |
Create a response
POST https://api.openscale.so/v1/responses
Create a response from a string or an array of input items (messages, tool call and tool output items, and reasoning items from an earlier turn). Function, custom, namespace, shell, local shell, apply patch and client tool search tools are supported, and strict, tool_choice (including allowed_tools) and parallel_tool_calls: false are enforced. Reasoning comes back as a reasoning item with encrypted_content you can send back unchanged, readable reasoning_text content, and a summary when reasoning.summary is set. Responses are stored for 30 days by default (store), so a later request can continue from one with previous_response_id, or keep its turns in a conversation; with background: true the response runs on its own and is retrieved later. See the Responses API compatibility table and Data retention in the introduction.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
model | string | Yes | One of deepseek/deepseek-v4.1-flash, z-ai/glm-5.3-flash, deepseek/deepseek-v4.1-flash-1017, deepseek/deepseek-v4.1-flash-0910, z-ai/glm-5.3-flash-0828, deepseek/deepseek-v4.1-flash:fast, deepseek/deepseek-v4.1-flash-1017:fast, deepseek/deepseek-v4.1-flash-0910:fast. |
input | string or array of object | Yes | |
instructions | string | No | |
tools | array of object | No | function (with strict), custom, namespace, shell, local_shell, apply_patch and client tool_search tools. Web search is left out (see x-openscale-ignored-tools); other hosted tools are refused. |
tool_choice | any | No | auto, none, required, a named tool, or allowed_tools. Enforced: a reply that breaks it is retried and never returned. |
parallel_tool_calls | boolean | No | |
text | object | No | Structured outputs: { "format": { "type": "json_schema", ... } } or json_object. json_object works whether or not your prompt mentions JSON. |
max_output_tokens | integer | No | |
temperature | number | No | From 0 to 2. |
top_p | number | No | From 0 to 1. |
stream | boolean | No | Default false. |
metadata | object | No | |
store | boolean | No | Store the response for 30 days, for previous_response_id, retrieval and input_items. false stores nothing. Always false when the account has zero data retention on. Default true. |
previous_response_id | string | No | Continue from a stored response: its input and output (and those of the responses before it) come before input. Its instructions do not carry over. |
conversation | string or object | No | A conversation id (or { "id": ... }): its items come before input, and the input and output are added to it when the response finishes. |
background | boolean | No | Run the response on its own: answered at once with a queued response; retrieve it, stream it, or cancel it by id. Default false. |
user | string | No | |
reasoning | object | No | Reasoning control: effort (none to xhigh) and summary (auto, concise or detailed returns a readable summary). |
Example request
curl https://api.openscale.so/v1/responses \
-H "Authorization: Bearer $OPENSCALE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek/deepseek-v4.1-flash",
"input": "Hello from OpenScale",
"store": false
}'Response
200: The response, or a typed SSE stream when stream is true.
| Field | Type | Description |
|---|---|---|
id | string | Example: resp_example. |
object | string | Always response. |
created_at | integer | |
status | string | One of completed, incomplete, failed, in_progress, queued, cancelled. |
model | string | One of deepseek/deepseek-v4.1-flash, z-ai/glm-5.3-flash, deepseek/deepseek-v4.1-flash-1017, deepseek/deepseek-v4.1-flash-0910, z-ai/glm-5.3-flash-0828, deepseek/deepseek-v4.1-flash:fast, deepseek/deepseek-v4.1-flash-1017:fast, deepseek/deepseek-v4.1-flash-0910:fast. |
output | array of object | |
output[].type | string | Always message. |
output[].id | string | Example: msg_example. |
output[].role | string | Always assistant. |
output[].status | string | Always completed. |
output[].content | array of object | |
output[].phase | string | commentary: text written before a tool call in the same response. final_answer: the reply. Assistant messages sent back in input may keep it. One of commentary, final_answer. |
usage | object | |
usage.input_tokens | integer | |
usage.input_tokens_details | object | |
usage.output_tokens | integer | |
usage.output_tokens_details | object | |
usage.total_tokens | integer | |
service_tier | string | The tier that served the response: priority in fast mode. One of default, priority. |
{
"id": "resp_example",
"object": "response",
"created_at": 1790078324,
"status": "completed",
"model": "deepseek/deepseek-v4.1-flash",
"output": [
{
"type": "message",
"id": "msg_example",
"role": "assistant",
"status": "completed",
"content": [
{
"type": "output_text",
"text": "Hello!",
"annotations": []
}
],
"phase": "final_answer"
}
],
"usage": {
"input_tokens": 5,
"input_tokens_details": {
"cached_tokens": 0
},
"output_tokens": 2,
"output_tokens_details": {
"reasoning_tokens": 0
},
"total_tokens": 7
}
}With stream: true: Typed events: response.created, response.in_progress, response.output_item.added and .done, response.content_part.added and .done, response.output_text.delta and .done, response.reasoning_summary_part and response.reasoning_summary_text events, response.function_call_arguments.delta and .done, response.custom_tool_call_input.done, and response.completed, response.incomplete or response.failed.
Errors
| Status | Meaning |
|---|---|
| 400 | Invalid request; param names the field. previous_response_not_found when the previous response is unknown, deleted or past its 30 days. |
| 401 | Missing or invalid API key. |
| 402 | Empty balance, or the key reached its spend limit. |
| 404 | Unknown model id. |
| 429 | Rate limit crossed or model at capacity. |
| 502 | The model is temporarily unavailable. |
| 504 | The model did not respond in time. |
Retrieve a response
GET https://api.openscale.so/v1/responses/{response_id}
A stored response, as it was returned (status queued or in_progress while a background response runs). With stream=true (background responses only), its stream events from the start, or after starting_after, then each new one as it happens.
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
response_id | string | Yes |
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
stream | boolean | No | Stream a background response as SSE events. |
starting_after | integer | No | With stream: the sequence number to resume after. |
Example request
curl https://api.openscale.so/v1/responses/$RESPONSE_ID \
-H "Authorization: Bearer $OPENSCALE_API_KEY"Response
200: The response, or its events when stream is true.
| Field | Type | Description |
|---|---|---|
id | string | Example: resp_example. |
object | string | Always response. |
created_at | integer | |
status | string | One of completed, incomplete, failed, in_progress, queued, cancelled. |
model | string | One of deepseek/deepseek-v4.1-flash, z-ai/glm-5.3-flash, deepseek/deepseek-v4.1-flash-1017, deepseek/deepseek-v4.1-flash-0910, z-ai/glm-5.3-flash-0828, deepseek/deepseek-v4.1-flash:fast, deepseek/deepseek-v4.1-flash-1017:fast, deepseek/deepseek-v4.1-flash-0910:fast. |
output | array of object | |
output[].type | string | Always message. |
output[].id | string | Example: msg_example. |
output[].role | string | Always assistant. |
output[].status | string | Always completed. |
output[].content | array of object | |
output[].phase | string | commentary: text written before a tool call in the same response. final_answer: the reply. Assistant messages sent back in input may keep it. One of commentary, final_answer. |
usage | object | |
usage.input_tokens | integer | |
usage.input_tokens_details | object | |
usage.output_tokens | integer | |
usage.output_tokens_details | object | |
usage.total_tokens | integer | |
service_tier | string | The tier that served the response: priority in fast mode. One of default, priority. |
Errors
| Status | Meaning |
|---|---|
| 404 | No stored response with this id in your account (never stored, deleted or past its 30 days). |
Delete a response
DELETE https://api.openscale.so/v1/responses/{response_id}
Delete a stored response, its input and its output at once. A running background response is cancelled.
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
response_id | string | Yes |
Example request
curl -X DELETE https://api.openscale.so/v1/responses/$RESPONSE_ID \
-H "Authorization: Bearer $OPENSCALE_API_KEY"Response
200: Deleted.
{
"id": "resp_example",
"object": "response.deleted",
"deleted": true
}Errors
| Status | Meaning |
|---|---|
| 404 | No stored response with this id. |
Cancel a background response
POST https://api.openscale.so/v1/responses/{response_id}/cancel
Stop a queued or running background response; it ends with status cancelled and is not billed for unfinished work. Cancelling again, or cancelling a finished response, returns it unchanged.
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
response_id | string | Yes |
Example request
curl -X POST https://api.openscale.so/v1/responses/$RESPONSE_ID/cancel \
-H "Authorization: Bearer $OPENSCALE_API_KEY"Response
200: The response.
| Field | Type | Description |
|---|---|---|
id | string | Example: resp_example. |
object | string | Always response. |
created_at | integer | |
status | string | One of completed, incomplete, failed, in_progress, queued, cancelled. |
model | string | One of deepseek/deepseek-v4.1-flash, z-ai/glm-5.3-flash, deepseek/deepseek-v4.1-flash-1017, deepseek/deepseek-v4.1-flash-0910, z-ai/glm-5.3-flash-0828, deepseek/deepseek-v4.1-flash:fast, deepseek/deepseek-v4.1-flash-1017:fast, deepseek/deepseek-v4.1-flash-0910:fast. |
output | array of object | |
output[].type | string | Always message. |
output[].id | string | Example: msg_example. |
output[].role | string | Always assistant. |
output[].status | string | Always completed. |
output[].content | array of object | |
output[].phase | string | commentary: text written before a tool call in the same response. final_answer: the reply. Assistant messages sent back in input may keep it. One of commentary, final_answer. |
usage | object | |
usage.input_tokens | integer | |
usage.input_tokens_details | object | |
usage.output_tokens | integer | |
usage.output_tokens_details | object | |
usage.total_tokens | integer | |
service_tier | string | The tier that served the response: priority in fast mode. One of default, priority. |
Errors
| Status | Meaning |
|---|---|
| 400 | The response was not created in the background. |
| 404 | No stored response with this id. |
List input items
GET https://api.openscale.so/v1/responses/{response_id}/input_items
The input items of a stored response, each with its id. Paged with limit (1 to 100, default 20), order (desc by default) and after (an item id).
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
response_id | string | Yes |
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
limit | integer | No | From 1 to 100. Default 20. |
order | string | No | One of asc, desc. Default "desc". |
after | string | No |
Example request
curl https://api.openscale.so/v1/responses/$RESPONSE_ID/input_items \
-H "Authorization: Bearer $OPENSCALE_API_KEY"Response
200: A list of items.
| Field | Type | Description |
|---|---|---|
object | string | Always list. |
data | array of object | |
first_id | string or null | |
last_id | string or null | |
has_more | boolean |
Errors
| Status | Meaning |
|---|---|
| 404 | No stored response (or after item) with this id. |
Compact a conversation
POST https://api.openscale.so/v1/responses/compact
Summarize a conversation so it can continue in fewer tokens. Takes model and the conversation as input (and/or previous_response_id, plus instructions). The output keeps your user messages and ends with a compaction item that stands for everything else; send the output, followed by new items, as the next input. Nothing is stored. Billed like a response.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
model | string | Yes | |
input | any | No | |
previous_response_id | string | No | |
instructions | string | No |
Example request
curl https://api.openscale.so/v1/responses/compact \
-H "Authorization: Bearer $OPENSCALE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek/deepseek-v4.1-flash",
"input": [
{
"role": "user",
"content": "My locker number is 7731."
},
{
"type": "message",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "Noted."
}
]
}
]
}'Response
200: The compacted conversation.
| Field | Type | Description |
|---|---|---|
id | string | |
object | string | Always response.compaction. |
created_at | integer | |
output | array of object | |
usage | object |
Errors
| Status | Meaning |
|---|---|
| 400 | The request cannot be served; param names the field. |
| 401 | Missing or invalid API key. |
More of the API reference
- API reference: base URLs, authentication and a first request.
- Chat Completions: POST /v1/chat/completions: the OpenAI Chat Completions format, streamed or not, with reasoning and tools.
- Conversations: Keep the turns of a Responses conversation on our side and continue it by id.
- Prompts: Save instructions, messages and settings once, then use them by id in the Responses API.
- Anthropic Messages: POST /anthropic/v1/messages: the Anthropic Messages format, for Claude Code and Anthropic SDKs.
- Models and pricing: Model ids, prices per 1M tokens, context windows, output limits, versions and the live catalog endpoint.
- Batch: Upload a JSONL file of chat completions, create a batch and collect the results when it finishes.
- Errors: The error shape, every status code and code, and which ones to retry.
- Rate limits: Requests and tokens per minute, how a 429 tells you when to retry, and how to get more.
- Data retention: What is stored, for how long, how to delete it, and zero data retention.
- Interactive reference: try every endpoint in the browser.
- OpenAPI document: the whole API as OpenAPI 3.1.
This page as Markdown: /docs/responses.md