Responses API
OpenAI Responses requests, for Codex and other Responses clients.
POST https://api.aimodelsrouter.ai/v1/responses takes an OpenAI Responses API request and runs it on the same models, prices, holds, key limits and failover as Chat Completions. Use it for Codex and other clients that only speak Responses. Your API key and the base URL are the same.
input every time, which is what Codex does. With previous_response_id, conversation or an item_reference item you get 400, and GET /responses/{id} is 404. Responses report store: false.Request body
| Field | Type | Description |
|---|---|---|
model | string, required | Model slug, e.g. deepseek/deepseek-v4-flash. |
input | string | item[], required | A user message, or the whole conversation as items (see below). |
instructions | string | System instructions, sent to the model first. |
tools | array | function tools, custom (freeform) tools and namespace groups of them. OpenAI's hosted tools (web_search, file_search, code_interpreter, computer use, image_generation, mcp…) get 400. |
tool_choice | string | object | auto, none, required, a named function or custom tool, or allowed_tools. |
parallel_tool_calls | boolean | Whether the model may call several tools at once. |
max_output_tokens | integer | Upper bound on generated tokens. Also lowers the hold placed on your balance. |
temperature, top_p | number | Sampling parameters, passed through to the model. |
reasoning.effort | string | Sent as reasoning_effort to models with the reasoning capability: low, medium, high (minimal is sent as low, xhigh as high). Ignored for other models. |
reasoning.summary | string | Any value returns the model's reasoning as summary parts (the full reasoning, not a summary). Without it, reasoning comes back as reasoning_text content. |
text.format | object | json_schema or json_object, for models with the structured_outputs capability. |
stream | boolean | Stream the response as server-sent events. Default false. |
store, include, metadata, prompt_cache_key, user | Accepted. Nothing is stored or passed to the model provider; responses report store: false and echo metadata. |
Input items
| Item | What it carries |
|---|---|
message | Roles user, assistant, system and developer. Content is a string or parts: input_text, input_image (an https URL or a data: URL; file_id is not supported) and, for assistant turns, output_text. Leading system and developer messages are joined with instructions into one system message. |
function_call | A call the model made earlier: call_id, name, arguments (and namespace for namespaced tools). |
function_call_output | Its result: call_id and output, a string or input_text / input_image parts. Images a tool returns are shown to the model in a user turn right after the results. |
reasoning | Reasoning we returned earlier. Send it back with the rest of the turn and the model gets its own earlier reasoning again; some models need it on tool turns. |
custom_tool_call, custom_tool_call_output | The same for custom tools. |
# pip install openai
import os
from openai import OpenAI
client = OpenAI(base_url="https://api.aimodelsrouter.ai/v1", api_key=os.environ["AMR_API_KEY"])
response = client.responses.create(
model="deepseek/deepseek-v4-flash",
instructions="You are concise.",
input="Explain idempotency keys in one paragraph.",
max_output_tokens=512,
store=False,
)
print(response.output_text)
print(response.usage.model_extra["cost"]) # USD chargedResponse
idis our generation id (gen-…), also in theX-Generation-Idheader.statusiscompleted, orincompletewithincomplete_details.reason: "max_output_tokens"when the output was cut off.outputholds areasoningitem when the model reasoned, amessagewith the answer, and afunction_callorcustom_tool_callper tool call. A call to a namespaced tool carries itsnamespace.usage:input_tokens(withinput_tokens_details.cached_tokens),output_tokens(withoutput_tokens_details.reasoning_tokens),total_tokensandcost, the amount charged in USD.
Streaming
With "stream": true you get the Responses event stream. Every event has an event: line and a sequence_number. While the model is still thinking we send : keepalive comment lines, which clients ignore.
| Events | When |
|---|---|
response.created, response.in_progress | First, with the response object (status in_progress). |
response.output_item.added / .done | Each output item: reasoning, message, function_call or custom_tool_call. |
response.content_part.added / .done | The output_text part of a message. |
response.output_text.delta / .done | Answer text. |
response.reasoning_summary_part.added / .done, response.reasoning_summary_text.delta / .done | Reasoning, when the request set reasoning.summary. |
response.reasoning_text.delta / .done | Reasoning, when it did not. |
response.function_call_arguments.delta / .done | Tool-call arguments as they are generated. |
response.completed | The final response with usage and cost. response.incomplete instead when the output hit max_output_tokens. |
error, response.failed | A failure after the stream started (see Errors). |
Errors
Errors use OpenAI's envelope. type and code are both our error type from the Errors page, as a string, and param names the field when a request field is the problem:
{"error": {"message": "`previous_response_id` is not supported: AI Models Router never stores previous responses (we don't keep prompts or completions). Send the full conversation in `input`, with `store: false`.", "type": "invalid_request", "param": "previous_response_id", "code": "invalid_request"}}After a stream has started, a failure sends an error event and then response.failed. Its response has error.code (server_error when the model provider failed, otherwise our type, e.g. insufficient_credits or key_limit_exceeded) and the usage you were charged for the output already sent.