Skip to content
ABTO Guide
abto.app
Start free

Integration guide

Chat Completions

The fields POST /v1/chat/completions accepts and how they differ across providers.

POST /v1/chat/completions accepts requests in the OpenAI Chat Completions format. The Gateway rejects unsupported fields, and any field not listed here, with 400. A field with an empty “Provider differences” cell behaves the same whichever of OpenAI, Anthropic, Gemini, DeepSeek, and Kimi is assigned.

The shared rules and error sources are in the Gateway overview.

  • Anthropic requires a maximum token count. When both max_completion_tokens and max_tokens are omitted, the Gateway sends that model’s output ceiling. See max_output_tokens in GET /v1/models for each model’s value, and set the field yourself when you need a long response.
  • Anthropic adds additionalProperties: false to every object in a json_schema. A property the schema does not declare will not appear in the response.
  • Anthropic has no schema-free JSON mode. The Gateway adds a tool of its own named json_output, has the model call it, and returns the result as a content string. json_object cannot be combined with tools, and the tool name json_output cannot be used.
  • Kimi fixes its generation parameters to the values its model defines. Another value is rejected by Kimi, and you receive that response as it came.
  • DeepSeek and Kimi accept the OpenAI format as it is, so the request shape stays the same. The values they do not accept are listed per field in the tables below.
FieldSupportProvider differences
modelSupported
messages[].role: system, developerSupported (text only)Anthropic, Gemini: concatenated into one message at the front
DeepSeek, Kimi: developer is sent as system, and its position is kept
messages[].role: userSupported (string or part array)
messages[].role: assistantSupported (text only)
messages[].content[].image_url.urlSupported (base64 data URL or http(s) URL)Gemini: a URL’s type comes from the extension at the end of the address, so an address without one is rejected
Kimi: http(s) URLs are not accepted
DeepSeek: some of its models read images and some do not
messages[].content[].file.file_dataSupported (base64 PDF data URL only)DeepSeek, Kimi: PDFs are not accepted
messages[].content[].file.filenameSupportedGemini: not sent
  • Content shape: The content of a user message is a string or an array of text, image_url, and file parts. An assistant message needs content unless it carries tool_calls or reasoning_details.
  • Media parts: Images and PDFs are accepted only in user messages, and images may be png, jpeg, webp, or gif.
  • Image URLs: An image may be sent as an http(s) URL instead of a base64 data URL. The Gateway passes the address through and the provider downloads it, so the address must be publicly reachable by the provider. PDFs are accepted as base64 data URLs only.
  • System prompt: When the assigned option has a system prompt, it is used instead of the system and developer messages.
  • Model name: Before routing is configured, requests go to OpenAI, so model must be an OpenAI model name. Once routing is configured, the assigned option sets the provider and the model. The available names are in the Model list.
FieldSupportProvider differences
max_completion_tokensSupportedAnthropic: the model’s output ceiling when both are omitted
max_tokensSupported (legacy)Anthropic: the model’s output ceiling when both are omitted
nNo multiple choices (1 only)
streamNo streaming (false only)

When max_tokens and max_completion_tokens are sent together, max_completion_tokens is used.

FieldSupportProvider differences
temperatureSupportedKimi: only the value its model defines
DeepSeek: not applied while the model reasons
top_pSupportedKimi: only the value its model defines
frequency_penaltySupportedKimi: only the value its model defines
DeepSeek: not applied
presence_penaltySupportedKimi: only the value its model defines
DeepSeek: not applied
seedSupportedKimi: not applied
reasoning_effortSupportedDeepSeek, Kimi: the accepted values differ from OpenAI, so check them in the dashboard
verbositySupportedDeepSeek, Kimi: not applied
  • Before routing is configured: The values you send are used as sent, and that setup is registered as an Origin option.
  • After routing is configured: The assigned option’s values are used, and the values in the request are not applied. A parameter the option leaves unset is not sent to the provider, so the provider’s own default applies.
  • What you can set: The dashboard shows the range each option can set for a given provider and model. Options can also carry provider-specific parameters that this table does not list.
FieldSupportProvider differences
response_format: textSupported
response_format: json_schemaSupportedAnthropic: adds additionalProperties: false
DeepSeek: not accepted
response_format: json_objectSupportedAnthropic: implemented as a tool call
  • Schema: json_schema requires json_schema.schema. The inside of the schema is passed through without inspection.
  • What travels: A json_schema carries four keys — name, description, strict, and schema. Any other key is not passed on to the provider, and key names must match exactly, including case. Anthropic and Gemini rebuild it in the provider’s own format and carry only json_schema.schema, so name, description, and strict reach OpenAI only.
  • Value types: name and description are strings and strict is a boolean. A mismatched type is rejected with a 400 that names the key.
  • Combination rule: json_object cannot be sent together with tools.
