Skip to content

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.

Nothing is stored. Send the whole conversation in 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

FieldTypeDescription
modelstring, requiredModel slug, e.g. deepseek/deepseek-v4-flash.
inputstring | item[], requiredA user message, or the whole conversation as items (see below).
instructionsstringSystem instructions, sent to the model first.
toolsarrayfunction 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_choicestring | objectauto, none, required, a named function or custom tool, or allowed_tools.
parallel_tool_callsbooleanWhether the model may call several tools at once.
max_output_tokensintegerUpper bound on generated tokens. Also lowers the hold placed on your balance.
temperature, top_pnumberSampling parameters, passed through to the model.
reasoning.effortstringSent 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.summarystringAny 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.formatobjectjson_schema or json_object, for models with the structured_outputs capability.
streambooleanStream the response as server-sent events. Default false.
store, include, metadata, prompt_cache_key, userAccepted. Nothing is stored or passed to the model provider; responses report store: false and echo metadata.

Input items

ItemWhat it carries
messageRoles 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_callA call the model made earlier: call_id, name, arguments (and namespace for namespaced tools).
function_call_outputIts 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.
reasoningReasoning 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_outputThe 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 charged

Response

  • id is our generation id (gen-…), also in the X-Generation-Id header.
  • status is completed, or incomplete with incomplete_details.reason: "max_output_tokens" when the output was cut off.
  • output holds a reasoning item when the model reasoned, a message with the answer, and a function_call or custom_tool_call per tool call. A call to a namespaced tool carries its namespace.
  • usage: input_tokens (with input_tokens_details.cached_tokens), output_tokens (with output_tokens_details.reasoning_tokens), total_tokens and cost, 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.

EventsWhen
response.created, response.in_progressFirst, with the response object (status in_progress).
response.output_item.added / .doneEach output item: reasoning, message, function_call or custom_tool_call.
response.content_part.added / .doneThe output_text part of a message.
response.output_text.delta / .doneAnswer text.
response.reasoning_summary_part.added / .done, response.reasoning_summary_text.delta / .doneReasoning, when the request set reasoning.summary.
response.reasoning_text.delta / .doneReasoning, when it did not.
response.function_call_arguments.delta / .doneTool-call arguments as they are generated.
response.completedThe final response with usage and cost. response.incomplete instead when the output hit max_output_tokens.
error, response.failedA 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.