API reference
Introduction
DMM AI Router provides a REST API that lets you call many LLMs with one API key and one request format. Requests are sent as JSON and responses come back as JSON, or as Server-Sent Events when streaming. Two endpoints are offered: GET /v1/models lists the models you can call and POST /v1/chat/completions generates a chat response. Embeddings, the Responses API and image or audio input and output are not offered.
When a model is available through several providers, the cheapest route is tried first. If a provider is temporarily unavailable, whether because of an outage, rate limiting or load, the next route takes over. The provider field in the response tells you which provider answered.
https://api.airouter.dmm.com/v1curl https://api.airouter.dmm.com/v1/chat/completions \
-H "Authorization: Bearer $AIROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "google/gemini-2.5-flash", "messages": [{"role": "user", "content": "Hello!"}]}'Authentication
Pass your API key in the Authorization: Bearer header. Keys are issued under "API keys" in the dashboard, and usage is settled from the balance of the workspace the key belongs to. You can create several keys for different purposes. A revoked key stops working immediately and cannot be restored.
Each key can have a monthly spending limit. Once it is reached, requests with that key are rejected with 402 (monthly_limit_exceeded). Usage resets on the 1st of each month at 00:00 UTC.
- Use keys only on the server. Never embed them in a browser or mobile app.
- Keep keys out of source code. Load them from environment variables or a secret manager.
POST /v1/chat/completions HTTP/1.1
Host: api.airouter.dmm.com
Authorization: Bearer sk-air-...
Content-Type: application/jsoncurl https://api.airouter.dmm.com/v1/models \
-H "Authorization: Bearer $AIROUTER_API_KEY"Models
/v1/modelsLists the models you can call right now. id is the value to pass as model, and owned_by is the model developer.
Context length, maximum output, price and data retention policy for each model are on the models page. The listed price is for the cheapest route; usage is charged at the price of the route that answered.
Returns
A list of model objects.
The list object
objectstringAlways
listPossible values:listdataarrayThe models
Show 4 child attributesHide child attributes
idstringPublic model ID. The value to pass as
modelobjectstringAlways
modelPossible values:modelcreatedintegerRegistration time in UNIX seconds
owned_bystringThe model developer
curl https://api.airouter.dmm.com/v1/models \
-H "Authorization: Bearer $AIROUTER_API_KEY"{
"object": "list",
"data": [
{
"id": "google/gemini-2.5-flash",
"object": "model",
"created": 1759363200,
"owned_by": "google"
},
{
"id": "deepseek/deepseek-v4-pro",
"object": "model",
"created": 1759363200,
"owned_by": "deepseek"
}
]
}Chat Completions
/v1/chat/completionsGenerates a model reply for a conversation. With stream set to true, returns a sequence of chat.completion.chunk objects over Server-Sent Events.
Generation parameters such as temperature and reasoning_effort are applied on a best-effort basis, depending on the provider and model.
Request body
modelstringrequiredPublic model ID. Same as
idfromGET /v1/modelsmessagesarrayrequiredThe conversation, oldest first, with at least one entry. Up to 2,000,000 characters of JSON
Show 6 child attributesHide child attributes
rolestringrequiredWho is speaking
Possible values:systemuserassistanttoolcontentstring | array | nullrequiredThe text, as a string or an array of parts with
typeset totext. May benullfor an assistant message that only called toolsnamestringAn identifier for the speaker
Applies to: system, user, assistant
tool_callsarrayThe tool calls the model returned, passed back as is
Applies to: assistant
Show 3 child attributesHide child attributes
idstringrequiredCall ID. Matches
tool_call_idon the tool messagetypestringrequiredAlways
functionPossible values:functionfunctionobjectrequiredThe function to call
Show 2 child attributesHide child attributes
namestringrequiredFunction name
argumentsstringrequiredArguments as a JSON string, exactly as the model produced them
refusalstring | nullThe refusal text when the model declined to answer
Applies to: assistant
tool_call_idstringrequiredThe
idof the tool call this message answersApplies to: tool
streambooleanDefault: falsetrueto receive the reply incrementally over Server-Sent Eventsstream_optionsobjectStreaming options. Allowed only when
streamistrueShow 1 child attributesHide child attributes
include_usagebooleanHas no effect; the usage event is always sent
max_completion_tokensintegerMaximum number of output tokens
max_tokensintegerLegacy name for
max_completion_tokens. Specify only one of the tworeasoning_effortstringReasoning effort. Accepted values and their effect depend on the model
temperaturenumberSampling randomness, from 0 to 2
top_pnumberNucleus sampling probability mass, from 0 to 1
seedintegerRandom seed for deterministic output. Guarantees depend on the model
presence_penaltynumberPenalty for tokens already present, from -2 to 2
frequency_penaltynumberPenalty proportional to token frequency, from -2 to 2
response_formatobjectOutput format. No constraint when omitted
Show 2 child attributesHide child attributes
typestringrequiredThe kind of format
Possible values:textjson_objectjson_schemajson_schemaobjectRequired when
typeisjson_schemaShow 4 child attributesHide child attributes
namestringrequiredSchema name: letters, digits,
_and-, 1 to 64 charactersdescriptionstringWhat the schema describes
schemaobjectrequiredA JSON Schema object
strictbooleantrueto require strict adherence to the schema
toolsarrayFunctions the model may call
Show 2 child attributesHide child attributes
typestringrequiredAlways
functionPossible values:functionfunctionobjectrequiredThe function definition
Show 4 child attributesHide child attributes
namestringrequiredFunction name
descriptionstringWhat the function does. Helps the model decide when to call it
parametersobjectJSON Schema for the arguments
strictbooleantrueto require strict adherence to the parameter schema
tool_choicestring | objectDefault: autoControls tool use: the string
none,autoorrequired, or an object naming a function (typeset tofunctionand the name infunction.name)parallel_tool_callsbooleanfalseasks for at most one tool call per reply
Limits
- The request body may be up to 10 MiB. Larger bodies return
413(payload_too_large). messagesas a whole may be up to 2,000,000 characters of JSON. Larger conversations return400.
Returns
A chat.completion object. id equals the x-request-id response header.
The charge is prompt_tokens and completion_tokens multiplied by the model price, settled from the workspace balance. Consumption tax is added for residents of Japan.
The response object
idstringRequest ID. Equals the
x-request-idresponse headerobjectstringAlways
chat.completionPossible values:chat.completioncreatedintegerCreation time in UNIX seconds
modelstringThe public model ID that answered
providerstringThe ID of the provider that answered
choicesarrayThe generated reply. Always one entry
Show 3 child attributesHide child attributes
indexintegerChoice index. Always 0
messageobjectThe model reply
Show 4 child attributesHide child attributes
rolestringAlways
assistantPossible values:assistantcontentstring | nullThe reply text.
nullwhen the reply is tool calls onlyrefusalstring | nullThe refusal text when the model declined. Usually
nulltool_callsarrayTool calls requested by the model. Omitted when there are none
Show 3 child attributesHide child attributes
idstringrequiredCall ID. Matches
tool_call_idon the tool messagetypestringrequiredAlways
functionPossible values:functionfunctionobjectrequiredThe function to call
Show 2 child attributesHide child attributes
namestringrequiredFunction name
argumentsstringrequiredArguments as a JSON string, exactly as the model produced them
finish_reasonstringWhy generation stopped
Possible values:stoplengthtool_callscontent_filter
usageobjectToken usage
Show 5 child attributesHide child attributes
prompt_tokensintegerInput tokens
completion_tokensintegerOutput tokens
total_tokensintegerTotal
prompt_tokens_detailsobjectInput breakdown. Present only when the provider returns it
completion_tokens_detailsobjectOutput breakdown. Present only when the provider returns it
curl https://api.airouter.dmm.com/v1/chat/completions \
-H "Authorization: Bearer $AIROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "google/gemini-2.5-flash",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"}
]
}'{
"id": "01K72W3M9Q4ZJ8N2T6VY5XH0RB",
"object": "chat.completion",
"created": 1759968000,
"model": "google/gemini-2.5-flash",
"provider": "edensoft",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello! How can I help you today?",
"refusal": null
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 17,
"completion_tokens": 9,
"total_tokens": 26
}
}Streaming
Set stream to true to receive text/event-stream. Each event is JSON after data: .
Event order
- Chunks carrying the content piece by piece. Each has a delta in
choices[0].deltaand arrives as generation proceeds - The final chunk.
usageholds the token counts data: [DONE], the end of the stream
Each chunk carries only the difference in choices[0].delta. Concatenate content in order to get the text. For tool calls, join fragments that share tool_calls[].index, and parse function.arguments as JSON only after concatenating it.
The chunk object
idstringRequest ID. Equals the
x-request-idresponse headerobjectstringAlways
chat.completion.chunkPossible values:chat.completion.chunkcreatedintegerCreation time in UNIX seconds
modelstringThe public model ID that answered
providerstringThe ID of the provider that answered
choicesarrayThe delta. The usage and error events carry a single empty choice
Show 3 child attributesHide child attributes
indexintegerChoice index. Always 0
deltaobjectWhat changed since the previous chunk
Show 4 child attributesHide child attributes
rolestringassistant, on the first chunk onlycontentstring | nullA fragment of the reply text
refusalstring | nullA fragment of the refusal text
tool_callsarrayTool call fragments. Join fragments with the same
indexShow 4 child attributesHide child attributes
indexintegerrequiredWhich call the fragment belongs to
idstringOn the first fragment only
typestringfunction, on the first fragment onlyfunctionobjectFunction fragment
Show 2 child attributesHide child attributes
namestringOn the first fragment only
argumentsstringA fragment of the arguments JSON string
finish_reasonstring | nullnulluntil the last content chunk.errorwhen a failure happened after the stream startedPossible values:stoplengthtool_callscontent_filtererror
usageobjectOnly on the usage event just before the end
Show 5 child attributesHide child attributes
prompt_tokensintegerInput tokens
completion_tokensintegerOutput tokens
total_tokensintegerTotal
prompt_tokens_detailsobjectInput breakdown. Present only when the provider returns it
completion_tokens_detailsobjectOutput breakdown. Present only when the provider returns it
errorobjectOnly on the final event after a mid-stream failure. Same shape as
errorin an error responseShow 3 child attributesHide child attributes
messagestringDescription of the error
codestringStable identifier to branch on
paramstring | nullDotted path to the field at fault (array elements carry an index).
nullotherwise
curl https://api.airouter.dmm.com/v1/chat/completions \
-H "Authorization: Bearer $AIROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "google/gemini-2.5-flash",
"messages": [{"role": "user", "content": "Hello!"}],
"stream": true
}'data: {"id":"01K72W3M9Q4ZJ8N2T6VY5XH0RB","object":"chat.completion.chunk","created":1759968000,"model":"google/gemini-2.5-flash","provider":"edensoft","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"01K72W3M9Q4ZJ8N2T6VY5XH0RB","object":"chat.completion.chunk","created":1759968000,"model":"google/gemini-2.5-flash","provider":"edensoft","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}
data: {"id":"01K72W3M9Q4ZJ8N2T6VY5XH0RB","object":"chat.completion.chunk","created":1759968000,"model":"google/gemini-2.5-flash","provider":"edensoft","choices":[{"index":0,"delta":{"content":"! How can I help you today?"},"finish_reason":"stop"}]}
data: {"id":"01K72W3M9Q4ZJ8N2T6VY5XH0RB","object":"chat.completion.chunk","created":1759968000,"model":"google/gemini-2.5-flash","provider":"edensoft","choices":[{"index":0,"delta":{},"finish_reason":null}],"usage":{"prompt_tokens":17,"completion_tokens":9,"total_tokens":26}}
data: [DONE]{
"id": "01K72W3M9Q4ZJ8N2T6VY5XH0RB",
"object": "chat.completion.chunk",
"created": 1759968000,
"model": "google/gemini-2.5-flash",
"provider": "edensoft",
"choices": [
{
"index": 0,
"delta": {"content": "Hello"},
"finish_reason": null
}
]
}Tool calling
Give the model function definitions, receive call instructions, and send back the results.
- Send a request with
toolsdescribing each function: its name, description and a JSON Schema for its arguments. - When the model decides to call a function,
finish_reasonistool_callsandmessage.tool_callslists the functions to call with their arguments as JSON strings. - Run the function in your code, then append a message with
roletoolandtool_call_idset to the callid, right after the assistant message that containstool_calls, and send the request again. - The model returns a final reply that takes the results into account.
curl https://api.airouter.dmm.com/v1/chat/completions \
-H "Authorization: Bearer $AIROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "google/gemini-2.5-flash",
"messages": [{"role": "user", "content": "What is the weather in Tokyo?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name"}
},
"required": ["city"]
}
}
}],
"tool_choice": "auto"
}'{
"id": "01K72W3M9Q4ZJ8N2T6VY5XH0RB",
"object": "chat.completion",
"created": 1759968000,
"model": "google/gemini-2.5-flash",
"provider": "edensoft",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"refusal": null,
"tool_calls": [
{
"id": "call_7Yq3",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\": \"Tokyo\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
],
"usage": {
"prompt_tokens": 58,
"completion_tokens": 14,
"total_tokens": 72
}
}curl https://api.airouter.dmm.com/v1/chat/completions \
-H "Authorization: Bearer $AIROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "google/gemini-2.5-flash",
"messages": [
{"role": "user", "content": "What is the weather in Tokyo?"},
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_7Yq3",
"type": "function",
"function": {"name": "get_weather", "arguments": "{\"city\": \"Tokyo\"}"}
}
]
},
{
"role": "tool",
"tool_call_id": "call_7Yq3",
"content": "{\"temperature_c\": 24, \"condition\": \"sunny\"}"
}
],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name"}
},
"required": ["city"]
}
}
}]
}'calls = {}
for chunk in stream:
choice = chunk.choices[0]
for part in choice.delta.tool_calls or []:
call = calls.setdefault(part.index, {"id": None, "name": None, "arguments": ""})
if part.id:
call["id"] = part.id
if part.function and part.function.name:
call["name"] = part.function.name
if part.function and part.function.arguments:
call["arguments"] += part.function.arguments
if choice.finish_reason == "tool_calls":
break
# calls[index]["arguments"] is now a complete JSON stringStructured outputs
Use response_format to constrain the reply to JSON. json_schema asks for JSON that follows a schema, and json_object asks for any valid JSON.
json_schema.name and json_schema.schema are required. With strict set to true, supporting models adhere strictly to the schema. message.content in the response is a JSON string, so parse it on your side.
curl https://api.airouter.dmm.com/v1/chat/completions \
-H "Authorization: Bearer $AIROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "google/gemini-2.5-flash",
"messages": [
{"role": "system", "content": "Extract the event details."},
{"role": "user", "content": "Team lunch on Friday at 12:30 in Shibuya."}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "event",
"schema": {
"type": "object",
"properties": {
"title": {"type": "string"},
"day": {"type": "string"},
"time": {"type": "string"},
"location": {"type": "string"}
},
"required": ["title", "day", "time", "location"],
"additionalProperties": false
},
"strict": true
}
}
}'{
"role": "assistant",
"content": "{\"title\":\"Team lunch\",\"day\":\"Friday\",\"time\":\"12:30\",\"location\":\"Shibuya\"}",
"refusal": null
}{
"model": "google/gemini-2.5-flash",
"messages": [
{"role": "system", "content": "Answer in JSON with keys \"answer\" and \"confidence\"."},
{"role": "user", "content": "What is the capital of Japan?"}
],
"response_format": {"type": "json_object"}
}{
"error": {
"message": "This model does not support JSON output.",
"code": "unsupported_parameter",
"param": "response_format"
}
}Errors
Errors are returned as an HTTP status with a JSON body: a single error object with message, code and param.
The error object
messagestringDescription of the error
codestringStable identifier to branch on
paramstring | nullDotted path to the field at fault (array elements carry an index).
nullotherwise
Errors mid-stream
Failures before the stream starts are ordinary HTTP error responses. After it starts, the HTTP status stays 200: an event with finish_reason error and an error object is sent, followed by [DONE]. Discard any partial text or retry.
HTTP status
| HTTP status | Meaning |
|---|---|
| 400 | The request is invalid |
| 401 | The API key is invalid |
| 402 | Insufficient balance, or the key monthly limit |
| 404 | The model does not exist |
| 413 | The body is too large |
| 5xx | Server or provider failure |
Error codes
| code | Meaning |
|---|---|
| validation_failed400 | The body does not match the specification. param points to the fieldFix the field named by param and message |
| invalid_request400 | The HTTP request itself is malformed, for example unparsable JSONCheck how the request is built |
| unsupported_parameter400 | The model does not support the requested option (such as JSON output)Remove the option or use another model |
| provider_rejected_request400 | Every provider rejected the request because of its content. A parameter or the input does not suit the modelDrop parameters, revise the input, or use another model |
| invalid_api_key401 | The key is missing, malformed or revokedCheck the Authorization header and the key |
| insufficient_credits402 | The workspace balance is too lowTop up |
| monthly_limit_exceeded402 | The key reached its monthly limitRaise the limit or wait for next month |
| model_not_found404 | The model does not exist or has been retiredCheck the ID with GET /v1/models |
| payload_too_large413 | The body exceeds 10 MiBReduce the input |
| internal_error5xx | A server or provider failureRetry after a short wait |
Requests that produce no response are not billed.
Every response carries an x-request-id header. When contacting support, include this value and the time of the request.
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
x-request-id: 01K72W3M9Q4ZJ8N2T6VY5XH0RB
{
"error": {
"message": "messages[1].role: role must be one of system, user, assistant or tool.",
"code": "validation_failed",
"param": "messages[1].role"
}
}data: {"id":"01K72W3M9Q4ZJ8N2T6VY5XH0RB","object":"chat.completion.chunk","created":1759968000,"model":"google/gemini-2.5-flash","provider":"edensoft","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}
data: {"id":"01K72W3M9Q4ZJ8N2T6VY5XH0RB","object":"chat.completion.chunk","created":1759968000,"model":"google/gemini-2.5-flash","provider":"edensoft","choices":[{"index":0,"delta":{},"finish_reason":"error"}],"error":{"message":"An unexpected error occurred. Please try again later.","code":"internal_error","param":null}}
data: [DONE]