FieldSupportProvider differences
toolsSupported (type: function only)
tools[].function.strictSupportedGemini: one true validates every tool
tool_choiceSupported (none, auto, required, named function)A named function may still be called more than once
tool_choice: allowed_toolsSupported (mode is auto or required only)Anthropic, DeepSeek, Kimi: tools outside the list are removed
parallel_tool_callsCannot be turned off (true only)
functionsSupported (legacy)
function_callSupported (legacy; none, auto, named function)
messages[].tool_calls[].idSupported
messages[].tool_calls[].function.argumentsSupported (JSON object string only)
messages[].role: toolSupported
messages[].role: functionSupported (legacy)
  • Combination rules: tool_choice must be sent with tools. Legacy functions cannot be sent with tools or tool_choice, and function_call requires functions.
  • Tool names and schemas: The tool name json_output cannot be used. The inside of tools[].function.parameters is passed through without inspection.
  • Returning results: Send back the tool_calls[].id and tool_call_id values you received in the response. Values that do not pair up are rejected by the provider. The content of a role: tool message is a string or a text part, and a role: function message needs a name matching the preceding function_call.
  • Response shape: A request sent with functions comes back with message.function_call and finish_reason: "function_call". When one response carries several calls, only the first one is placed in message.function_call; read the rest from message.tool_calls. Every other tool-calling response comes back with message.tool_calls and finish_reason: "tool_calls".
  • Legacy recommendation: Legacy functions expresses only one call per turn. Gemini, DeepSeek, and Kimi return several calls in one response, and answering them one at a time makes them ask for the remaining calls again, which adds turns. Use tools.
FieldSupportProvider differences
messages[].reasoning_detailsSupportedOpenAI: returns no reasoning, so there is nothing to send
  • What comes back: Reasoning models return their reasoning in message.reasoning_details. Each entry is identified by type: reasoning.text holds the text in text, and reasoning.encrypted holds a value only the provider can read in data. format names the provider that produced the reasoning.
  • Carrying it to the next turn: To continue a conversation, send the reasoning_details you received back in the assistant message without changing it. Reordering the entries or editing their contents breaks the continuation. Placing the response message object into the history as it is carries the field along.
  • Keep a conversation on one option: Send the same x-abto-device-id on every request of a multi-turn conversation. That value keeps the conversation assigned to one option so the reasoning carries over. Without it each request is assigned on its own, and once the provider changes the earlier reasoning is not used and the model reasons again.
  • When it is left out: Gemini rejects a history whose tool-calling turn is missing its reasoning. DeepSeek rejects a history that changes the tool_calls[].id values it returned and drops the reasoning as well. Anthropic and Kimi continue without it and reason again on every turn, which raises the reasoning token count.
  • Reasoning tokens: usage.completion_tokens_details.reasoning_tokens counts the tokens spent on reasoning and is separate from the reasoning contents.
  • Conversations without tools: Reasoning carries over independently of tool calling. Send it the same way in multi-turn conversations that use no tools and in conversations that use functions.

The Gateway rejects the fields below with 400. Fields that appear in no table are rejected the same way.

GroupFields
Token probabilitieslogprobs, top_logprobs, logit_bias
Audio and other inputsmodalities, audio, messages[].audio, other content parts such as input_audio
Image and file optionsmessages[].content[].image_url.detail, messages[].content[].file.file_id, an http(s) URL in messages[].content[].file.file_data
Provider-side featuresstore, service_tier, moderation, web_search_options, prediction
Prompt cachingprompt_cache_key, prompt_cache_options, prompt_cache_retention
Request tags and user identitymetadata, user, safety_identifier
Otherstop, stream_options, messages[].name (except role: function), messages[].refusal, messages[].reasoning, messages[].reasoning_content

Tagging requests at the provider and identifying users to the provider cannot be replaced. For your own analytics, send identifiers as x-abto-feature-id and x-abto-device-id from the Reference; those headers are recorded in ABTO and are not forwarded to the provider.

The Gateway sends requests in the API formats below. For the values each provider accepts and the conditions it rejects, see its documentation.