API reference
The OpenAI-compatible data plane.
Interactive OpenAPI reference
The operations below are generated from the canonical OpenAPI specification. Use Test Request to build and send a real request, inspect every field, and view the documented response and error schemas.
Testing an authenticated endpoint sends a real request and may consume credits.
Create a chat completion
post/v1/chat/completionsCreate a response
post/v1/responsesCreate embeddings
post/v1/embeddingsTranscribe audio
post/v1/audio/transcriptionsCreate speech
post/v1/audio/speechList models
get/v1/modelsCheck service health
get/healthzConventions
- Model ids are
provider/model, e.g.mistral/mistral-medium-3.5. - Money is integer micro-EUR (1 EUR = 1,000,000 µEUR), quoted per million tokens.
- Request bodies are capped at 2 MiB.
Guides and examples
Chat completion
const res = await client.chat.completions.create({
model: "mistral/mistral-medium-3.5",
messages: [{ role: "user", content: "Hallo!" }],
});res = client.chat.completions.create(
model="mistral/mistral-medium-3.5",
messages=[{"role": "user", "content": "Hallo!"}],
)curl https://api.kontinent.ai/v1/chat/completions \
-H "Authorization: Bearer $KONTINENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"mistral/mistral-medium-3.5",
"messages":[{"role":"user","content":"Hallo!"}]}'Streaming works the same way with "stream": true. See Streaming.
Tool calling works on every chat model whose supported_parameters include tools, streaming and non-streaming. A model without it returns 400 tools_not_supported. Send tools (function tools) with an optional tool_choice and parallel_tool_calls, and the model answers with message.tool_calls (or delta.tool_calls while streaming) and finish_reason: "tool_calls". Continue the loop by sending the assistant turn back with its tool_calls, followed by one {"role": "tool", "tool_call_id": "...", "content": "..."} message per call; on a reasoning model, replay that turn's reasoning_details as well.
A tool definition travels whole, strict and the JSON Schema in parameters included. Nothing tool-related is silently dropped on a path that rebuilds the request: every model on Bedrock, Claude on Vertex, and /v1/responses. There the request is refused with a 400 naming the field when an upstream cannot express a value: tool_choice: "none" and parallel_tool_calls: false on every model served by Bedrock, forcing a tool call ("required" or a named function) together with reasoning on either Claude path, and hosted tools such as web search or MCP, because this gateway runs no tools of its own. On the other providers the request is passed through untouched instead, so a tool the provider rejects comes back as that provider's own error. See Streaming for the delta shape.
JSON mode. response_format (for example {"type": "json_object"} or a json_schema) is passed to OpenAI-compatible providers unchanged, so it works wherever the provider supports it. On every model served by Bedrock (Claude, Nova, GPT-OSS, Qwen and others) and on Claude via Vertex it is currently ignored: the request succeeds, but the answer is not guaranteed to be JSON. For structured output there, use a tool with a JSON Schema in parameters and read the arguments of the tool call.
Reasoning models take a reasoning object and answer with message.reasoning and/or message.reasoning_details. Neither field is guaranteed: reasoning.exclude: true removes both, and thinking that a provider only returns encrypted arrives as a reasoning_details entry with no message.reasoning at all, because there is no plaintext. Treat both as optional. See Reasoning.
Responses
The same models, OpenAI's Responses shape. input takes a string or a list of input items, max_output_tokens replaces max_tokens, and the reply is a response object whose output array holds reasoning and message items.
curl https://api.kontinent.ai/v1/responses \
-H "Authorization: Bearer $KONTINENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"bedrock/claude-sonnet-5","input":"Hallo!",
"reasoning":{"effort":"high"}}'With "stream": true you get named events, each with a monotonic sequence_number: response.created, response.output_item.added, response.reasoning_text.delta, response.reasoning_text.done, response.content_part.added, response.output_text.delta, response.output_text.done, response.content_part.done, response.function_call_arguments.delta, response.function_call_arguments.done, response.output_item.done, response.completed, or response.failed when a generation breaks after the first byte. Item and content-part events are paired (added/done), so a client can close what it opened.
Tools work here too, in the flattened Responses shape: tools: [{"type": "function", "name": "...", "parameters": {...}}], with tool_choice and parallel_tool_calls. A call comes back as a function_call output item (call_id, name, arguments), and the loop continues by replaying it in input as a function_call item followed by a function_call_output item with the same call_id. On a reasoning model, replay the reasoning output item that preceded the call as well, reasoning_details and all: Claude verifies its own thinking and rejects a tool loop that comes back without it. The refusals are the ones chat completions make, named the same way.
Input items carry text only: an image or file content part returns 400. Fields this endpoint does not translate, such as text.format, are ignored rather than refused, so do not rely on them for structured output.
This endpoint is stateless. store: true and previous_response_id are rejected with 400. Kontinent retains no prompts or completions, so a stored response could never be read back. Send the previous turns in input instead.
Embeddings
curl https://api.kontinent.ai/v1/embeddings \
-H "Authorization: Bearer $KONTINENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"mistral/mistral-embed","input":"Hallo!"}'Other OpenAI fields such as encoding_format and dimensions are passed to the provider unchanged; whether they take effect depends on the model. stream: true returns 400, because embeddings have no incremental form. Sending a chat model here (or an embeddings model to the chat endpoint) is rejected.
Audio
Speech to text and text to speech use the OpenAI audio shapes. Send a transcription model to the first endpoint and a speech model to the second; the wrong kind is rejected.
Transcription takes multipart/form-data with file and model (both required), plus optional language, prompt, temperature, response_format and user. The file may be up to 25 MB (the whole request up to 26 MB). response_format is json (default) or text; anything else returns 400, and so does stream=true. The file name is never forwarded to the provider, only a safe extension. The whole upload must finish within 5 minutes; a slower upload is cut off and returns 400. If this gateway instance is already busy with 4 transcriptions and no slot frees up within 10 seconds, you get 503 transcriptions_busy with a Retry-After: 10 header: retry after that many seconds.
curl https://api.kontinent.ai/v1/audio/transcriptions \
-H "Authorization: Bearer $KONTINENT_API_KEY" \
-F model=scaleway/whisper-large-v3 \
-F file=@gespraech.m4a \
-F language=deSpeech takes JSON with model, input (up to 4096 characters) and voice (all required), plus optional response_format (mp3 default, wav, opus, aac, flac, pcm) and user. stream is not supported and returns 400. The reply body is the audio itself.
curl https://api.kontinent.ai/v1/audio/speech \
-H "Authorization: Bearer $KONTINENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"mistral/voxtral-tts","input":"Good morning","voice":"en_paul_neutral"}' \
--output answer.mp3- Billing. Transcription is billed per started second of audio, measured by the gateway, with a minimum of one second. Speech is billed per character of
input, counted as Unicode characters, not bytes. Prices appear in/v1/modelsasaudio_micro_eur_per_hourandcharacter_micro_eur_per_million; a field is omitted when it is zero. - Fallback. Transcription falls back along the model's fallback chain like chat. Speech never falls back to another model on its own, because a different model speaks with a different voice. Routing policies you build yourself still work.
- Voices.
voicemust be one of the voices the catalog lists for that model. Any other value is refused with400before the provider is called, and the error lists the valid voices.mistral/voxtral-ttscurrently offers English voices only. For German, useovh/nvr-tts-de-dewith the voiceGerman-DE-Male-1, its only voice. That model accepts at most 1000 characters and returns onlywav(16 kHz mono): sendresponse_formatwavor leave it out, in which case the reply iswav, notmp3. - Guardrails. Content guardrails (the prompt-injection scan) do not inspect audio. Provider blocks and zero-data-retention rules still apply.
List models
const models = await client.models.list();models = client.models.list()curl https://api.kontinent.ai/v1/models \
-H "Authorization: Bearer $KONTINENT_API_KEY"Returns every active model, the same list for every key, each with kind, context_length (where known), sovereignty, pricing, and, for models that think, a reasoning object (supported_efforts, default_effort, supports_max_tokens, mandatory). See Models & sovereignty.
Health
curl https://api.kontinent.ai/healthzUnauthenticated liveness probe. Use it for uptime monitoring, not for model availability.
Related
Limits & conventions Handling errors…