Chat Completions
Request and response schema.
POST https://api.aimodelsrouter.ai/v1/chat/completions creates a model response for a conversation. The body is the OpenAI Chat Completions request. model and a non-empty messages array are required; if the model rejects a parameter, you get 400 invalid_request with the reason.
Request body
| Field | Type | Description |
|---|---|---|
model | string, required | Model slug, e.g. deepseek/deepseek-v4-flash. |
messages | array, required | Conversation so far: objects with role (system, user, assistant, tool) and content (string or content parts). |
stream | boolean | Stream the response as server-sent events. Default false. |
stream_options | object | { include_usage: true } is accepted; the final usage chunk is always sent when streaming. |
max_tokens / max_completion_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. |
stop | string | string[] | Stop sequences. |
tools, tool_choice | array, string | object | Function calling, for models with the tools capability. |
response_format | object | JSON mode / JSON schema, for models with the structured_outputs capability. |
seed, presence_penalty, frequency_penalty | number | Passed through when the model supports them. |
user | string | Accepted for compatibility. Not stored and not passed to the model provider. |
curl https://api.aimodelsrouter.ai/v1/chat/completions \
-H "Authorization: Bearer $AMR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek/deepseek-v4-flash",
"max_tokens": 512,
"messages": [
{"role": "system", "content": "You are concise."},
{"role": "user", "content": "Explain idempotency keys in one paragraph."}
]
}'Response
| Field | Description |
|---|---|
id | Our generation id, gen-…. Also returned in the X-Generation-Id header. Use it with GET /generation?id= and to find the request in your activity log. |
model | The slug that served the request: the one you sent, or the replacement of a retired slug (then the X-AMR-Model-Alias header repeats the slug you sent). |
choices[] | OpenAI-shaped choices: message (content, tool_calls) and finish_reason. A reasoning model's trace is in both reasoning_content and reasoning (the same text), on every route; read either. |
usage | prompt_tokens, completion_tokens, total_tokens, details where reported, plus cost: the amount charged in USD (a number). |
The upstream provider that served a request is never exposed in responses. Only OpenAI-schema fields are passed on, at every level, so responses look the same whichever route served them: no
system_fingerprint, service_tier or serving-engine fields.Routing controls
| Field | Effect |
|---|---|
max_price (or provider.max_price) | {"prompt": 1, "completion": 4} in USD per 1M tokens. If the model costs more, the request is refused with 400 max_price_exceeded and nothing is charged. |
zdr (or provider.zdr) | true: use only routes whose supplier's terms promise prompts and outputs are not stored. A model without one answers 400 zdr_unavailable. See data_retention in GET /models. |
Neither is sent to the model. service_tier is not sent either: every request is served at the listed price.
Look up a generation
GET /generation?id=gen-… (authenticated) returns metadata for one of your requests: model, status, tokens, cost, latency, time to first token and creation time. GET /generations lists your recent ones and GET /usage totals them by day or model; see Usage API.
curl "https://api.aimodelsrouter.ai/v1/generation?id=gen-3f1c9b8e0a2d4c55b6e7f8a9b0c1d2e3" \
-H "Authorization: Bearer $AMR_API_KEY"