# Introduction
> EUrouter is a unified AI API for accessing leading models through European infrastructure with configurable routing and retention controls.
Source: https://www.eurouter.ai/docs
***
## Get Started [#get-started]
Getting started with EUrouter is easy. Just follow the steps below.
Create an API key and make your first request.
Explore the full API documentation.
Browse all available models and pricing.
Browse all available providers and their models.
***
## What is EUrouter? [#what-is-eurouter]
EUrouter provides a single, consistent API for accessing leading AI models through infrastructure hosted in the EU.
All requests are routed and processed entirely inside the European Union, making it easy to build GDPR-aligned AI applications without juggling multiple integrations.
If you're already familiar with the OpenAI or OpenRouter APIs, EUrouter will feel instantly familiar — just change the base URL.
All inference traffic is processed inside the EU. GDPR-aligned by design.
One endpoint. One API key. No provider-specific integrations needed.
Automatic provider selection based on speed, costs and availability.
Built-in failover keeps your application running during provider outages or rate limits.
***
## Why EUrouter exists [#why-eurouter-exists]
Modern AI development comes with avoidable complexity:
* Every provider has its own API, authentication, and billing.
* Most inference traffic leaves the EU.
* Outages or rate limits at a single provider can halt your entire application.
* Switching models often means rewriting code.
EUrouter removes these barriers so you can focus on building.
***
## Quick Example [#quick-example]
```bash
curl https://api.eurouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $EUROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "mistral-large-3",
"messages": [{"role": "user", "content": "Hello!"}]
}'
```
Using OpenAI or OpenRouter already?
```bash
# Just change the base URL:
# From: https://api.openai.com/v1
# Or: https://openrouter.ai/api/v1
# To: https://api.eurouter.ai/api/v1
```
---
# Audio
> API reference for Audio
Source: https://www.eurouter.ai/docs/api/audio
## POST /api/v1/audio/speech
Create speech
Generate audio from text (text-to-speech). Returns raw audio bytes by default, or `speech.audio.delta`/`speech.audio.done` SSE events when `stream_format` is `"sse"`.
```json
{
"operation": {
"summary": "Create speech",
"tags": [
"Audio"
],
"description": "Generate audio from text (text-to-speech). Returns raw audio bytes by default, or `speech.audio.delta`/`speech.audio.done` SSE events when `stream_format` is `\"sse\"`.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"model": {
"description": "Model identifier (e.g., \"openai/tts-1\")",
"type": "string"
},
"rule_id": {
"description": "Routing rule ID to apply",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"rule_name": {
"description": "Routing rule name to apply",
"type": "string"
},
"input": {
"description": "Text to synthesize (max 4096 characters)",
"type": "string",
"minLength": 1,
"maxLength": 4096
},
"voice": {
"description": "Voice identifier",
"type": "string"
},
"response_format": {
"description": "Output audio format",
"default": "mp3",
"type": "string",
"enum": [
"mp3",
"opus",
"aac",
"flac",
"wav",
"pcm"
]
},
"speed": {
"description": "Playback speed (0.25-4.0)",
"default": 1,
"type": "number",
"minimum": 0.25,
"maximum": 4
},
"instructions": {
"description": "Natural-language voice/delivery instructions",
"type": "string"
},
"stream_format": {
"description": "Streaming transport: raw audio bytes or SSE events",
"default": "audio",
"type": "string",
"enum": [
"audio",
"sse"
]
},
"input_references": {
"description": "Reference audio samples for voice cloning",
"type": "array",
"items": {
"type": "object",
"properties": {
"data": {
"description": "Base64-encoded reference audio (voice cloning), ≤20 MiB base64 / ≤15 MiB decoded",
"type": "string",
"maxLength": 20971520
},
"format": {
"description": "Reference audio format",
"type": "string",
"enum": [
"wav",
"mp3",
"flac",
"m4a",
"ogg",
"webm",
"aac"
]
}
},
"required": [
"data"
]
}
},
"provider": {
"description": "Provider routing preferences",
"type": "object",
"properties": {
"order": {
"description": "Provider priority order - try these first, in order",
"type": "array",
"items": {
"type": "string"
}
},
"ignore": {
"description": "Providers to exclude from routing",
"type": "array",
"items": {
"type": "string"
}
},
"only": {
"description": "Only use these providers (exclusive list)",
"type": "array",
"items": {
"type": "string"
}
},
"allow_fallbacks": {
"description": "Allow fallback to other providers on failure (default: true)",
"type": "boolean"
},
"sort": {
"description": "Sort strategy: price (cheapest), latency (fastest), throughput (highest tokens/s)",
"type": "string",
"enum": [
"price",
"latency",
"throughput"
]
},
"require_parameters": {
"description": "Only use providers that support all request parameters",
"type": "boolean"
},
"quantizations": {
"description": "Filter by model quantization levels",
"type": "array",
"items": {
"description": "Model quantization level",
"type": "string",
"enum": [
"int4",
"int8",
"fp4",
"fp6",
"fp8",
"fp16",
"bf16",
"fp32"
]
}
},
"data_collection": {
"description": "Filter providers by data collection policy",
"type": "string",
"enum": [
"allow",
"deny"
]
},
"data_residency": {
"description": "Filter endpoints by geographic data processing region",
"type": "string",
"minLength": 2,
"maxLength": 10
},
"max_retention_days": {
"description": "Maximum data retention period in days (0 = ZDR only)",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"eu_owned": {
"description": "Only use EU-headquartered providers",
"type": "boolean"
}
}
},
"trace": {
"description": "Trace context for Broadcast observability",
"type": "object",
"properties": {
"trace_id": {
"description": "Groups multiple requests into a single trace",
"type": "string"
},
"trace_name": {
"description": "Custom name for the root trace",
"type": "string"
},
"span_name": {
"description": "Creates a parent span grouping LLM operations",
"type": "string"
},
"generation_name": {
"description": "Names the specific LLM generation span",
"type": "string"
},
"parent_span_id": {
"description": "Links to an existing external span in your trace hierarchy",
"type": "string"
}
},
"additionalProperties": {}
},
"session_id": {
"description": "Session identifier for grouping related requests",
"type": "string",
"maxLength": 128
}
},
"required": [
"input"
],
"additionalProperties": {}
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Default Response"
}
},
"operationId": "createSpeech"
}
}
```
## POST /api/v1/audio/transcriptions
Create transcription
Transcribe audio to text (speech-to-text). Accepts multipart file upload or JSON `input_audio`.
```json
{
"operation": {
"summary": "Create transcription",
"tags": [
"Audio"
],
"description": "Transcribe audio to text (speech-to-text). Accepts multipart file upload or JSON `input_audio`.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"model": {
"description": "Model identifier (e.g., \"openai/whisper-1\")",
"type": "string"
},
"rule_id": {
"description": "Routing rule ID to apply",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"rule_name": {
"description": "Routing rule name to apply",
"type": "string"
},
"input_audio": {
"description": "Base64-encoded audio input",
"type": "object",
"properties": {
"data": {
"description": "Base64-encoded audio data",
"type": "string"
},
"format": {
"description": "Audio format",
"type": "string",
"enum": [
"wav",
"mp3",
"flac",
"m4a",
"ogg",
"webm",
"aac"
]
}
},
"required": [
"data",
"format"
]
},
"language": {
"description": "ISO-639-1 language hint",
"type": "string"
},
"prompt": {
"description": "Optional text to guide the transcription style",
"type": "string"
},
"response_format": {
"default": "json",
"description": "Transcription response format",
"type": "string",
"enum": [
"json",
"text",
"srt",
"verbose_json",
"vtt"
]
},
"temperature": {
"description": "Sampling temperature (0-1)",
"type": "number",
"minimum": 0,
"maximum": 1
},
"timestamp_granularities": {
"description": "Timestamp detail level (verbose_json only)",
"type": "array",
"items": {
"type": "string",
"enum": [
"word",
"segment"
]
}
},
"stream": {
"description": "Enable streaming transcript events",
"type": "boolean"
},
"include": {
"description": "Additional fields to include (e.g. \"logprobs\")",
"type": "array",
"items": {
"type": "string"
}
},
"chunking_strategy": {
"description": "Chunking strategy: \"auto\" or a provider-specific config object",
"anyOf": [
{
"type": "string",
"enum": [
"auto"
]
},
{
"type": "object",
"properties": {},
"additionalProperties": {}
}
]
},
"provider": {
"description": "Provider routing preferences",
"type": "object",
"properties": {
"order": {
"description": "Provider priority order - try these first, in order",
"type": "array",
"items": {
"type": "string"
}
},
"ignore": {
"description": "Providers to exclude from routing",
"type": "array",
"items": {
"type": "string"
}
},
"only": {
"description": "Only use these providers (exclusive list)",
"type": "array",
"items": {
"type": "string"
}
},
"allow_fallbacks": {
"description": "Allow fallback to other providers on failure (default: true)",
"type": "boolean"
},
"sort": {
"description": "Sort strategy: price (cheapest), latency (fastest), throughput (highest tokens/s)",
"type": "string",
"enum": [
"price",
"latency",
"throughput"
]
},
"require_parameters": {
"description": "Only use providers that support all request parameters",
"type": "boolean"
},
"quantizations": {
"description": "Filter by model quantization levels",
"type": "array",
"items": {
"description": "Model quantization level",
"type": "string",
"enum": [
"int4",
"int8",
"fp4",
"fp6",
"fp8",
"fp16",
"bf16",
"fp32"
]
}
},
"data_collection": {
"description": "Filter providers by data collection policy",
"type": "string",
"enum": [
"allow",
"deny"
]
},
"data_residency": {
"description": "Filter endpoints by geographic data processing region",
"type": "string",
"minLength": 2,
"maxLength": 10
},
"max_retention_days": {
"description": "Maximum data retention period in days (0 = ZDR only)",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"eu_owned": {
"description": "Only use EU-headquartered providers",
"type": "boolean"
}
}
},
"trace": {
"description": "Trace context for Broadcast observability",
"type": "object",
"properties": {
"trace_id": {
"description": "Groups multiple requests into a single trace",
"type": "string"
},
"trace_name": {
"description": "Custom name for the root trace",
"type": "string"
},
"span_name": {
"description": "Creates a parent span grouping LLM operations",
"type": "string"
},
"generation_name": {
"description": "Names the specific LLM generation span",
"type": "string"
},
"parent_span_id": {
"description": "Links to an existing external span in your trace hierarchy",
"type": "string"
}
},
"additionalProperties": {}
},
"session_id": {
"description": "Session identifier for grouping related requests",
"type": "string",
"maxLength": 128
}
},
"required": [
"input_audio"
],
"additionalProperties": {}
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Default Response"
}
},
"operationId": "createTranscription"
}
}
```
---
# Broadcast
> API reference for Broadcast
Source: https://www.eurouter.ai/docs/api/broadcast
## GET /api/v1/broadcast-destinations
List broadcast destinations
Retrieve all broadcast destinations for the authenticated user.
```json
{
"operation": {
"summary": "List broadcast destinations",
"tags": [
"Broadcast"
],
"description": "Retrieve all broadcast destinations for the authenticated user.",
"parameters": [
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "query",
"name": "workspace_id",
"required": false,
"description": "Filter destinations by workspace ID. Omit to list all accessible destinations; when set, account-wide destinations (workspace_id null) are also included."
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "List of broadcast destinations",
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"description": "Unique destination identifier",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"name": {
"description": "Display name for the destination",
"type": "string"
},
"type": {
"description": "Destination type (langwatch, langfuse, datadog, otel, webhook)",
"type": "string"
},
"config": {
"description": "Destination configuration (endpoint, apiKey, etc.)",
"type": "object",
"additionalProperties": {}
},
"org_id": {
"description": "Organization that owns the destination (null for personal)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"workspace_id": {
"description": "Workspace the destination is scoped to (null = fires for the whole account)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"privacy_mode": {
"description": "Whether to strip sensitive data before export",
"type": "boolean"
},
"sampling_rate": {
"description": "Sampling rate as numeric string (0.00–1.00)",
"type": "string"
},
"enabled": {
"description": "Whether the destination is active",
"type": "boolean"
},
"api_key_filter": {
"description": "Limit export to specific API key IDs",
"nullable": true,
"type": "array",
"items": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
}
},
"created_at": {
"description": "ISO 8601 creation timestamp",
"type": "string"
},
"updated_at": {
"description": "ISO 8601 last update timestamp",
"type": "string"
}
},
"required": [
"id",
"name",
"type",
"config",
"org_id",
"workspace_id",
"privacy_mode",
"sampling_rate",
"enabled",
"api_key_filter",
"created_at",
"updated_at"
]
}
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "listBroadcastDestinations"
}
}
```
## POST /api/v1/broadcast-destinations
Create broadcast destination
Create a new broadcast destination for exporting observability data.
```json
{
"operation": {
"summary": "Create broadcast destination",
"tags": [
"Broadcast"
],
"description": "Create a new broadcast destination for exporting observability data.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"description": "Display name for the destination (1–255 characters)",
"type": "string",
"minLength": 1,
"maxLength": 255
},
"type": {
"description": "Destination type",
"type": "string",
"enum": [
"langwatch",
"langfuse",
"datadog",
"otel",
"posthog",
"sentry",
"webhook"
]
},
"config": {
"description": "Destination configuration (endpoint, apiKey, etc.)",
"type": "object",
"additionalProperties": {}
},
"workspace_id": {
"description": "Scope the destination to a workspace (omit/null = fires for the whole account)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"privacy_mode": {
"description": "Strip sensitive data before export (default: false)",
"default": false,
"type": "boolean"
},
"sampling_rate": {
"description": "Sampling rate 0.0–1.0 (default: 1.0)",
"default": 1,
"type": "number",
"minimum": 0,
"maximum": 1
},
"enabled": {
"description": "Whether the destination is active (default: true)",
"default": true,
"type": "boolean"
},
"api_key_filter": {
"description": "Limit export to specific API key IDs",
"nullable": true,
"type": "array",
"items": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
}
}
},
"required": [
"name",
"type",
"config"
]
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "The broadcast destination",
"type": "object",
"properties": {
"id": {
"description": "Unique destination identifier",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"name": {
"description": "Display name for the destination",
"type": "string"
},
"type": {
"description": "Destination type (langwatch, langfuse, datadog, otel, webhook)",
"type": "string"
},
"config": {
"description": "Destination configuration (endpoint, apiKey, etc.)",
"type": "object",
"additionalProperties": {}
},
"org_id": {
"description": "Organization that owns the destination (null for personal)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"workspace_id": {
"description": "Workspace the destination is scoped to (null = fires for the whole account)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"privacy_mode": {
"description": "Whether to strip sensitive data before export",
"type": "boolean"
},
"sampling_rate": {
"description": "Sampling rate as numeric string (0.00–1.00)",
"type": "string"
},
"enabled": {
"description": "Whether the destination is active",
"type": "boolean"
},
"api_key_filter": {
"description": "Limit export to specific API key IDs",
"nullable": true,
"type": "array",
"items": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
}
},
"created_at": {
"description": "ISO 8601 creation timestamp",
"type": "string"
},
"updated_at": {
"description": "ISO 8601 last update timestamp",
"type": "string"
}
},
"required": [
"id",
"name",
"type",
"config",
"org_id",
"workspace_id",
"privacy_mode",
"sampling_rate",
"enabled",
"api_key_filter",
"created_at",
"updated_at"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "createBroadcastDestination"
}
}
```
## POST /api/v1/broadcast-destinations/test
Test broadcast destination config
Send a test trace to verify connectivity and credentials before saving a destination.
```json
{
"operation": {
"summary": "Test broadcast destination config",
"tags": [
"Broadcast"
],
"description": "Send a test trace to verify connectivity and credentials before saving a destination.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"type": {
"description": "Destination type",
"type": "string",
"enum": [
"langwatch",
"langfuse",
"datadog",
"otel",
"posthog",
"sentry",
"webhook"
]
},
"config": {
"description": "Destination configuration to test",
"type": "object",
"additionalProperties": {}
}
},
"required": [
"type",
"config"
]
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"success": {
"description": "Whether the test trace was accepted",
"type": "boolean"
},
"status": {
"description": "HTTP status code from the destination",
"type": "number"
},
"message": {
"description": "Error message if the test failed",
"type": "string"
}
},
"required": [
"success"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "testBroadcastDestinationConfig"
}
}
```
## GET /api/v1/broadcast-destinations/{id}
Get broadcast destination
Retrieve a specific broadcast destination by ID.
```json
{
"operation": {
"summary": "Get broadcast destination",
"tags": [
"Broadcast"
],
"description": "Retrieve a specific broadcast destination by ID.",
"parameters": [
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "id",
"required": true,
"description": "Broadcast destination UUID"
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "The broadcast destination",
"type": "object",
"properties": {
"id": {
"description": "Unique destination identifier",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"name": {
"description": "Display name for the destination",
"type": "string"
},
"type": {
"description": "Destination type (langwatch, langfuse, datadog, otel, webhook)",
"type": "string"
},
"config": {
"description": "Destination configuration (endpoint, apiKey, etc.)",
"type": "object",
"additionalProperties": {}
},
"org_id": {
"description": "Organization that owns the destination (null for personal)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"workspace_id": {
"description": "Workspace the destination is scoped to (null = fires for the whole account)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"privacy_mode": {
"description": "Whether to strip sensitive data before export",
"type": "boolean"
},
"sampling_rate": {
"description": "Sampling rate as numeric string (0.00–1.00)",
"type": "string"
},
"enabled": {
"description": "Whether the destination is active",
"type": "boolean"
},
"api_key_filter": {
"description": "Limit export to specific API key IDs",
"nullable": true,
"type": "array",
"items": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
}
},
"created_at": {
"description": "ISO 8601 creation timestamp",
"type": "string"
},
"updated_at": {
"description": "ISO 8601 last update timestamp",
"type": "string"
}
},
"required": [
"id",
"name",
"type",
"config",
"org_id",
"workspace_id",
"privacy_mode",
"sampling_rate",
"enabled",
"api_key_filter",
"created_at",
"updated_at"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "getBroadcastDestination"
}
}
```
## PATCH /api/v1/broadcast-destinations/{id}
Update broadcast destination
Update an existing broadcast destination. Only provided fields are changed.
```json
{
"operation": {
"summary": "Update broadcast destination",
"tags": [
"Broadcast"
],
"description": "Update an existing broadcast destination. Only provided fields are changed.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"description": "New display name",
"type": "string",
"minLength": 1,
"maxLength": 255
},
"type": {
"description": "New destination type",
"type": "string",
"enum": [
"langwatch",
"langfuse",
"datadog",
"otel",
"posthog",
"sentry",
"webhook"
]
},
"config": {
"description": "New configuration (replaces existing)",
"type": "object",
"additionalProperties": {}
},
"privacy_mode": {
"description": "Strip sensitive data before export",
"type": "boolean"
},
"sampling_rate": {
"description": "Sampling rate 0.0–1.0",
"type": "number",
"minimum": 0,
"maximum": 1
},
"enabled": {
"description": "Whether the destination is active",
"type": "boolean"
},
"api_key_filter": {
"description": "Limit export to specific API key IDs (null to remove)",
"nullable": true,
"type": "array",
"items": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
}
}
}
}
}
}
},
"parameters": [
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "id",
"required": true,
"description": "Broadcast destination UUID"
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "The broadcast destination",
"type": "object",
"properties": {
"id": {
"description": "Unique destination identifier",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"name": {
"description": "Display name for the destination",
"type": "string"
},
"type": {
"description": "Destination type (langwatch, langfuse, datadog, otel, webhook)",
"type": "string"
},
"config": {
"description": "Destination configuration (endpoint, apiKey, etc.)",
"type": "object",
"additionalProperties": {}
},
"org_id": {
"description": "Organization that owns the destination (null for personal)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"workspace_id": {
"description": "Workspace the destination is scoped to (null = fires for the whole account)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"privacy_mode": {
"description": "Whether to strip sensitive data before export",
"type": "boolean"
},
"sampling_rate": {
"description": "Sampling rate as numeric string (0.00–1.00)",
"type": "string"
},
"enabled": {
"description": "Whether the destination is active",
"type": "boolean"
},
"api_key_filter": {
"description": "Limit export to specific API key IDs",
"nullable": true,
"type": "array",
"items": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
}
},
"created_at": {
"description": "ISO 8601 creation timestamp",
"type": "string"
},
"updated_at": {
"description": "ISO 8601 last update timestamp",
"type": "string"
}
},
"required": [
"id",
"name",
"type",
"config",
"org_id",
"workspace_id",
"privacy_mode",
"sampling_rate",
"enabled",
"api_key_filter",
"created_at",
"updated_at"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "updateBroadcastDestination"
}
}
```
## DELETE /api/v1/broadcast-destinations/{id}
Delete broadcast destination
Permanently delete a broadcast destination.
```json
{
"operation": {
"summary": "Delete broadcast destination",
"tags": [
"Broadcast"
],
"description": "Permanently delete a broadcast destination.",
"parameters": [
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "id",
"required": true,
"description": "Broadcast destination UUID"
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"success": {
"description": "Whether the deletion was successful",
"type": "boolean"
}
},
"required": [
"success"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "deleteBroadcastDestination"
}
}
```
## POST /api/v1/broadcast-destinations/{id}/test
Test saved broadcast destination
Send a test trace to a saved destination to verify it still works.
```json
{
"operation": {
"summary": "Test saved broadcast destination",
"tags": [
"Broadcast"
],
"description": "Send a test trace to a saved destination to verify it still works.",
"parameters": [
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "id",
"required": true,
"description": "Broadcast destination UUID"
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"success": {
"description": "Whether the test trace was accepted",
"type": "boolean"
},
"status": {
"description": "HTTP status code from the destination",
"type": "number"
},
"message": {
"description": "Error message if the test failed",
"type": "string"
}
},
"required": [
"success"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "testSavedBroadcastDestination"
}
}
```
---
# BYOK
> Bring-your-own-key provider credential management
Source: https://www.eurouter.ai/docs/api/byok
## GET /api/v1/byok
List BYOK provider credentials
List personal bring-your-own-key (BYOK) provider credentials owned by the authenticated Pro or Enterprise user. Use the provider query parameter to filter by upstream provider.
```json
{
"operation": {
"summary": "List BYOK provider credentials",
"tags": [
"BYOK"
],
"description": "List personal bring-your-own-key (BYOK) provider credentials owned by the authenticated Pro or Enterprise user. Use the provider query parameter to filter by upstream provider.",
"parameters": [
{
"schema": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"in": "query",
"name": "offset",
"required": false,
"description": "Number of records to skip for pagination"
},
{
"schema": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"in": "query",
"name": "limit",
"required": false,
"description": "Maximum number of records to return (max 100)"
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "provider",
"required": false,
"description": "Optional provider slug to filter by (e.g. `openai`, `anthropic`, `aws-bedrock`)."
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "List of BYOK credentials.",
"type": "array",
"items": {
"type": "object",
"properties": {
"allowed_api_key_hashes": {
"description": "Optional allowlist of EUrouter API key hashes (`api_keys.hash`) that may use this credential. `null` means no restriction.",
"nullable": true,
"type": "array",
"items": {
"type": "string"
}
},
"allowed_models": {
"description": "Optional allowlist of model slugs this credential may be used for. `null` means no restriction.",
"nullable": true,
"type": "array",
"items": {
"type": "string"
}
},
"always_use": {
"description": "Always use this credential for its provider: when true (on a non-fallback credential), EUrouter never falls back to its own shared endpoints for this provider — requests fail rather than silently running on EUrouter keys/billing.",
"type": "boolean"
},
"created_at": {
"description": "ISO timestamp of when the credential was created.",
"type": "string"
},
"disabled": {
"description": "Whether this credential is currently disabled.",
"type": "boolean"
},
"id": {
"description": "Stable public identifier for this BYOK credential.",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"is_fallback": {
"description": "Whether this credential is treated as a fallback - used only after non-fallback keys for the same provider have been tried.",
"type": "boolean"
},
"label": {
"description": "Short masked snippet of the key (e.g. the first/last few characters) used to identify it in the UI.",
"type": "string"
},
"last_used": {
"description": "ISO timestamp of the most recent provider attempt with this credential. `null` means it has not been used yet or tracking is not available.",
"nullable": true,
"type": "string"
},
"name": {
"description": "Optional human-readable name for the credential.",
"nullable": true,
"type": "string"
},
"provider": {
"description": "The upstream provider this credential authenticates against, as a lowercase slug (e.g. `openai`, `anthropic`, `aws-bedrock`).",
"type": "string"
},
"sort_order": {
"description": "Position within the provider - credentials are tried in ascending sort order.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"allowed_api_key_hashes",
"allowed_models",
"always_use",
"created_at",
"disabled",
"id",
"is_fallback",
"label",
"last_used",
"provider",
"sort_order"
]
}
},
"total_count": {
"description": "Total number of BYOK credentials matching the filters.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"data",
"total_count"
]
}
}
}
}
},
"operationId": "listByokProviderCredentials"
}
}
```
## POST /api/v1/byok
Create a BYOK provider credential
Create a personal bring-your-own-key (BYOK) provider credential for the authenticated Pro or Enterprise user. The raw key is encrypted at rest and never returned in API responses.
```json
{
"operation": {
"summary": "Create a BYOK provider credential",
"tags": [
"BYOK"
],
"description": "Create a personal bring-your-own-key (BYOK) provider credential for the authenticated Pro or Enterprise user. The raw key is encrypted at rest and never returned in API responses.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"allowed_api_key_hashes": {
"description": "Optional allowlist of EUrouter API key hashes (`api_keys.hash`) that may use this credential. `null` means no restriction.",
"nullable": true,
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
"allowed_models": {
"description": "Optional allowlist of model slugs this credential may be used for. `null` means no restriction.",
"nullable": true,
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
"always_use": {
"description": "Always use this credential for its provider, without falling back to EUrouter shared endpoints.",
"type": "boolean"
},
"disabled": {
"description": "Whether this credential is disabled.",
"type": "boolean"
},
"is_fallback": {
"description": "Whether this credential is treated as a fallback - used only after non-fallback keys for the same provider have been tried.",
"type": "boolean"
},
"name": {
"description": "Optional human-readable name for the credential.",
"nullable": true,
"type": "string",
"minLength": 1,
"maxLength": 255
},
"sort_order": {
"description": "Position within the provider. Credentials are tried in ascending sort order.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"key": {
"description": "The raw provider credential (OpenRouter-compatible formats). Plain API key string for most providers. AWS Bedrock: a Bedrock API key string (region-locked to where it was issued) or an AWS credentials JSON `{\"accessKeyId\",\"secretAccessKey\"[,\"sessionToken\"]}` for multi-region SigV4. Microsoft Foundry: `{\"api_key\",\"resource_name\"[,\"resource_type\":\"ai_foundry\"]}`. EUrouter always calls the model's EU region/location for data residency, so any `region` field is ignored. Encrypted at rest and never returned in API responses.",
"type": "string",
"minLength": 1
},
"provider": {
"description": "The upstream provider this credential authenticates against, as a lowercase slug (e.g. `openai`, `anthropic`, `aws-bedrock`).",
"type": "string",
"minLength": 1
}
},
"required": [
"key",
"provider"
]
}
}
},
"required": true
},
"responses": {
"201": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "The BYOK provider credential",
"type": "object",
"properties": {
"allowed_api_key_hashes": {
"description": "Optional allowlist of EUrouter API key hashes (`api_keys.hash`) that may use this credential. `null` means no restriction.",
"nullable": true,
"type": "array",
"items": {
"type": "string"
}
},
"allowed_models": {
"description": "Optional allowlist of model slugs this credential may be used for. `null` means no restriction.",
"nullable": true,
"type": "array",
"items": {
"type": "string"
}
},
"always_use": {
"description": "Always use this credential for its provider: when true (on a non-fallback credential), EUrouter never falls back to its own shared endpoints for this provider — requests fail rather than silently running on EUrouter keys/billing.",
"type": "boolean"
},
"created_at": {
"description": "ISO timestamp of when the credential was created.",
"type": "string"
},
"disabled": {
"description": "Whether this credential is currently disabled.",
"type": "boolean"
},
"id": {
"description": "Stable public identifier for this BYOK credential.",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"is_fallback": {
"description": "Whether this credential is treated as a fallback - used only after non-fallback keys for the same provider have been tried.",
"type": "boolean"
},
"label": {
"description": "Short masked snippet of the key (e.g. the first/last few characters) used to identify it in the UI.",
"type": "string"
},
"last_used": {
"description": "ISO timestamp of the most recent provider attempt with this credential. `null` means it has not been used yet or tracking is not available.",
"nullable": true,
"type": "string"
},
"name": {
"description": "Optional human-readable name for the credential.",
"nullable": true,
"type": "string"
},
"provider": {
"description": "The upstream provider this credential authenticates against, as a lowercase slug (e.g. `openai`, `anthropic`, `aws-bedrock`).",
"type": "string"
},
"sort_order": {
"description": "Position within the provider - credentials are tried in ascending sort order.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"allowed_api_key_hashes",
"allowed_models",
"always_use",
"created_at",
"disabled",
"id",
"is_fallback",
"label",
"last_used",
"provider",
"sort_order"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "createAByokProviderCredential"
}
}
```
## POST /api/v1/byok/test
Test a BYOK provider credential before saving it
For an authenticated Pro or Enterprise user, run live checks against the provider with a raw credential without storing anything. Multi-region providers (AWS Bedrock) are checked against every EU region in the EUrouter catalog, so region-locked keys show exactly where they work. All checks are free provider calls, except AWS SigV4 credentials which send a single 1-max-token request per region. A failing key returns success=false with per-check reasons (not an error status).
```json
{
"operation": {
"summary": "Test a BYOK provider credential before saving it",
"tags": [
"BYOK"
],
"description": "For an authenticated Pro or Enterprise user, run live checks against the provider with a raw credential without storing anything. Multi-region providers (AWS Bedrock) are checked against every EU region in the EUrouter catalog, so region-locked keys show exactly where they work. All checks are free provider calls, except AWS SigV4 credentials which send a single 1-max-token request per region. A failing key returns success=false with per-check reasons (not an error status).",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"key": {
"description": "The raw provider credential to test, in the same format the create endpoint accepts for this provider.",
"type": "string",
"minLength": 1
},
"provider": {
"description": "The upstream provider slug to test against (e.g. `openai`, `aws-bedrock`, `microsoft-foundry`).",
"type": "string",
"minLength": 1
}
},
"required": [
"key",
"provider"
]
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"checks": {
"description": "Per-target results. Multi-region providers report one check per seeded EU region so region-locked keys show exactly where they work.",
"type": "array",
"items": {
"type": "object",
"properties": {
"latency_ms": {
"description": "Wall-clock duration of this check in milliseconds.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"message": {
"description": "Actionable detail — the upstream failure reason, or extra context for a passing check.",
"type": "string"
},
"ok": {
"description": "Whether the credential worked against this target.",
"type": "boolean"
},
"target": {
"description": "What was probed: an EU region/location for multi-region providers (AWS Bedrock), otherwise the provider host.",
"type": "string"
}
},
"required": [
"latency_ms",
"ok",
"target"
]
}
},
"provider": {
"description": "The provider slug that was tested.",
"type": "string"
},
"success": {
"description": "True when the credential works against at least one EU target.",
"type": "boolean"
}
},
"required": [
"checks",
"provider",
"success"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "testAByokProviderCredentialBeforeSavingIt"
}
}
```
## GET /api/v1/byok/usage
Get current BYOK subscription-period usage
Return successful request allowance, estimated upstream provider cost, and separate incurred, charged, and pending EUrouter platform-fee totals for the authenticated user's exact active subscription period.
```json
{
"operation": {
"summary": "Get current BYOK subscription-period usage",
"tags": [
"BYOK"
],
"description": "Return successful request allowance, estimated upstream provider cost, and separate incurred, charged, and pending EUrouter platform-fee totals for the authenticated user's exact active subscription period.",
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"period_start": {
"description": "Exact active subscription-period start.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"period_end": {
"description": "Exact active subscription-period end.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"successful_requests": {
"description": "Successful BYOK requests with an incurred allowance/fee allocation in this subscription period.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"settled_requests": {
"description": "Successful BYOK requests whose usage and ledger writes have settled. Null only while settlement schema data is unavailable.",
"nullable": true,
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"pending_settlement_requests": {
"description": "Successful BYOK requests still pending usage/ledger settlement. Null only while settlement schema data is unavailable.",
"nullable": true,
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"free_request_allowance": {
"description": "Successful requests carrying no EUrouter BYOK platform fee.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"allowance_used": {
"description": "Free requests consumed in this period.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"allowance_remaining": {
"description": "Free requests remaining in this period.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"chargeable_requests": {
"description": "Successful requests above the free allowance.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"estimated_upstream_cost_eur": {
"description": "Estimated provider cost in EUR; billed by the customer's provider, not EUrouter.",
"type": "string"
},
"eurouter_platform_fee_eur": {
"description": "EUrouter BYOK platform fees incurred in this period, including fees whose ledger settlement is pending.",
"type": "string"
},
"eurouter_platform_fee_charged_eur": {
"description": "EUrouter BYOK platform fees whose usage and ledger writes have settled. Null only while settlement schema data is unavailable.",
"nullable": true,
"type": "string"
},
"eurouter_platform_fee_pending_eur": {
"description": "Incurred EUrouter BYOK platform fees still pending usage/ledger settlement. Null only while settlement schema data is unavailable.",
"nullable": true,
"type": "string"
},
"platform_fee_rate": {
"description": "The plan's markup percentage represented as a decimal rate.",
"type": "string"
}
},
"required": [
"period_start",
"period_end",
"successful_requests",
"settled_requests",
"pending_settlement_requests",
"free_request_allowance",
"allowance_used",
"allowance_remaining",
"chargeable_requests",
"estimated_upstream_cost_eur",
"eurouter_platform_fee_eur",
"eurouter_platform_fee_charged_eur",
"eurouter_platform_fee_pending_eur",
"platform_fee_rate"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "getCurrentByokSubscriptionPeriodUsage"
}
}
```
## GET /api/v1/byok/{id}
Get BYOK provider credential
Get a personal bring-your-own-key (BYOK) provider credential owned by the authenticated Pro or Enterprise user.
```json
{
"operation": {
"summary": "Get BYOK provider credential",
"tags": [
"BYOK"
],
"description": "Get a personal bring-your-own-key (BYOK) provider credential owned by the authenticated Pro or Enterprise user.",
"parameters": [
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "id",
"required": true,
"description": "The BYOK credential ID (UUID)."
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "The BYOK provider credential",
"type": "object",
"properties": {
"allowed_api_key_hashes": {
"description": "Optional allowlist of EUrouter API key hashes (`api_keys.hash`) that may use this credential. `null` means no restriction.",
"nullable": true,
"type": "array",
"items": {
"type": "string"
}
},
"allowed_models": {
"description": "Optional allowlist of model slugs this credential may be used for. `null` means no restriction.",
"nullable": true,
"type": "array",
"items": {
"type": "string"
}
},
"always_use": {
"description": "Always use this credential for its provider: when true (on a non-fallback credential), EUrouter never falls back to its own shared endpoints for this provider — requests fail rather than silently running on EUrouter keys/billing.",
"type": "boolean"
},
"created_at": {
"description": "ISO timestamp of when the credential was created.",
"type": "string"
},
"disabled": {
"description": "Whether this credential is currently disabled.",
"type": "boolean"
},
"id": {
"description": "Stable public identifier for this BYOK credential.",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"is_fallback": {
"description": "Whether this credential is treated as a fallback - used only after non-fallback keys for the same provider have been tried.",
"type": "boolean"
},
"label": {
"description": "Short masked snippet of the key (e.g. the first/last few characters) used to identify it in the UI.",
"type": "string"
},
"last_used": {
"description": "ISO timestamp of the most recent provider attempt with this credential. `null` means it has not been used yet or tracking is not available.",
"nullable": true,
"type": "string"
},
"name": {
"description": "Optional human-readable name for the credential.",
"nullable": true,
"type": "string"
},
"provider": {
"description": "The upstream provider this credential authenticates against, as a lowercase slug (e.g. `openai`, `anthropic`, `aws-bedrock`).",
"type": "string"
},
"sort_order": {
"description": "Position within the provider - credentials are tried in ascending sort order.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"allowed_api_key_hashes",
"allowed_models",
"always_use",
"created_at",
"disabled",
"id",
"is_fallback",
"label",
"last_used",
"provider",
"sort_order"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "getByokProviderCredential"
}
}
```
## PATCH /api/v1/byok/{id}
Update BYOK provider credential
Update a personal bring-your-own-key (BYOK) provider credential owned by the authenticated Pro or Enterprise user. Include the key field to rotate the raw provider API key in-place (the previous key material is overwritten).
```json
{
"operation": {
"summary": "Update BYOK provider credential",
"tags": [
"BYOK"
],
"description": "Update a personal bring-your-own-key (BYOK) provider credential owned by the authenticated Pro or Enterprise user. Include the key field to rotate the raw provider API key in-place (the previous key material is overwritten).",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"allowed_api_key_hashes": {
"description": "Optional allowlist of EUrouter API key hashes (`api_keys.hash`) that may use this credential. `null` means no restriction.",
"nullable": true,
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
"allowed_models": {
"description": "Optional allowlist of model slugs this credential may be used for. `null` means no restriction.",
"nullable": true,
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
"always_use": {
"description": "Always use this credential for its provider, without falling back to EUrouter shared endpoints.",
"type": "boolean"
},
"disabled": {
"description": "Whether this credential is disabled.",
"type": "boolean"
},
"is_fallback": {
"description": "Whether this credential is treated as a fallback - used only after non-fallback keys for the same provider have been tried.",
"type": "boolean"
},
"name": {
"description": "Optional human-readable name for the credential.",
"nullable": true,
"type": "string",
"minLength": 1,
"maxLength": 255
},
"sort_order": {
"description": "Position within the provider. Credentials are tried in ascending sort order.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"key": {
"description": "A new raw provider credential to rotate in-place, in the same per-provider format the create endpoint accepts (plain key; AWS Bedrock key or credentials JSON; Microsoft Foundry `{\"api_key\",\"resource_name\"}`). Any `region` field is ignored — EUrouter forces the model's EU region. The previous key material is overwritten and the masked label is regenerated. Encrypted at rest and never returned in API responses.",
"type": "string",
"minLength": 1
}
}
}
}
}
},
"parameters": [
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "id",
"required": true,
"description": "The BYOK credential ID (UUID)."
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "The BYOK provider credential",
"type": "object",
"properties": {
"allowed_api_key_hashes": {
"description": "Optional allowlist of EUrouter API key hashes (`api_keys.hash`) that may use this credential. `null` means no restriction.",
"nullable": true,
"type": "array",
"items": {
"type": "string"
}
},
"allowed_models": {
"description": "Optional allowlist of model slugs this credential may be used for. `null` means no restriction.",
"nullable": true,
"type": "array",
"items": {
"type": "string"
}
},
"always_use": {
"description": "Always use this credential for its provider: when true (on a non-fallback credential), EUrouter never falls back to its own shared endpoints for this provider — requests fail rather than silently running on EUrouter keys/billing.",
"type": "boolean"
},
"created_at": {
"description": "ISO timestamp of when the credential was created.",
"type": "string"
},
"disabled": {
"description": "Whether this credential is currently disabled.",
"type": "boolean"
},
"id": {
"description": "Stable public identifier for this BYOK credential.",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"is_fallback": {
"description": "Whether this credential is treated as a fallback - used only after non-fallback keys for the same provider have been tried.",
"type": "boolean"
},
"label": {
"description": "Short masked snippet of the key (e.g. the first/last few characters) used to identify it in the UI.",
"type": "string"
},
"last_used": {
"description": "ISO timestamp of the most recent provider attempt with this credential. `null` means it has not been used yet or tracking is not available.",
"nullable": true,
"type": "string"
},
"name": {
"description": "Optional human-readable name for the credential.",
"nullable": true,
"type": "string"
},
"provider": {
"description": "The upstream provider this credential authenticates against, as a lowercase slug (e.g. `openai`, `anthropic`, `aws-bedrock`).",
"type": "string"
},
"sort_order": {
"description": "Position within the provider - credentials are tried in ascending sort order.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"allowed_api_key_hashes",
"allowed_models",
"always_use",
"created_at",
"disabled",
"id",
"is_fallback",
"label",
"last_used",
"provider",
"sort_order"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "updateByokProviderCredential"
}
}
```
## DELETE /api/v1/byok/{id}
Delete BYOK provider credential
Delete (soft-delete) a personal bring-your-own-key (BYOK) provider credential owned by the authenticated Pro or Enterprise user. The encrypted key material is wiped and the record is marked as deleted.
```json
{
"operation": {
"summary": "Delete BYOK provider credential",
"tags": [
"BYOK"
],
"description": "Delete (soft-delete) a personal bring-your-own-key (BYOK) provider credential owned by the authenticated Pro or Enterprise user. The encrypted key material is wiped and the record is marked as deleted.",
"parameters": [
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "id",
"required": true,
"description": "The BYOK credential ID (UUID)."
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"deleted": {
"description": "Confirmation that the BYOK credential was deleted.",
"type": "boolean",
"enum": [
true
]
}
},
"required": [
"deleted"
]
}
}
}
}
},
"operationId": "deleteByokProviderCredential"
}
}
```
## POST /api/v1/byok/{id}/test
Test a stored BYOK provider credential
Run the same live checks as POST /v1/byok/test against a personal stored credential owned by the authenticated Pro or Enterprise user. The raw key never appears in the response.
```json
{
"operation": {
"summary": "Test a stored BYOK provider credential",
"tags": [
"BYOK"
],
"description": "Run the same live checks as POST /v1/byok/test against a personal stored credential owned by the authenticated Pro or Enterprise user. The raw key never appears in the response.",
"parameters": [
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "id",
"required": true,
"description": "The BYOK credential ID (UUID)."
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"checks": {
"description": "Per-target results. Multi-region providers report one check per seeded EU region so region-locked keys show exactly where they work.",
"type": "array",
"items": {
"type": "object",
"properties": {
"latency_ms": {
"description": "Wall-clock duration of this check in milliseconds.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"message": {
"description": "Actionable detail — the upstream failure reason, or extra context for a passing check.",
"type": "string"
},
"ok": {
"description": "Whether the credential worked against this target.",
"type": "boolean"
},
"target": {
"description": "What was probed: an EU region/location for multi-region providers (AWS Bedrock), otherwise the provider host.",
"type": "string"
}
},
"required": [
"latency_ms",
"ok",
"target"
]
}
},
"provider": {
"description": "The provider slug that was tested.",
"type": "string"
},
"success": {
"description": "True when the credential works against at least one EU target.",
"type": "boolean"
}
},
"required": [
"checks",
"provider",
"success"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "testAStoredByokProviderCredential"
}
}
```
---
# Chat
> Chat completion endpoints
Source: https://www.eurouter.ai/docs/api/chat
## POST /api/v1/chat/completions
Create chat completion
Generate a chat completion using the specified model. Supports streaming, tool calling, vision, audio inputs, provider routing, and fallback.
```json
{
"operation": {
"summary": "Create chat completion",
"tags": [
"Chat"
],
"description": "Generate a chat completion using the specified model. Supports streaming, tool calling, vision, audio inputs, provider routing, and fallback.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"model": {
"description": "Model identifier (e.g., \"openai/gpt-4\")",
"type": "string"
},
"models": {
"description": "Fallback model list (not yet implemented)",
"type": "array",
"items": {
"type": "string"
}
},
"rule_id": {
"description": "Routing rule ID to apply",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"rule_name": {
"description": "Routing rule name to apply",
"type": "string"
},
"messages": {
"description": "Conversation messages",
"minItems": 1,
"type": "array",
"items": {
"description": "Chat message",
"anyOf": [
{
"type": "object",
"properties": {
"role": {
"description": "Message role",
"type": "string",
"enum": [
"system"
]
},
"content": {
"description": "System prompt content",
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"text"
]
},
"text": {
"description": "The text content",
"type": "string"
}
},
"required": [
"type",
"text"
]
}
}
]
},
"name": {
"description": "Optional name for the participant",
"type": "string"
}
},
"required": [
"role",
"content"
],
"additionalProperties": {}
},
{
"type": "object",
"properties": {
"role": {
"description": "Message role",
"type": "string",
"enum": [
"user"
]
},
"content": {
"description": "User message content (text, images, or audio)",
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"text"
]
},
"text": {
"description": "The text content",
"type": "string"
}
},
"required": [
"type",
"text"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"image_url"
]
},
"image_url": {
"type": "object",
"properties": {
"url": {
"description": "URL or base64 data URI of the image",
"type": "string"
},
"detail": {
"description": "Image detail level for vision models",
"type": "string",
"enum": [
"auto",
"low",
"high"
]
}
},
"required": [
"url"
]
}
},
"required": [
"type",
"image_url"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"input_audio"
]
},
"input_audio": {
"type": "object",
"properties": {
"data": {
"description": "Base64-encoded audio data",
"type": "string"
},
"format": {
"description": "Audio format",
"type": "string",
"enum": [
"wav",
"mp3",
"flac",
"m4a",
"ogg",
"pcm16",
"pcm24"
]
}
},
"required": [
"data",
"format"
]
}
},
"required": [
"type",
"input_audio"
]
}
]
}
}
]
},
"name": {
"description": "Optional name for the participant",
"type": "string"
}
},
"required": [
"role",
"content"
],
"additionalProperties": {}
},
{
"type": "object",
"properties": {
"role": {
"description": "Message role",
"type": "string",
"enum": [
"developer"
]
},
"content": {
"description": "Developer instruction content",
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"text"
]
},
"text": {
"description": "The text content",
"type": "string"
}
},
"required": [
"type",
"text"
]
}
}
]
},
"name": {
"description": "Optional name for the participant",
"type": "string"
}
},
"required": [
"role",
"content"
],
"additionalProperties": {}
},
{
"type": "object",
"properties": {
"role": {
"description": "Message role",
"type": "string",
"enum": [
"assistant"
]
},
"content": {
"description": "Assistant response content",
"anyOf": [
{
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"text"
]
},
"text": {
"description": "The text content",
"type": "string"
}
},
"required": [
"type",
"text"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"image_url"
]
},
"image_url": {
"type": "object",
"properties": {
"url": {
"description": "URL or base64 data URI of the image",
"type": "string"
},
"detail": {
"description": "Image detail level for vision models",
"type": "string",
"enum": [
"auto",
"low",
"high"
]
}
},
"required": [
"url"
]
}
},
"required": [
"type",
"image_url"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"input_audio"
]
},
"input_audio": {
"type": "object",
"properties": {
"data": {
"description": "Base64-encoded audio data",
"type": "string"
},
"format": {
"description": "Audio format",
"type": "string",
"enum": [
"wav",
"mp3",
"flac",
"m4a",
"ogg",
"pcm16",
"pcm24"
]
}
},
"required": [
"data",
"format"
]
}
},
"required": [
"type",
"input_audio"
]
}
]
}
}
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"name": {
"description": "Optional name for the participant",
"type": "string"
},
"tool_calls": {
"description": "Tool calls made by the assistant",
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"description": "Unique identifier for this tool call",
"type": "string"
},
"type": {
"description": "Tool call type",
"type": "string",
"enum": [
"function"
]
},
"index": {
"description": "Tool call index position",
"type": "number"
},
"function": {
"description": "Function call details",
"type": "object",
"properties": {
"name": {
"description": "Name of the function to call",
"type": "string"
},
"arguments": {
"description": "JSON-encoded function arguments",
"type": "string"
}
},
"required": [
"name",
"arguments"
]
}
},
"required": [
"id",
"type",
"function"
]
}
},
"refusal": {
"description": "Refusal message if the model declined",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"reasoning": {
"description": "Model reasoning (for reasoning models)",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"annotations": {
"description": "OpenAI annotations for assistant output",
"type": "array",
"items": {}
}
},
"required": [
"role"
],
"additionalProperties": {}
},
{
"type": "object",
"properties": {
"role": {
"description": "Message role",
"type": "string",
"enum": [
"tool"
]
},
"content": {
"description": "Tool response content",
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"text"
]
},
"text": {
"description": "The text content",
"type": "string"
}
},
"required": [
"type",
"text"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"image_url"
]
},
"image_url": {
"type": "object",
"properties": {
"url": {
"description": "URL or base64 data URI of the image",
"type": "string"
},
"detail": {
"description": "Image detail level for vision models",
"type": "string",
"enum": [
"auto",
"low",
"high"
]
}
},
"required": [
"url"
]
}
},
"required": [
"type",
"image_url"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"input_audio"
]
},
"input_audio": {
"type": "object",
"properties": {
"data": {
"description": "Base64-encoded audio data",
"type": "string"
},
"format": {
"description": "Audio format",
"type": "string",
"enum": [
"wav",
"mp3",
"flac",
"m4a",
"ogg",
"pcm16",
"pcm24"
]
}
},
"required": [
"data",
"format"
]
}
},
"required": [
"type",
"input_audio"
]
}
]
}
}
]
},
"tool_call_id": {
"description": "ID of the tool call this responds to",
"type": "string"
}
},
"required": [
"role",
"content",
"tool_call_id"
],
"additionalProperties": {}
}
]
}
},
"stream": {
"description": "Enable streaming responses",
"anyOf": [
{
"default": false,
"type": "boolean"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"stream_options": {
"description": "Streaming options",
"anyOf": [
{
"type": "object",
"properties": {
"include_usage": {
"description": "Include usage in final chunk",
"type": "boolean"
}
},
"required": [
"include_usage"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"max_tokens": {
"description": "Maximum tokens to generate (deprecated, use max_completion_tokens). When omitted, the provider default applies; providers that require a limit receive the selected endpoint's catalogued maximum",
"anyOf": [
{
"type": "number",
"minimum": 1
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"max_completion_tokens": {
"description": "Maximum tokens to generate. When omitted, the provider default applies; providers that require a limit receive the selected endpoint's catalogued maximum",
"anyOf": [
{
"type": "number",
"minimum": 1
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"temperature": {
"description": "Sampling temperature (0-2)",
"anyOf": [
{
"default": 1,
"type": "number",
"minimum": 0,
"maximum": 2
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"top_p": {
"description": "Nucleus sampling probability (0-1)",
"anyOf": [
{
"default": 1,
"type": "number",
"minimum": 0,
"maximum": 1
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"frequency_penalty": {
"description": "Frequency penalty (-2 to 2)",
"anyOf": [
{
"type": "number",
"minimum": -2,
"maximum": 2
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"presence_penalty": {
"description": "Presence penalty (-2 to 2)",
"anyOf": [
{
"type": "number",
"minimum": -2,
"maximum": 2
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"logit_bias": {
"description": "Token logit biases",
"anyOf": [
{
"type": "object",
"additionalProperties": {
"type": "number"
}
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"logprobs": {
"description": "Return log probabilities",
"anyOf": [
{
"type": "boolean"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"top_logprobs": {
"description": "Number of top logprobs to return (0-20)",
"anyOf": [
{
"type": "number",
"minimum": 0,
"maximum": 20
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"n": {
"description": "Number of chat completion choices to generate",
"anyOf": [
{
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"seed": {
"description": "Random seed for deterministic generation",
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"stop": {
"description": "Stop sequences",
"anyOf": [
{
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"reasoning": {
"description": "Reasoning parameters (for reasoning models)",
"type": "object",
"properties": {
"effort": {
"description": "How much effort to spend on reasoning",
"anyOf": [
{
"description": "Reasoning effort level",
"type": "string",
"enum": [
"none",
"minimal",
"low",
"medium",
"high",
"xhigh",
"max"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"summary": {
"description": "Verbosity of reasoning summary",
"anyOf": [
{
"description": "Reasoning summary verbosity",
"type": "string",
"enum": [
"auto",
"concise",
"detailed"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
}
}
},
"reasoning_effort": {
"description": "OpenAI-compatible shorthand for reasoning.effort",
"anyOf": [
{
"description": "Reasoning effort level",
"type": "string",
"enum": [
"none",
"minimal",
"low",
"medium",
"high",
"xhigh",
"max"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"include_reasoning": {
"description": "Include reasoning in response",
"type": "boolean"
},
"response_format": {
"description": "Response format specification",
"anyOf": [
{
"type": "object",
"properties": {
"type": {
"description": "Response format type",
"type": "string",
"enum": [
"text"
]
}
},
"required": [
"type"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Response format type",
"type": "string",
"enum": [
"json_object"
]
}
},
"required": [
"type"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Response format type",
"type": "string",
"enum": [
"json_schema"
]
},
"json_schema": {
"type": "object",
"properties": {
"name": {
"description": "Schema name (max 64 chars)",
"type": "string",
"maxLength": 64
},
"description": {
"description": "Schema description",
"type": "string"
},
"schema": {
"description": "JSON Schema definition",
"type": "object",
"additionalProperties": {}
},
"strict": {
"description": "Enable strict schema validation",
"anyOf": [
{
"type": "boolean"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
}
},
"required": [
"name"
]
}
},
"required": [
"type",
"json_schema"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Response format type",
"type": "string",
"enum": [
"grammar"
]
},
"grammar": {
"description": "GBNF grammar string",
"type": "string"
}
},
"required": [
"type",
"grammar"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Response format type",
"type": "string",
"enum": [
"python"
]
}
},
"required": [
"type"
]
}
]
},
"tool_choice": {
"description": "Tool calling behavior",
"anyOf": [
{
"description": "Do not call any tools",
"type": "string",
"enum": [
"none"
]
},
{
"description": "Model decides whether to call tools",
"type": "string",
"enum": [
"auto"
]
},
{
"description": "Model must call at least one tool",
"type": "string",
"enum": [
"required"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Tool choice type",
"type": "string",
"enum": [
"function"
]
},
"function": {
"type": "object",
"properties": {
"name": {
"description": "Name of the function to call",
"type": "string"
}
},
"required": [
"name"
]
}
},
"required": [
"type",
"function"
]
}
]
},
"tools": {
"description": "Available tools for the model",
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {
"description": "Tool type",
"type": "string",
"enum": [
"function"
]
},
"function": {
"description": "Function definition",
"type": "object",
"properties": {
"name": {
"description": "Function name (max 64 chars)",
"type": "string",
"maxLength": 64
},
"description": {
"description": "Description of what the function does",
"type": "string"
},
"parameters": {
"description": "JSON Schema for function parameters",
"type": "object",
"additionalProperties": {}
},
"strict": {
"description": "Enable strict schema validation",
"anyOf": [
{
"type": "boolean"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
}
},
"required": [
"name",
"parameters"
]
}
},
"required": [
"type",
"function"
]
}
},
"user": {
"description": "End-user identifier for abuse detection",
"type": "string"
},
"store": {
"description": "Whether to store the conversation for later retrieval",
"nullable": true,
"type": "boolean"
},
"metadata": {
"description": "Custom metadata for the request",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"plugins": {
"description": "Optional plugins (e.g. { id: \"response-healing\", enabled?: boolean })",
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"enabled": {
"type": "boolean"
}
},
"required": [
"id"
],
"additionalProperties": {}
}
},
"provider": {
"description": "Provider routing preferences",
"type": "object",
"properties": {
"order": {
"description": "Provider priority order - try these first, in order",
"type": "array",
"items": {
"type": "string"
}
},
"ignore": {
"description": "Providers to exclude from routing",
"type": "array",
"items": {
"type": "string"
}
},
"only": {
"description": "Only use these providers (exclusive list)",
"type": "array",
"items": {
"type": "string"
}
},
"allow_fallbacks": {
"description": "Allow fallback to other providers on failure (default: true)",
"type": "boolean"
},
"sort": {
"description": "Sort strategy: price (cheapest), latency (fastest), throughput (highest tokens/s)",
"type": "string",
"enum": [
"price",
"latency",
"throughput"
]
},
"require_parameters": {
"description": "Only use providers that support all request parameters",
"type": "boolean"
},
"quantizations": {
"description": "Filter by model quantization levels",
"type": "array",
"items": {
"description": "Model quantization level",
"type": "string",
"enum": [
"int4",
"int8",
"fp4",
"fp6",
"fp8",
"fp16",
"bf16",
"fp32"
]
}
},
"data_collection": {
"description": "Filter providers by data collection policy",
"type": "string",
"enum": [
"allow",
"deny"
]
},
"data_residency": {
"description": "Filter endpoints by geographic data processing region",
"type": "string",
"minLength": 2,
"maxLength": 10
},
"max_retention_days": {
"description": "Maximum data retention period in days (0 = ZDR only)",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"eu_owned": {
"description": "Only use EU-headquartered providers",
"type": "boolean"
}
}
},
"trace": {
"description": "Trace context for Broadcast observability",
"type": "object",
"properties": {
"trace_id": {
"description": "Groups multiple requests into a single trace",
"type": "string"
},
"trace_name": {
"description": "Custom name for the root trace",
"type": "string"
},
"span_name": {
"description": "Creates a parent span grouping LLM operations",
"type": "string"
},
"generation_name": {
"description": "Names the specific LLM generation span",
"type": "string"
},
"parent_span_id": {
"description": "Links to an existing external span in your trace hierarchy",
"type": "string"
}
},
"additionalProperties": {}
},
"session_id": {
"description": "Session identifier for grouping related requests",
"type": "string",
"maxLength": 128
}
},
"required": [
"messages"
],
"additionalProperties": {}
},
"example": {
"model": "mistral-large-3",
"messages": [
{
"role": "user",
"content": "Hello!"
}
]
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"description": "Unique completion identifier",
"type": "string"
},
"provider": {
"description": "Provider that served the request",
"type": "string"
},
"object": {
"description": "Object type",
"type": "string",
"enum": [
"chat.completion"
]
},
"created": {
"description": "Unix timestamp of creation",
"type": "number"
},
"model": {
"description": "Model used for completion",
"type": "string"
},
"service_tier": {
"description": "Service tier used",
"type": "string"
},
"system_fingerprint": {
"description": "System fingerprint for reproducibility",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"choices": {
"description": "Completion choices",
"type": "array",
"items": {
"type": "object",
"properties": {
"index": {
"description": "Choice index",
"type": "number"
},
"message": {
"description": "The assistant message",
"type": "object",
"properties": {
"role": {
"description": "Message role",
"type": "string",
"enum": [
"assistant"
]
},
"content": {
"description": "Assistant response content",
"anyOf": [
{
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"text"
]
},
"text": {
"description": "The text content",
"type": "string"
}
},
"required": [
"type",
"text"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"image_url"
]
},
"image_url": {
"type": "object",
"properties": {
"url": {
"description": "URL or base64 data URI of the image",
"type": "string"
},
"detail": {
"description": "Image detail level for vision models",
"type": "string",
"enum": [
"auto",
"low",
"high"
]
}
},
"required": [
"url"
]
}
},
"required": [
"type",
"image_url"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"input_audio"
]
},
"input_audio": {
"type": "object",
"properties": {
"data": {
"description": "Base64-encoded audio data",
"type": "string"
},
"format": {
"description": "Audio format",
"type": "string",
"enum": [
"wav",
"mp3",
"flac",
"m4a",
"ogg",
"pcm16",
"pcm24"
]
}
},
"required": [
"data",
"format"
]
}
},
"required": [
"type",
"input_audio"
]
}
]
}
}
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"name": {
"description": "Optional name for the participant",
"type": "string"
},
"tool_calls": {
"description": "Tool calls made by the assistant",
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"description": "Unique identifier for this tool call",
"type": "string"
},
"type": {
"description": "Tool call type",
"type": "string",
"enum": [
"function"
]
},
"index": {
"description": "Tool call index position",
"type": "number"
},
"function": {
"description": "Function call details",
"type": "object",
"properties": {
"name": {
"description": "Name of the function to call",
"type": "string"
},
"arguments": {
"description": "JSON-encoded function arguments",
"type": "string"
}
},
"required": [
"name",
"arguments"
]
}
},
"required": [
"id",
"type",
"function"
]
}
},
"refusal": {
"description": "Refusal message if the model declined",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"reasoning": {
"description": "Model reasoning (for reasoning models)",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"annotations": {
"description": "OpenAI annotations for assistant output",
"type": "array",
"items": {}
}
},
"required": [
"role"
],
"additionalProperties": {}
},
"finish_reason": {
"description": "Why the model stopped",
"anyOf": [
{
"description": "Reason the model stopped generating",
"type": "string",
"enum": [
"tool_calls",
"stop",
"length",
"content_filter",
"error"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"native_finish_reason": {
"description": "Raw finish reason from the upstream provider",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"logprobs": {
"description": "Token log probabilities",
"anyOf": [
{
"type": "object",
"properties": {
"content": {
"description": "Logprobs for content tokens",
"anyOf": [
{
"type": "array",
"items": {
"type": "object",
"properties": {
"token": {
"description": "The token",
"type": "string"
},
"logprob": {
"description": "Log probability of the token",
"type": "number"
},
"bytes": {
"description": "UTF-8 bytes of the token",
"anyOf": [
{
"type": "array",
"items": {
"type": "number"
}
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"top_logprobs": {
"description": "Top alternative tokens",
"type": "array",
"items": {
"type": "object",
"properties": {
"token": {
"description": "The token",
"type": "string"
},
"logprob": {
"description": "Log probability of the token",
"type": "number"
},
"bytes": {
"description": "UTF-8 bytes of the token",
"anyOf": [
{
"type": "array",
"items": {
"type": "number"
}
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
}
},
"required": [
"token",
"logprob",
"bytes"
]
}
}
},
"required": [
"token",
"logprob",
"bytes",
"top_logprobs"
]
}
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"refusal": {
"description": "Logprobs for refusal tokens",
"anyOf": [
{
"type": "array",
"items": {
"type": "object",
"properties": {
"token": {
"description": "The token",
"type": "string"
},
"logprob": {
"description": "Log probability of the token",
"type": "number"
},
"bytes": {
"description": "UTF-8 bytes of the token",
"anyOf": [
{
"type": "array",
"items": {
"type": "number"
}
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"top_logprobs": {
"description": "Top alternative tokens",
"type": "array",
"items": {
"type": "object",
"properties": {
"token": {
"description": "The token",
"type": "string"
},
"logprob": {
"description": "Log probability of the token",
"type": "number"
},
"bytes": {
"description": "UTF-8 bytes of the token",
"anyOf": [
{
"type": "array",
"items": {
"type": "number"
}
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
}
},
"required": [
"token",
"logprob",
"bytes"
]
}
}
},
"required": [
"token",
"logprob",
"bytes",
"top_logprobs"
]
}
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
}
},
"required": [
"content",
"refusal"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
}
},
"required": [
"index",
"message",
"finish_reason"
]
}
},
"usage": {
"description": "Token usage statistics",
"type": "object",
"properties": {
"completion_tokens": {
"description": "Tokens in the completion",
"type": "number"
},
"prompt_tokens": {
"description": "Tokens in the prompt",
"type": "number"
},
"total_tokens": {
"description": "Total tokens used",
"type": "number"
},
"completion_tokens_details": {
"description": "Completion token breakdown",
"type": "object",
"properties": {
"reasoning_tokens": {
"description": "Tokens used for reasoning",
"type": "number"
},
"audio_tokens": {
"description": "Tokens used for audio output",
"type": "number"
},
"accepted_prediction_tokens": {
"description": "Accepted speculative tokens",
"type": "number"
},
"rejected_prediction_tokens": {
"description": "Rejected speculative tokens",
"type": "number"
},
"image_tokens": {
"description": "Tokens used for image output",
"type": "number"
}
},
"additionalProperties": {}
},
"prompt_tokens_details": {
"description": "Prompt token breakdown",
"type": "object",
"properties": {
"cached_tokens": {
"description": "Tokens served from cache",
"type": "number"
},
"audio_tokens": {
"description": "Tokens from audio input",
"type": "number"
},
"cache_write_tokens": {
"description": "Tokens written to prompt cache",
"type": "number"
},
"video_tokens": {
"description": "Tokens from video input",
"type": "number"
}
},
"additionalProperties": {}
},
"cost": {
"description": "Total request cost in native currency",
"type": "number"
},
"cost_currency": {
"description": "Currency of `cost` — the serving endpoint's native pricing currency",
"type": "string",
"enum": [
"USD",
"EUR"
]
},
"cost_eur": {
"description": "Cost converted to EUR — the amount debited from the account balance",
"type": "number"
},
"is_byok": {
"description": "Whether request used bring-your-own-key",
"type": "boolean"
},
"cost_details": {
"description": "Detailed cost breakdown",
"type": "object",
"properties": {
"upstream_inference_cost": {
"description": "Total upstream inference cost",
"type": "number"
},
"upstream_inference_prompt_cost": {
"description": "Upstream cost for prompt tokens",
"type": "number"
},
"upstream_inference_completions_cost": {
"description": "Upstream cost for completion tokens",
"type": "number"
}
},
"additionalProperties": {}
}
},
"required": [
"completion_tokens",
"prompt_tokens",
"total_tokens"
],
"additionalProperties": {}
}
},
"required": [
"id",
"object",
"created",
"model",
"choices",
"usage"
]
}
}
}
}
},
"operationId": "createChatCompletion"
}
}
```
---
# Completions
> Text completion endpoints
Source: https://www.eurouter.ai/docs/api/completions
## POST /api/v1/completions
Create text completion
Generate a text completion using the specified model. Supports streaming and fallback routing.
```json
{
"operation": {
"summary": "Create text completion",
"tags": [
"Completions"
],
"description": "Generate a text completion using the specified model. Supports streaming and fallback routing.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"model": {
"description": "Model identifier (e.g., \"openai/gpt-3.5-turbo-instruct\")",
"type": "string"
},
"prompt": {
"description": "The prompt to generate completions for. Supports strings, batches of strings, token arrays, and batches of token arrays.",
"anyOf": [
{
"type": "string"
},
{
"minItems": 1,
"type": "array",
"items": {
"type": "string"
}
},
{
"minItems": 1,
"type": "array",
"items": {
"type": "number"
}
},
{
"minItems": 1,
"type": "array",
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "number"
}
}
}
]
},
"models": {
"description": "Fallback model list (not yet implemented)",
"type": "array",
"items": {
"type": "string"
}
},
"provider": {
"description": "Provider routing preferences",
"type": "object",
"properties": {
"order": {
"description": "Provider priority order - try these first, in order",
"type": "array",
"items": {
"type": "string"
}
},
"ignore": {
"description": "Providers to exclude from routing",
"type": "array",
"items": {
"type": "string"
}
},
"only": {
"description": "Only use these providers (exclusive list)",
"type": "array",
"items": {
"type": "string"
}
},
"allow_fallbacks": {
"description": "Allow fallback to other providers on failure (default: true)",
"type": "boolean"
},
"sort": {
"description": "Sort strategy: price (cheapest), latency (fastest), throughput (highest tokens/s)",
"type": "string",
"enum": [
"price",
"latency",
"throughput"
]
},
"require_parameters": {
"description": "Only use providers that support all request parameters",
"type": "boolean"
},
"quantizations": {
"description": "Filter by model quantization levels",
"type": "array",
"items": {
"description": "Model quantization level",
"type": "string",
"enum": [
"int4",
"int8",
"fp4",
"fp6",
"fp8",
"fp16",
"bf16",
"fp32"
]
}
},
"data_collection": {
"description": "Filter providers by data collection policy",
"type": "string",
"enum": [
"allow",
"deny"
]
},
"data_residency": {
"description": "Filter endpoints by geographic data processing region",
"type": "string",
"minLength": 2,
"maxLength": 10
},
"max_retention_days": {
"description": "Maximum data retention period in days (0 = ZDR only)",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"eu_owned": {
"description": "Only use EU-headquartered providers",
"type": "boolean"
}
}
},
"reasoning": {
"description": "Reasoning parameters (for reasoning models)",
"type": "object",
"properties": {
"effort": {
"description": "How much effort to spend on reasoning",
"anyOf": [
{
"description": "Reasoning effort level",
"type": "string",
"enum": [
"none",
"minimal",
"low",
"medium",
"high",
"xhigh",
"max"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
}
}
},
"reasoning_effort": {
"description": "OpenAI-compatible shorthand for reasoning.effort",
"anyOf": [
{
"description": "Reasoning effort level",
"type": "string",
"enum": [
"none",
"minimal",
"low",
"medium",
"high",
"xhigh",
"max"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"transforms": {
"description": "Prompt transforms to apply",
"type": "array",
"items": {
"type": "string"
}
},
"stream": {
"description": "Enable streaming responses",
"anyOf": [
{
"default": false,
"type": "boolean"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"max_tokens": {
"description": "Maximum tokens to generate. When omitted, the provider default applies; providers that require a limit receive the selected endpoint's catalogued maximum",
"anyOf": [
{
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"temperature": {
"description": "Sampling temperature (0-2)",
"anyOf": [
{
"default": 1,
"type": "number",
"minimum": 0,
"maximum": 2
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"seed": {
"description": "Random seed for deterministic generation",
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"top_p": {
"description": "Nucleus sampling probability (0-1)",
"anyOf": [
{
"default": 1,
"type": "number",
"minimum": 0,
"maximum": 1
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"top_k": {
"description": "Top-k sampling (0 = disabled)",
"anyOf": [
{
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"frequency_penalty": {
"description": "Frequency penalty (-2 to 2)",
"anyOf": [
{
"type": "number",
"minimum": -2,
"maximum": 2
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"presence_penalty": {
"description": "Presence penalty (-2 to 2)",
"anyOf": [
{
"type": "number",
"minimum": -2,
"maximum": 2
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"repetition_penalty": {
"description": "Repetition penalty multiplier",
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"stop": {
"description": "Stop sequences",
"anyOf": [
{
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"logit_bias": {
"description": "Token logit biases",
"anyOf": [
{
"type": "object",
"additionalProperties": {
"type": "number"
}
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"logprobs": {
"description": "Number of logprobs to return (0-5)",
"anyOf": [
{
"type": "integer",
"minimum": 0,
"maximum": 5
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"top_logprobs": {
"description": "Number of top logprobs to return (0-20)",
"anyOf": [
{
"type": "integer",
"minimum": 0,
"maximum": 20
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"min_p": {
"description": "Minimum probability threshold (0-1)",
"anyOf": [
{
"type": "number",
"minimum": 0,
"maximum": 1
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"top_a": {
"description": "Top-a sampling parameter (0-1)",
"anyOf": [
{
"type": "number",
"minimum": 0,
"maximum": 1
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"user": {
"description": "End-user identifier for abuse detection",
"type": "string"
},
"trace": {
"description": "Trace context for Broadcast observability",
"type": "object",
"properties": {
"trace_id": {
"description": "Groups multiple requests into a single trace",
"type": "string"
},
"trace_name": {
"description": "Custom name for the root trace",
"type": "string"
},
"span_name": {
"description": "Creates a parent span grouping LLM operations",
"type": "string"
},
"generation_name": {
"description": "Names the specific LLM generation span",
"type": "string"
},
"parent_span_id": {
"description": "Links to an existing external span in your trace hierarchy",
"type": "string"
}
},
"additionalProperties": {}
},
"session_id": {
"description": "Session identifier for grouping related requests",
"type": "string",
"maxLength": 128
}
},
"required": [
"model",
"prompt"
],
"additionalProperties": {}
},
"example": {
"model": "mistral-large-3",
"prompt": "Write a short greeting."
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"description": "Unique completion identifier",
"type": "string"
},
"object": {
"description": "Object type",
"type": "string",
"enum": [
"text_completion"
]
},
"created": {
"description": "Unix timestamp of creation",
"type": "number"
},
"model": {
"description": "Model used for completion",
"type": "string"
},
"provider": {
"description": "Provider that served the request",
"type": "string"
},
"system_fingerprint": {
"description": "System fingerprint for reproducibility",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"choices": {
"description": "Completion choices",
"type": "array",
"items": {
"type": "object",
"properties": {
"text": {
"description": "Generated text",
"type": "string"
},
"index": {
"description": "Choice index",
"type": "number"
},
"finish_reason": {
"description": "Reason the model stopped",
"anyOf": [
{
"description": "Reason the model stopped generating",
"type": "string",
"enum": [
"stop",
"length",
"content_filter",
"tool_calls",
"error"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"native_finish_reason": {
"description": "Raw finish reason from upstream provider",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"logprobs": {
"description": "Token log probabilities",
"anyOf": [
{
"type": "object",
"properties": {
"tokens": {
"description": "Generated tokens",
"type": "array",
"items": {
"type": "string"
}
},
"token_logprobs": {
"description": "Log probabilities for each token",
"type": "array",
"items": {
"type": "number"
}
},
"top_logprobs": {
"description": "Top alternatives for each token",
"anyOf": [
{
"type": "array",
"items": {
"type": "object",
"additionalProperties": {
"type": "number"
}
}
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"text_offset": {
"description": "Character offset for each token",
"type": "array",
"items": {
"type": "number"
}
}
},
"required": [
"tokens",
"token_logprobs",
"top_logprobs",
"text_offset"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"reasoning": {
"description": "Reasoning output (for reasoning models)",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
}
},
"required": [
"text",
"index",
"finish_reason"
]
}
},
"usage": {
"description": "Token usage statistics",
"type": "object",
"properties": {
"prompt_tokens": {
"description": "Tokens in the prompt",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"completion_tokens": {
"description": "Tokens in the completion",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"total_tokens": {
"description": "Total tokens used",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"cost": {
"description": "Total request cost",
"type": "number"
},
"cost_currency": {
"description": "Currency of `cost` — the serving endpoint's native pricing currency",
"type": "string",
"enum": [
"USD",
"EUR"
]
},
"cost_eur": {
"description": "Cost converted to EUR — the amount debited from the account balance",
"type": "number"
},
"is_byok": {
"description": "Whether the request used a BYOK key",
"type": "boolean"
},
"prompt_tokens_details": {
"description": "Details about prompt tokens",
"type": "object",
"properties": {
"cached_tokens": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"audio_tokens": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"additionalProperties": {}
},
"completion_tokens_details": {
"description": "Details about completion tokens",
"type": "object",
"properties": {
"cached_tokens": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"audio_tokens": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"additionalProperties": {}
},
"cost_details": {
"description": "Breakdown of costs",
"type": "object",
"properties": {
"upstream_inference_cost": {
"type": "number"
},
"upstream_inference_prompt_cost": {
"type": "number"
},
"upstream_inference_completions_cost": {
"type": "number"
}
}
}
},
"required": [
"prompt_tokens",
"completion_tokens",
"total_tokens"
]
}
},
"required": [
"id",
"object",
"created",
"model",
"choices"
]
}
}
}
}
},
"operationId": "createTextCompletion"
}
}
```
---
# Credits
> Account balance and credits
Source: https://www.eurouter.ai/docs/api/credits
## GET /api/v1/credits
Get credits
Get total credits purchased and used for the authenticated user.
```json
{
"operation": {
"summary": "Get credits",
"tags": [
"Credits"
],
"description": "Get total credits purchased and used for the authenticated user.",
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"total_credits": {
"description": "Total credits purchased/added (in EUR)",
"type": "string"
},
"total_usage": {
"description": "Total credits consumed (in EUR)",
"type": "string"
}
},
"required": [
"total_credits",
"total_usage"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "getCredits"
}
}
```
---
# Embeddings
> API reference for Embeddings
Source: https://www.eurouter.ai/docs/api/embeddings
## POST /api/v1/embeddings
Create embeddings
Generate embeddings for the given input text. Supports a single string or an array of strings. Returns embedding vectors suitable for semantic search, clustering, and other ML applications.
```json
{
"operation": {
"summary": "Create embeddings",
"tags": [
"Embeddings"
],
"description": "Generate embeddings for the given input text. Supports a single string or an array of strings. Returns embedding vectors suitable for semantic search, clustering, and other ML applications.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"model": {
"description": "Model identifier (e.g., \"openai/text-embedding-3-small\")",
"type": "string",
"minLength": 1
},
"input": {
"description": "Input text or token arrays to embed. Can be a single string, array of strings, token array, or array of token arrays.",
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
{
"minItems": 1,
"type": "array",
"items": {
"type": "number"
}
},
{
"minItems": 1,
"type": "array",
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "number"
}
}
}
]
},
"encoding_format": {
"description": "The format to return the embeddings in. Default: float",
"default": "float",
"type": "string",
"enum": [
"float",
"base64"
]
},
"dimensions": {
"description": "The number of dimensions for the output embeddings. Only supported by some models.",
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
"user": {
"description": "End-user identifier for abuse detection",
"type": "string"
},
"provider": {
"description": "Provider routing preferences",
"type": "object",
"properties": {
"order": {
"description": "Provider priority order - try these first, in order",
"type": "array",
"items": {
"type": "string"
}
},
"ignore": {
"description": "Providers to exclude from routing",
"type": "array",
"items": {
"type": "string"
}
},
"only": {
"description": "Only use these providers (exclusive list)",
"type": "array",
"items": {
"type": "string"
}
},
"allow_fallbacks": {
"description": "Allow fallback to other providers on failure (default: true)",
"type": "boolean"
},
"sort": {
"description": "Sort strategy: price (cheapest), latency (fastest), throughput (highest tokens/s)",
"type": "string",
"enum": [
"price",
"latency",
"throughput"
]
},
"require_parameters": {
"description": "Only use providers that support all request parameters",
"type": "boolean"
},
"quantizations": {
"description": "Filter by model quantization levels",
"type": "array",
"items": {
"description": "Model quantization level",
"type": "string",
"enum": [
"int4",
"int8",
"fp4",
"fp6",
"fp8",
"fp16",
"bf16",
"fp32"
]
}
},
"data_collection": {
"description": "Filter providers by data collection policy",
"type": "string",
"enum": [
"allow",
"deny"
]
},
"data_residency": {
"description": "Filter endpoints by geographic data processing region",
"type": "string",
"minLength": 2,
"maxLength": 10
},
"max_retention_days": {
"description": "Maximum data retention period in days (0 = ZDR only)",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"eu_owned": {
"description": "Only use EU-headquartered providers",
"type": "boolean"
}
}
},
"trace": {
"description": "Trace context for Broadcast observability",
"type": "object",
"properties": {
"trace_id": {
"description": "Groups multiple requests into a single trace",
"type": "string"
},
"trace_name": {
"description": "Custom name for the root trace",
"type": "string"
},
"span_name": {
"description": "Creates a parent span grouping LLM operations",
"type": "string"
},
"generation_name": {
"description": "Names the specific LLM generation span",
"type": "string"
},
"parent_span_id": {
"description": "Links to an existing external span in your trace hierarchy",
"type": "string"
}
},
"additionalProperties": {}
},
"session_id": {
"description": "Session identifier for grouping related requests",
"type": "string",
"maxLength": 128
}
},
"required": [
"model",
"input",
"encoding_format"
],
"additionalProperties": {}
},
"example": {
"model": "bge-m3",
"input": "European AI infrastructure"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"description": "Unique request identifier",
"type": "string"
},
"object": {
"description": "Object type",
"type": "string",
"enum": [
"list"
]
},
"data": {
"description": "List of embedding objects",
"type": "array",
"items": {
"type": "object",
"properties": {
"object": {
"description": "Object type",
"type": "string",
"enum": [
"embedding"
]
},
"embedding": {
"description": "The embedding vector (float array) or base64 string",
"anyOf": [
{
"type": "array",
"items": {
"type": "number"
}
},
{
"type": "string"
}
]
},
"index": {
"description": "Index of the embedding in the input array",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"object",
"embedding",
"index"
]
}
},
"model": {
"description": "Model used for the embeddings",
"type": "string"
},
"usage": {
"description": "Token usage statistics",
"type": "object",
"properties": {
"prompt_tokens": {
"description": "Number of tokens in the input",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"total_tokens": {
"description": "Total tokens used (same as prompt_tokens for embeddings)",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"cost": {
"description": "Total request cost in native currency",
"type": "number"
},
"cost_currency": {
"description": "Currency of `cost` — the serving endpoint's native pricing currency",
"type": "string",
"enum": [
"USD",
"EUR"
]
},
"cost_eur": {
"description": "Cost converted to EUR — the amount debited from the account balance",
"type": "number"
},
"is_byok": {
"description": "Whether the request used a user-supplied provider key",
"type": "boolean"
},
"cost_details": {
"description": "Detailed upstream inference cost breakdown",
"type": "object",
"properties": {
"upstream_inference_cost": {
"type": "number"
},
"upstream_inference_prompt_cost": {
"type": "number"
},
"upstream_inference_completions_cost": {
"type": "number"
}
},
"required": [
"upstream_inference_cost",
"upstream_inference_prompt_cost",
"upstream_inference_completions_cost"
]
}
},
"required": [
"prompt_tokens",
"total_tokens"
]
},
"provider": {
"description": "Provider that served the request",
"type": "string"
}
},
"required": [
"object",
"data",
"model",
"usage"
]
}
}
}
}
},
"operationId": "createEmbeddings"
}
}
```
---
# Generation
> Per-request usage and cost lookup
Source: https://www.eurouter.ai/docs/api/generation
## GET /api/v1/generation
Get generation
Look up the recorded usage and cost of a single request by its id — the `x-request-id` response header returned by the original request. Usage is recorded asynchronously after the response is flushed, so a lookup made immediately after a request may return 404 for a short period; retry after a moment. Only requests you made are visible; anything else returns 404.
```json
{
"operation": {
"summary": "Get generation",
"tags": [
"Generation"
],
"description": "Look up the recorded usage and cost of a single request by its id — the `x-request-id` response header returned by the original request. Usage is recorded asynchronously after the response is flushed, so a lookup made immediately after a request may return 404 for a short period; retry after a moment. Only requests you made are visible; anything else returns 404.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "query",
"name": "id",
"required": true,
"description": "The request id — the `x-request-id` response header of the original request"
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"id": {
"description": "The request id — the `x-request-id` header returned by the original request",
"type": "string"
},
"created_at": {
"description": "ISO 8601 timestamp of when the usage was recorded",
"type": "string"
},
"request_method": {
"description": "The endpoint that produced this generation, e.g. `chat.completions` or `audio.speech`",
"nullable": true,
"type": "string"
},
"model": {
"description": "Model slug that served the request",
"nullable": true,
"type": "string"
},
"provider": {
"description": "Slug of the upstream provider that served the request",
"nullable": true,
"type": "string"
},
"status": {
"description": "Outcome of the request",
"type": "string",
"enum": [
"success",
"error"
]
},
"usage": {
"description": "Billable units recorded for the request. Which fields are non-zero depends on `request_method`.",
"type": "object",
"properties": {
"tokens_in": {
"description": "Prompt tokens billed",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"tokens_out": {
"description": "Completion tokens billed",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"audio_in_seconds": {
"description": "Seconds of input audio billed (speech-to-text)",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"audio_out_seconds": {
"description": "Seconds of output audio billed (text-to-speech)",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"characters": {
"description": "Input characters billed (text-to-speech)",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"tokens_in",
"tokens_out",
"audio_in_seconds",
"audio_out_seconds",
"characters"
]
},
"cost_eur": {
"description": "Amount charged to your EUrouter account, in EUR",
"type": "string"
},
"cost_native": {
"description": "Cost in the provider’s native currency (null for BYOK requests)",
"nullable": true,
"type": "string"
},
"native_currency": {
"description": "Currency code for `cost_native` (null for BYOK requests)",
"nullable": true,
"type": "string"
},
"exchange_rate": {
"description": "Native-to-EUR rate applied to `cost_native` (null for BYOK requests)",
"nullable": true,
"type": "string"
},
"is_byok": {
"description": "Whether the request used your own provider credentials (BYOK). When true, `cost_eur` is the EUrouter platform fee only — the provider billed you directly for the inference.",
"type": "boolean"
},
"latency_ms": {
"description": "End-to-end request latency in milliseconds",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"error_category": {
"description": "Why the request failed — one of `provider_error`, `timeout`, `rate_limit`, `content_filter`, `invalid_request`, `auth_error`. Null when `status` is `success`.",
"nullable": true,
"type": "string"
},
"error_status_code": {
"description": "HTTP status returned for a failed request. Null when `status` is `success`.",
"nullable": true,
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"id",
"created_at",
"request_method",
"model",
"provider",
"status",
"usage",
"cost_eur",
"cost_native",
"native_currency",
"exchange_rate",
"is_byok",
"latency_ms",
"error_category",
"error_status_code"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "getGeneration"
}
}
```
---
# Keys
> API key management
Source: https://www.eurouter.ai/docs/api/keys
## GET /api/v1/keys
List API keys
Retrieve the API keys associated with your account. Organization admins see all of the organization’s keys; members see their own.
```json
{
"operation": {
"summary": "List API keys",
"tags": [
"Keys"
],
"description": "Retrieve the API keys associated with your account. Organization admins see all of the organization’s keys; members see their own.",
"parameters": [
{
"schema": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"in": "query",
"name": "offset",
"required": false,
"description": "Number of keys to skip for pagination"
},
{
"schema": {
"type": "boolean"
},
"in": "query",
"name": "include_disabled",
"required": false,
"description": "Whether to include disabled keys in the response"
},
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "query",
"name": "workspace_id",
"required": false,
"description": "Filter API keys by workspace ID. Omit to list all accessible keys; when set, account-wide (unscoped) keys are also included."
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "List of API keys",
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"description": "Display name for the API key",
"type": "string"
},
"label": {
"description": "Human-readable label (defaults to hash if not set)",
"type": "string"
},
"type": {
"description": "Key type: `inference` keys call the model endpoints; `management` keys manage resources but cannot call inference endpoints",
"type": "string",
"enum": [
"inference",
"management"
]
},
"limit": {
"description": "Usage limit in credits (null = unlimited)",
"nullable": true,
"type": "number"
},
"limit_remaining": {
"description": "Remaining credits until limit is reached",
"nullable": true,
"type": "number"
},
"limit_reset": {
"description": "Period after which usage limits reset",
"nullable": true,
"type": "string",
"enum": [
"daily",
"weekly",
"monthly",
null
]
},
"include_byok_in_limit": {
"description": "Whether BYOK platform fees count toward this key’s usage limit",
"type": "boolean"
},
"usage": {
"description": "Total credits used (all time)",
"type": "number"
},
"usage_daily": {
"description": "Credits used today",
"type": "number"
},
"usage_weekly": {
"description": "Credits used this week",
"type": "number"
},
"usage_monthly": {
"description": "Credits used this month",
"type": "number"
},
"byok_usage": {
"description": "Total BYOK platform fees recorded for this key",
"type": "number"
},
"byok_usage_daily": {
"description": "BYOK platform fees recorded today",
"type": "number"
},
"byok_usage_weekly": {
"description": "BYOK platform fees recorded this week",
"type": "number"
},
"byok_usage_monthly": {
"description": "BYOK platform fees recorded this month",
"type": "number"
},
"disabled": {
"description": "Whether the key is disabled",
"type": "boolean"
},
"created_at": {
"description": "ISO 8601 timestamp of when the key was created",
"type": "string"
},
"updated_at": {
"description": "ISO 8601 timestamp of when the key was last updated",
"type": "string"
},
"last_used": {
"description": "ISO 8601 timestamp of when the key was last used (null if never used)",
"nullable": true,
"type": "string"
},
"hash": {
"description": "Public identifier for the key (used in URLs)",
"type": "string"
},
"org_id": {
"description": "Organization that owns the key (null for personal keys)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"workspace_id": {
"description": "Workspace this key is bound to (null for personal or legacy unscoped keys)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"created_by_user_id": {
"description": "User who created the key (null for legacy keys created before attribution)",
"nullable": true,
"type": "string"
},
"default_routing_rule_id": {
"description": "Routing rule applied to requests from this key that do not name one (null = no default)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
}
},
"required": [
"name",
"label",
"type",
"limit",
"limit_remaining",
"limit_reset",
"include_byok_in_limit",
"usage",
"usage_daily",
"usage_weekly",
"usage_monthly",
"byok_usage",
"byok_usage_daily",
"byok_usage_weekly",
"byok_usage_monthly",
"disabled",
"created_at",
"updated_at",
"last_used",
"hash",
"org_id",
"workspace_id",
"created_by_user_id",
"default_routing_rule_id"
]
}
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "listApiKeys"
}
}
```
## POST /api/v1/keys
Create API key
Create a new API key. The full key is only returned once upon creation.
```json
{
"operation": {
"summary": "Create API key",
"tags": [
"Keys"
],
"description": "Create a new API key. The full key is only returned once upon creation.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"description": "Display name for the API key",
"type": "string"
},
"type": {
"description": "Key type (defaults to `inference`). Use `management` for a key that manages resources but cannot call inference endpoints.",
"type": "string",
"enum": [
"inference",
"management"
]
},
"workspace_id": {
"description": "Workspace to bind the key to. Organization keys default to the selected/default workspace.",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"limit": {
"description": "Usage limit in credits (null = unlimited)",
"nullable": true,
"type": "number"
},
"limit_reset": {
"description": "Period after which usage limits reset",
"nullable": true,
"type": "string",
"enum": [
"daily",
"weekly",
"monthly",
null
]
},
"include_byok_in_limit": {
"description": "Whether BYOK platform fees count toward this key’s usage limit (defaults to false)",
"type": "boolean"
},
"default_routing_rule_id": {
"description": "Routing rule to apply to requests from this key that do not name one. Must be an enabled rule accessible to the caller.",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
}
},
"required": [
"name"
]
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "The created API key",
"type": "object",
"properties": {
"name": {
"description": "Display name for the API key",
"type": "string"
},
"label": {
"description": "Human-readable label (defaults to hash if not set)",
"type": "string"
},
"type": {
"description": "Key type: `inference` keys call the model endpoints; `management` keys manage resources but cannot call inference endpoints",
"type": "string",
"enum": [
"inference",
"management"
]
},
"limit": {
"description": "Usage limit in credits (null = unlimited)",
"nullable": true,
"type": "number"
},
"limit_remaining": {
"description": "Remaining credits until limit is reached",
"nullable": true,
"type": "number"
},
"limit_reset": {
"description": "Period after which usage limits reset",
"nullable": true,
"type": "string",
"enum": [
"daily",
"weekly",
"monthly",
null
]
},
"include_byok_in_limit": {
"description": "Whether BYOK platform fees count toward this key’s usage limit",
"type": "boolean"
},
"usage": {
"description": "Total credits used (all time)",
"type": "number"
},
"usage_daily": {
"description": "Credits used today",
"type": "number"
},
"usage_weekly": {
"description": "Credits used this week",
"type": "number"
},
"usage_monthly": {
"description": "Credits used this month",
"type": "number"
},
"byok_usage": {
"description": "Total BYOK platform fees recorded for this key",
"type": "number"
},
"byok_usage_daily": {
"description": "BYOK platform fees recorded today",
"type": "number"
},
"byok_usage_weekly": {
"description": "BYOK platform fees recorded this week",
"type": "number"
},
"byok_usage_monthly": {
"description": "BYOK platform fees recorded this month",
"type": "number"
},
"disabled": {
"description": "Whether the key is disabled",
"type": "boolean"
},
"created_at": {
"description": "ISO 8601 timestamp of when the key was created",
"type": "string"
},
"updated_at": {
"description": "ISO 8601 timestamp of when the key was last updated",
"type": "string"
},
"last_used": {
"description": "ISO 8601 timestamp of when the key was last used (null if never used)",
"nullable": true,
"type": "string"
},
"hash": {
"description": "Public identifier for the key (used in URLs)",
"type": "string"
},
"org_id": {
"description": "Organization that owns the key (null for personal keys)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"workspace_id": {
"description": "Workspace this key is bound to (null for personal or legacy unscoped keys)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"created_by_user_id": {
"description": "User who created the key (null for legacy keys created before attribution)",
"nullable": true,
"type": "string"
},
"default_routing_rule_id": {
"description": "Routing rule applied to requests from this key that do not name one (null = no default)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
}
},
"required": [
"name",
"label",
"type",
"limit",
"limit_remaining",
"limit_reset",
"include_byok_in_limit",
"usage",
"usage_daily",
"usage_weekly",
"usage_monthly",
"byok_usage",
"byok_usage_daily",
"byok_usage_weekly",
"byok_usage_monthly",
"disabled",
"created_at",
"updated_at",
"last_used",
"hash",
"org_id",
"workspace_id",
"created_by_user_id",
"default_routing_rule_id"
]
},
"key": {
"description": "The full API key (only shown once upon creation)",
"nullable": true,
"type": "string"
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "createApiKey"
}
}
```
## GET /api/v1/keys/{hash}
Get API key
Retrieve details of a specific API key by its hash.
```json
{
"operation": {
"summary": "Get API key",
"tags": [
"Keys"
],
"description": "Retrieve details of a specific API key by its hash.",
"parameters": [
{
"schema": {
"type": "string"
},
"in": "path",
"name": "hash",
"required": true,
"description": "Public identifier of the API key"
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "The API key",
"type": "object",
"properties": {
"name": {
"description": "Display name for the API key",
"type": "string"
},
"label": {
"description": "Human-readable label (defaults to hash if not set)",
"type": "string"
},
"type": {
"description": "Key type: `inference` keys call the model endpoints; `management` keys manage resources but cannot call inference endpoints",
"type": "string",
"enum": [
"inference",
"management"
]
},
"limit": {
"description": "Usage limit in credits (null = unlimited)",
"nullable": true,
"type": "number"
},
"limit_remaining": {
"description": "Remaining credits until limit is reached",
"nullable": true,
"type": "number"
},
"limit_reset": {
"description": "Period after which usage limits reset",
"nullable": true,
"type": "string",
"enum": [
"daily",
"weekly",
"monthly",
null
]
},
"include_byok_in_limit": {
"description": "Whether BYOK platform fees count toward this key’s usage limit",
"type": "boolean"
},
"usage": {
"description": "Total credits used (all time)",
"type": "number"
},
"usage_daily": {
"description": "Credits used today",
"type": "number"
},
"usage_weekly": {
"description": "Credits used this week",
"type": "number"
},
"usage_monthly": {
"description": "Credits used this month",
"type": "number"
},
"byok_usage": {
"description": "Total BYOK platform fees recorded for this key",
"type": "number"
},
"byok_usage_daily": {
"description": "BYOK platform fees recorded today",
"type": "number"
},
"byok_usage_weekly": {
"description": "BYOK platform fees recorded this week",
"type": "number"
},
"byok_usage_monthly": {
"description": "BYOK platform fees recorded this month",
"type": "number"
},
"disabled": {
"description": "Whether the key is disabled",
"type": "boolean"
},
"created_at": {
"description": "ISO 8601 timestamp of when the key was created",
"type": "string"
},
"updated_at": {
"description": "ISO 8601 timestamp of when the key was last updated",
"type": "string"
},
"last_used": {
"description": "ISO 8601 timestamp of when the key was last used (null if never used)",
"nullable": true,
"type": "string"
},
"hash": {
"description": "Public identifier for the key (used in URLs)",
"type": "string"
},
"org_id": {
"description": "Organization that owns the key (null for personal keys)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"workspace_id": {
"description": "Workspace this key is bound to (null for personal or legacy unscoped keys)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"created_by_user_id": {
"description": "User who created the key (null for legacy keys created before attribution)",
"nullable": true,
"type": "string"
},
"default_routing_rule_id": {
"description": "Routing rule applied to requests from this key that do not name one (null = no default)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
}
},
"required": [
"name",
"label",
"type",
"limit",
"limit_remaining",
"limit_reset",
"include_byok_in_limit",
"usage",
"usage_daily",
"usage_weekly",
"usage_monthly",
"byok_usage",
"byok_usage_daily",
"byok_usage_weekly",
"byok_usage_monthly",
"disabled",
"created_at",
"updated_at",
"last_used",
"hash",
"org_id",
"workspace_id",
"created_by_user_id",
"default_routing_rule_id"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "getApiKey"
}
}
```
## DELETE /api/v1/keys/{hash}
Delete API key
Permanently delete an API key. This action cannot be undone.
```json
{
"operation": {
"summary": "Delete API key",
"tags": [
"Keys"
],
"description": "Permanently delete an API key. This action cannot be undone.",
"parameters": [
{
"schema": {
"type": "string"
},
"in": "path",
"name": "hash",
"required": true,
"description": "Public identifier of the API key"
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"success": {
"description": "Whether the deletion was successful",
"type": "boolean"
}
},
"required": [
"success"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "deleteApiKey"
}
}
```
## GET /api/v1/key
Get current API key
Retrieve metadata about the API key used to authenticate this request, including its usage and spend limits. Requires API key authentication.
```json
{
"operation": {
"summary": "Get current API key",
"tags": [
"Keys"
],
"description": "Retrieve metadata about the API key used to authenticate this request, including its usage and spend limits. Requires API key authentication.",
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "The API key",
"type": "object",
"properties": {
"name": {
"description": "Display name for the API key",
"type": "string"
},
"label": {
"description": "Human-readable label (defaults to hash if not set)",
"type": "string"
},
"type": {
"description": "Key type: `inference` keys call the model endpoints; `management` keys manage resources but cannot call inference endpoints",
"type": "string",
"enum": [
"inference",
"management"
]
},
"limit": {
"description": "Usage limit in credits (null = unlimited)",
"nullable": true,
"type": "number"
},
"limit_remaining": {
"description": "Remaining credits until limit is reached",
"nullable": true,
"type": "number"
},
"limit_reset": {
"description": "Period after which usage limits reset",
"nullable": true,
"type": "string",
"enum": [
"daily",
"weekly",
"monthly",
null
]
},
"include_byok_in_limit": {
"description": "Whether BYOK platform fees count toward this key’s usage limit",
"type": "boolean"
},
"usage": {
"description": "Total credits used (all time)",
"type": "number"
},
"usage_daily": {
"description": "Credits used today",
"type": "number"
},
"usage_weekly": {
"description": "Credits used this week",
"type": "number"
},
"usage_monthly": {
"description": "Credits used this month",
"type": "number"
},
"byok_usage": {
"description": "Total BYOK platform fees recorded for this key",
"type": "number"
},
"byok_usage_daily": {
"description": "BYOK platform fees recorded today",
"type": "number"
},
"byok_usage_weekly": {
"description": "BYOK platform fees recorded this week",
"type": "number"
},
"byok_usage_monthly": {
"description": "BYOK platform fees recorded this month",
"type": "number"
},
"disabled": {
"description": "Whether the key is disabled",
"type": "boolean"
},
"created_at": {
"description": "ISO 8601 timestamp of when the key was created",
"type": "string"
},
"updated_at": {
"description": "ISO 8601 timestamp of when the key was last updated",
"type": "string"
},
"last_used": {
"description": "ISO 8601 timestamp of when the key was last used (null if never used)",
"nullable": true,
"type": "string"
},
"hash": {
"description": "Public identifier for the key (used in URLs)",
"type": "string"
},
"org_id": {
"description": "Organization that owns the key (null for personal keys)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"workspace_id": {
"description": "Workspace this key is bound to (null for personal or legacy unscoped keys)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"created_by_user_id": {
"description": "User who created the key (null for legacy keys created before attribution)",
"nullable": true,
"type": "string"
},
"default_routing_rule_id": {
"description": "Routing rule applied to requests from this key that do not name one (null = no default)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
}
},
"required": [
"name",
"label",
"type",
"limit",
"limit_remaining",
"limit_reset",
"include_byok_in_limit",
"usage",
"usage_daily",
"usage_weekly",
"usage_monthly",
"byok_usage",
"byok_usage_daily",
"byok_usage_weekly",
"byok_usage_monthly",
"disabled",
"created_at",
"updated_at",
"last_used",
"hash",
"org_id",
"workspace_id",
"created_by_user_id",
"default_routing_rule_id"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "getCurrentApiKey"
}
}
```
---
# Models
> Model information and listing
Source: https://www.eurouter.ai/docs/api/models
## GET /api/v1/models
List models
Retrieve all available models. Supports filtering by category, provider, and supported parameters.
```json
{
"operation": {
"summary": "List models",
"tags": [
"Models"
],
"description": "Retrieve all available models. Supports filtering by category, provider, and supported parameters.",
"parameters": [
{
"schema": {
"type": "string"
},
"in": "query",
"name": "category",
"required": false,
"description": "Filter by model category"
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "supported_parameters",
"required": false,
"description": "Filter by supported parameters (comma-separated)"
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "provider",
"required": false,
"description": "Filter by provider slug"
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "use_rss",
"required": false,
"description": "Return results as RSS feed"
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "use_rss_chat_links",
"required": false,
"description": "Include chat links in RSS feed"
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"object": {
"description": "Object type identifier (always \"list\")",
"default": "list",
"type": "string",
"enum": [
"list"
]
},
"data": {
"description": "List of available models",
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"description": "Unique model identifier (e.g., \"azure/gpt-5.1\")",
"type": "string"
},
"object": {
"description": "Object type identifier (always \"model\")",
"default": "model",
"type": "string",
"enum": [
"model"
]
},
"canonical_slug": {
"description": "Canonical slug for the model",
"nullable": true,
"type": "string"
},
"hugging_face_id": {
"description": "Hugging Face model ID if available",
"type": "string"
},
"name": {
"description": "Human-readable model name",
"type": "string"
},
"created": {
"description": "Unix timestamp of when the model was added",
"nullable": true,
"type": "number"
},
"description": {
"description": "Model description",
"type": "string"
},
"context_length": {
"description": "Maximum context window size in tokens",
"nullable": true,
"type": "number"
},
"pricing": {
"description": "Pricing information for the model",
"type": "object",
"properties": {
"prompt": {
"description": "Cost per prompt token",
"type": "string"
},
"completion": {
"description": "Cost per completion token",
"type": "string"
},
"request": {
"description": "Fixed cost per request",
"type": "string"
},
"image": {
"description": "Cost per input image",
"type": "string"
},
"image_token": {
"description": "Cost per image token",
"type": "string"
},
"image_output": {
"description": "Cost per output image",
"type": "string"
},
"audio": {
"description": "Cost per audio second",
"type": "string"
},
"input_audio_cache": {
"description": "Cost per cached audio second",
"type": "string"
},
"web_search": {
"description": "Cost per web search",
"type": "string"
},
"internal_reasoning": {
"description": "Cost per internal reasoning token",
"type": "string"
},
"input_cache_read": {
"description": "Cost per cached input token read",
"type": "string"
},
"input_cache_write": {
"description": "Cost per cached input token write",
"type": "string"
},
"currency": {
"description": "Currency code for the pricing (e.g. USD)",
"type": "string"
},
"discount": {
"description": "Discount percentage applied to this model (0-1)",
"type": "number"
}
},
"required": [
"prompt",
"completion",
"request",
"image",
"image_token",
"image_output",
"audio",
"input_audio_cache",
"web_search",
"internal_reasoning",
"input_cache_read",
"input_cache_write",
"discount"
]
},
"architecture": {
"description": "Model architecture details",
"type": "object",
"properties": {
"modality": {
"description": "Primary modality of the model (e.g., \"text\", \"multimodal\")",
"type": "string"
},
"input_modalities": {
"description": "Supported input modalities",
"type": "array",
"items": {
"type": "string"
}
},
"output_modalities": {
"description": "Supported output modalities",
"type": "array",
"items": {
"type": "string"
}
},
"tokenizer": {
"description": "Tokenizer used by the model",
"nullable": true,
"type": "string"
},
"instruct_type": {
"description": "Instruction format type (e.g., \"alpaca\", \"vicuna\")",
"nullable": true,
"type": "string"
}
},
"required": [
"modality",
"input_modalities",
"output_modalities",
"tokenizer",
"instruct_type"
]
},
"top_provider": {
"description": "Information about the top provider for this model",
"type": "object",
"properties": {
"context_length": {
"description": "Maximum context length supported by the top provider",
"nullable": true,
"type": "number"
},
"max_completion_tokens": {
"description": "Maximum completion tokens supported",
"nullable": true,
"type": "number"
},
"is_moderated": {
"description": "Whether the provider applies content moderation",
"type": "boolean"
}
},
"required": [
"context_length",
"max_completion_tokens",
"is_moderated"
]
},
"per_request_limits": {
"description": "Per-request limits (reserved for future use)",
"type": "string",
"nullable": true,
"enum": [
null
]
},
"supported_parameters": {
"description": "List of supported API parameters",
"type": "array",
"items": {
"type": "string"
}
},
"supported_voices": {
"description": "Supported voice identifiers, when applicable",
"nullable": true,
"type": "array",
"items": {
"type": "string"
}
},
"knowledge_cutoff": {
"description": "Model knowledge cutoff, when known",
"nullable": true,
"type": "string"
},
"release_date": {
"description": "Real-world model release date (not the DB insert date), when known",
"nullable": true,
"type": "string"
},
"last_updated": {
"description": "Date the model was last updated by its vendor, when known",
"nullable": true,
"type": "string"
},
"reasoning": {
"description": "Per-model reasoning controls",
"type": "object",
"properties": {
"mandatory": {
"description": "Whether the model always reasons and reasoning cannot be disabled",
"type": "boolean"
},
"supported_efforts": {
"description": "Supported reasoning effort levels. Empty when unknown or not a reasoning model — never guessed.",
"type": "array",
"items": {
"type": "string"
}
},
"supports_max_tokens": {
"description": "Whether the model accepts a reasoning token budget (reasoning.max_tokens)",
"type": "boolean"
}
},
"required": [
"mandatory",
"supported_efforts",
"supports_max_tokens"
]
},
"expiration_date": {
"description": "Model expiration date, when applicable",
"nullable": true,
"type": "string"
},
"links": {
"description": "Related model links",
"type": "object",
"properties": {
"details": {
"description": "URL for model endpoint details",
"type": "string"
}
},
"required": [
"details"
]
},
"supported_api_endpoints": {
"description": "List of supported API endpoints (e.g., \"chat.completions\", \"embeddings\"). Empty array means all endpoints are supported.",
"type": "array",
"items": {
"type": "string"
}
},
"default_parameters": {
"description": "Default parameter values",
"type": "object",
"properties": {
"temperature": {
"description": "Default temperature setting",
"nullable": true,
"type": "number"
},
"top_p": {
"description": "Default top_p (nucleus sampling) setting",
"nullable": true,
"type": "number"
},
"top_k": {
"description": "Default top_k setting",
"nullable": true,
"type": "number"
},
"frequency_penalty": {
"description": "Default frequency penalty setting",
"nullable": true,
"type": "number"
},
"presence_penalty": {
"description": "Default presence penalty setting",
"nullable": true,
"type": "number"
},
"repetition_penalty": {
"description": "Default repetition penalty setting",
"nullable": true,
"type": "number"
}
},
"required": [
"temperature",
"top_p",
"top_k",
"frequency_penalty",
"presence_penalty",
"repetition_penalty"
],
"additionalProperties": {}
},
"author": {
"description": "Model author or organization",
"type": "string"
},
"slug": {
"description": "URL-friendly model slug",
"type": "string"
},
"tags": {
"description": "Categorization tags",
"type": "array",
"items": {
"type": "string"
}
},
"providers": {
"description": "List of providers offering this model",
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"description": "Provider display name",
"type": "string"
},
"slug": {
"description": "Provider slug",
"type": "string"
}
},
"required": [
"name",
"slug"
]
}
},
"author_info": {
"description": "Author metadata for branding (logo, gradient colors)",
"nullable": true,
"type": "object",
"properties": {
"slug": {
"description": "Author slug identifier (e.g., \"openai\", \"meta\")",
"type": "string"
},
"name": {
"description": "Author name (e.g., \"OpenAI\", \"Meta\")",
"type": "string"
},
"display_name": {
"description": "Optional display name override for UI",
"nullable": true,
"type": "string"
},
"icon_url": {
"description": "URL to author logo image",
"nullable": true,
"type": "string"
},
"gradient_from": {
"description": "CSS gradient start class (e.g., \"from-zinc-800\")",
"nullable": true,
"type": "string"
},
"gradient_to": {
"description": "CSS gradient end class (e.g., \"to-zinc-900\")",
"nullable": true,
"type": "string"
},
"gradient_via": {
"description": "Optional CSS gradient via class",
"nullable": true,
"type": "string"
},
"website_url": {
"description": "Author website URL",
"nullable": true,
"type": "string"
}
},
"required": [
"slug",
"name",
"display_name",
"icon_url",
"gradient_from",
"gradient_to",
"gradient_via",
"website_url"
]
}
},
"required": [
"id",
"object",
"canonical_slug",
"hugging_face_id",
"name",
"created",
"description",
"context_length",
"architecture",
"top_provider",
"per_request_limits",
"supported_parameters",
"supported_voices",
"knowledge_cutoff",
"release_date",
"last_updated",
"reasoning",
"expiration_date",
"links",
"supported_api_endpoints",
"default_parameters",
"providers"
]
}
}
},
"required": [
"object",
"data"
]
}
}
}
}
},
"operationId": "listModels",
"security": []
}
}
```
## GET /api/v1/models/count
Get model count
Returns the total number of models available in the catalog.
```json
{
"operation": {
"summary": "Get model count",
"tags": [
"Models"
],
"description": "Returns the total number of models available in the catalog.",
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"count": {
"description": "Total number of available models",
"type": "number"
}
},
"required": [
"count"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "getModelCount",
"security": []
}
}
```
---
# OAuth
> API reference for OAuth
Source: https://www.eurouter.ai/docs/api/oauth
## GET /api/v1/me
Get authenticated identity
Returns the authenticated user identity and account summary. Useful as a stable OAuth connection test endpoint.
```json
{
"operation": {
"summary": "Get authenticated identity",
"tags": [
"OAuth"
],
"description": "Returns the authenticated user identity and account summary. Useful as a stable OAuth connection test endpoint.",
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"user_id": {
"description": "Authenticated user ID",
"type": "string"
},
"email": {
"description": "Authenticated user email",
"type": "string"
},
"org_name": {
"description": "Resolved organization name for the authenticated user",
"nullable": true,
"type": "string"
},
"org_id": {
"description": "Resolved organization ID for the authenticated user",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"plan": {
"description": "Current subscription plan name",
"nullable": true,
"type": "string"
},
"credits": {
"description": "Current credit summary for the authenticated user",
"type": "object",
"properties": {
"balance": {
"description": "Current credit balance in EUR",
"type": "string"
},
"total_credits": {
"description": "Lifetime credits added in EUR",
"type": "string"
},
"total_usage": {
"description": "Lifetime credits consumed in EUR",
"type": "string"
}
},
"required": [
"balance",
"total_credits",
"total_usage"
]
}
},
"required": [
"user_id",
"email",
"org_name",
"org_id",
"plan",
"credits"
]
}
}
}
}
},
"operationId": "getAuthenticatedIdentity"
}
}
```
## POST /api/v1/auth/keys/authorize
Create authorization code (consent flow)
Creates an OAuth authorization code on behalf of the authenticated user. Called by the webapp consent page after user approves.
```json
{
"operation": {
"summary": "Create authorization code (consent flow)",
"tags": [
"OAuth"
],
"description": "Creates an OAuth authorization code on behalf of the authenticated user. Called by the webapp consent page after user approves.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"callback_url": {
"description": "HTTPS callback URL (localhost allowed in development)",
"type": "string",
"format": "uri"
},
"code_challenge": {
"description": "Base64url-encoded PKCE code challenge",
"type": "string",
"minLength": 43,
"maxLength": 128
},
"code_challenge_method": {
"description": "PKCE code challenge method",
"type": "string",
"enum": [
"S256",
"plain"
]
},
"limit": {
"description": "Spending limit in credits for the created key",
"nullable": true,
"type": "number"
},
"limit_reset": {
"description": "Period after which the spending limit resets",
"nullable": true,
"type": "string",
"enum": [
"daily",
"weekly",
"monthly",
null
]
},
"key_label": {
"description": "Human-readable label for the created API key",
"type": "string",
"maxLength": 255
}
},
"required": [
"callback_url",
"code_challenge",
"code_challenge_method"
]
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"code": {
"description": "Authorization code to exchange for an API key",
"type": "string"
},
"created_at": {
"description": "ISO 8601 timestamp",
"type": "string"
}
},
"required": [
"code",
"created_at"
]
}
}
}
}
},
"operationId": "createAuthorizationCodeConsentFlow"
}
}
```
## POST /api/v1/auth/keys/code
Create authorization code (programmatic)
Programmatically creates an OAuth authorization code. Requires a management API key.
```json
{
"operation": {
"summary": "Create authorization code (programmatic)",
"tags": [
"OAuth"
],
"description": "Programmatically creates an OAuth authorization code. Requires a management API key.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"callback_url": {
"description": "HTTPS callback URL (localhost allowed in development)",
"type": "string",
"format": "uri"
},
"code_challenge": {
"description": "Base64url-encoded PKCE code challenge",
"type": "string",
"minLength": 43,
"maxLength": 128
},
"code_challenge_method": {
"description": "PKCE code challenge method",
"type": "string",
"enum": [
"S256",
"plain"
]
},
"limit": {
"description": "Spending limit in credits for the created key",
"nullable": true,
"type": "number"
},
"limit_reset": {
"description": "Period after which the spending limit resets",
"nullable": true,
"type": "string",
"enum": [
"daily",
"weekly",
"monthly",
null
]
},
"key_label": {
"description": "Human-readable label for the created API key",
"type": "string",
"maxLength": 255
}
},
"required": [
"callback_url",
"code_challenge",
"code_challenge_method"
]
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"code": {
"description": "Authorization code to exchange for an API key",
"type": "string"
},
"created_at": {
"description": "ISO 8601 timestamp",
"type": "string"
}
},
"required": [
"code",
"created_at"
]
}
}
}
}
},
"operationId": "createAuthorizationCodeProgrammatic"
}
}
```
## POST /api/v1/auth/keys
Exchange authorization code for API key
Exchanges an OAuth authorization code and PKCE verifier for a user-controlled API key. The code is single-use and expires after 10 minutes.
```json
{
"operation": {
"summary": "Exchange authorization code for API key",
"tags": [
"OAuth"
],
"description": "Exchanges an OAuth authorization code and PKCE verifier for a user-controlled API key. The code is single-use and expires after 10 minutes.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"code": {
"description": "Authorization code received from the callback",
"type": "string",
"minLength": 1
},
"code_verifier": {
"description": "Original PKCE code verifier",
"type": "string",
"minLength": 43,
"maxLength": 128
},
"code_challenge_method": {
"description": "PKCE code challenge method — must match the method used in step 1",
"type": "string",
"enum": [
"S256",
"plain"
]
}
},
"required": [
"code",
"code_verifier"
]
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"key": {
"description": "The API key (shown only once)",
"type": "string"
},
"user_id": {
"description": "The ID of the user who authorized the key",
"type": "string"
}
},
"required": [
"key",
"user_id"
]
}
}
}
}
},
"operationId": "exchangeAuthorizationCodeForApiKey",
"security": []
}
}
```
## GET /api/v1/auth
Begin OAuth authorization (browser redirect)
Redirects the user to the EUrouter consent page. After authorization, the user is redirected back to the callback URL with an authorization code.
```json
{
"operation": {
"summary": "Begin OAuth authorization (browser redirect)",
"tags": [
"OAuth"
],
"description": "Redirects the user to the EUrouter consent page. After authorization, the user is redirected back to the callback URL with an authorization code.",
"parameters": [
{
"schema": {
"type": "string",
"format": "uri"
},
"in": "query",
"name": "callback_url",
"required": true,
"description": "URL to redirect back to after authorization"
},
{
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 128
},
"in": "query",
"name": "code_challenge",
"required": true,
"description": "Base64url-encoded PKCE code challenge"
},
{
"schema": {
"default": "S256",
"type": "string",
"enum": [
"S256",
"plain"
]
},
"in": "query",
"name": "code_challenge_method",
"required": true,
"description": "PKCE code challenge method (S256 recommended)"
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "state",
"required": false,
"description": "Opaque client state echoed back unchanged to the callback flow"
},
{
"schema": {
"type": "string",
"enum": [
"code"
]
},
"in": "query",
"name": "response_type",
"required": false,
"description": "Optional OAuth response type accepted for compatibility with hosted OAuth clients"
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "client_id",
"required": false,
"description": "Optional OAuth client identifier accepted for compatibility with hosted OAuth clients"
},
{
"schema": {
"type": "string",
"format": "uri"
},
"in": "query",
"name": "redirect_uri",
"required": false,
"description": "Optional OAuth redirect URI accepted for compatibility; must match callback_url when both are present"
}
],
"responses": {
"200": {
"description": "Default Response"
}
},
"operationId": "beginOauthAuthorizationBrowserRedirect",
"security": []
}
}
```
---
# Providers
> Provider information
Source: https://www.eurouter.ai/docs/api/providers
## GET /api/v1/providers
List providers
Retrieve all available AI providers with their metadata.
```json
{
"operation": {
"summary": "List providers",
"tags": [
"Providers"
],
"description": "Retrieve all available AI providers with their metadata.",
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "List of available providers",
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"description": "Provider display name",
"type": "string"
},
"slug": {
"description": "URL-friendly provider identifier",
"type": "string"
},
"description": {
"description": "Provider description",
"nullable": true,
"type": "string"
},
"model_count": {
"description": "Number of models available from this provider",
"nullable": true,
"type": "number"
},
"privacy_policy_url": {
"description": "URL to the provider's privacy policy",
"nullable": true,
"type": "string"
},
"terms_of_service_url": {
"description": "URL to the provider's terms of service",
"nullable": true,
"type": "string"
},
"status_page_url": {
"description": "URL to the provider's status page",
"nullable": true,
"type": "string"
},
"id": {
"description": "Unique provider identifier",
"type": "string"
},
"region": {
"description": "Primary region where the provider operates",
"nullable": true,
"type": "string"
},
"enabled": {
"description": "Whether the provider is currently enabled",
"type": "boolean"
},
"data_policy": {
"description": "Provider data handling policies",
"nullable": true,
"type": "object",
"additionalProperties": {}
},
"headquarters": {
"description": "Provider headquarters location",
"nullable": true,
"type": "string"
},
"icon_url": {
"description": "URL to the provider's icon",
"nullable": true,
"type": "string"
},
"byok": {
"description": "BYOK availability and OpenRouter-compatible credential metadata.",
"oneOf": [
{
"type": "object",
"properties": {
"supported": {
"description": "This provider is not currently available for BYOK.",
"type": "boolean",
"enum": [
false
]
}
},
"required": [
"supported"
]
},
{
"type": "object",
"properties": {
"supported": {
"description": "This provider is available for personal BYOK credentials.",
"type": "boolean",
"enum": [
true
]
},
"canonical_slug": {
"description": "Canonical provider slug stored by EUrouter.",
"type": "string"
},
"aliases": {
"description": "Accepted OpenRouter-compatible aliases for this provider.",
"type": "array",
"items": {
"type": "string"
}
},
"credential_shape": {
"description": "Credential format accepted by the BYOK management API.",
"type": "string",
"enum": [
"bearer",
"aws",
"google-service-account",
"azure-foundry"
]
},
"test_strategy": {
"description": "Credential validation strategy used by the BYOK test endpoint.",
"type": "string",
"enum": [
"catalog",
"anthropic",
"aws-bedrock-eu",
"google-vertex-eu"
]
},
"eu_region_enforcement": {
"description": "How EUrouter constrains provider execution or validation to the configured EU boundary.",
"type": "string",
"enum": [
"provider-endpoint",
"customer-resource",
"seeded-eu-regions",
"seeded-eu-locations"
]
}
},
"required": [
"supported",
"canonical_slug",
"aliases",
"credential_shape",
"test_strategy",
"eu_region_enforcement"
]
}
]
}
},
"required": [
"name",
"slug"
]
}
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "listProviders",
"security": []
}
}
```
---
# Rerank
> API reference for Rerank
Source: https://www.eurouter.ai/docs/api/rerank
## POST /api/v1/rerank
Rerank documents
Rank a list of documents by relevance to a query. Documents can be plain strings or {"text": "..."} objects and are returned sorted by relevance score, echoing each document with its original input index. Text-only for now; streaming is not supported.
```json
{
"operation": {
"summary": "Rerank documents",
"tags": [
"Rerank"
],
"description": "Rank a list of documents by relevance to a query. Documents can be plain strings or {\"text\": \"...\"} objects and are returned sorted by relevance score, echoing each document with its original input index. Text-only for now; streaming is not supported.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"model": {
"description": "Model identifier (e.g., \"qwen/qwen3-reranker-4b\")",
"type": "string",
"minLength": 1
},
"query": {
"description": "The search query to rank the documents against",
"type": "string",
"minLength": 1
},
"documents": {
"description": "Documents to rank: plain strings or {\"text\": \"...\"} objects (text-only for now). At least one is required; there is no upper count limit. Search-unit-billed endpoints charge one unit per started block of 100 documents.",
"minItems": 1,
"type": "array",
"items": {
"description": "A document to rank: a plain string or an object with a \"text\" field",
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "object",
"properties": {
"text": {
"description": "Document text to rank against the query",
"type": "string",
"minLength": 1
},
"image": {
"description": "Not supported: the rerank endpoint is text-only for now"
}
},
"required": [
"text"
]
}
]
}
},
"top_n": {
"description": "Return only the N most relevant results. Default: all documents, ranked. Ranking always covers every document, so top_n does not reduce billing.",
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
"provider": {
"description": "Provider routing preferences",
"type": "object",
"properties": {
"order": {
"description": "Provider priority order - try these first, in order",
"type": "array",
"items": {
"type": "string"
}
},
"ignore": {
"description": "Providers to exclude from routing",
"type": "array",
"items": {
"type": "string"
}
},
"only": {
"description": "Only use these providers (exclusive list)",
"type": "array",
"items": {
"type": "string"
}
},
"allow_fallbacks": {
"description": "Allow fallback to other providers on failure (default: true)",
"type": "boolean"
},
"sort": {
"description": "Sort strategy: price (cheapest), latency (fastest), throughput (highest tokens/s)",
"type": "string",
"enum": [
"price",
"latency",
"throughput"
]
},
"require_parameters": {
"description": "Only use providers that support all request parameters",
"type": "boolean"
},
"quantizations": {
"description": "Filter by model quantization levels",
"type": "array",
"items": {
"description": "Model quantization level",
"type": "string",
"enum": [
"int4",
"int8",
"fp4",
"fp6",
"fp8",
"fp16",
"bf16",
"fp32"
]
}
},
"data_collection": {
"description": "Filter providers by data collection policy",
"type": "string",
"enum": [
"allow",
"deny"
]
},
"data_residency": {
"description": "Filter endpoints by geographic data processing region",
"type": "string",
"minLength": 2,
"maxLength": 10
},
"max_retention_days": {
"description": "Maximum data retention period in days (0 = ZDR only)",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"eu_owned": {
"description": "Only use EU-headquartered providers",
"type": "boolean"
}
}
},
"trace": {
"description": "Trace context for Broadcast observability",
"type": "object",
"properties": {
"trace_id": {
"description": "Groups multiple requests into a single trace",
"type": "string"
},
"trace_name": {
"description": "Custom name for the root trace",
"type": "string"
},
"span_name": {
"description": "Creates a parent span grouping LLM operations",
"type": "string"
},
"generation_name": {
"description": "Names the specific LLM generation span",
"type": "string"
},
"parent_span_id": {
"description": "Links to an existing external span in your trace hierarchy",
"type": "string"
}
},
"additionalProperties": {}
},
"session_id": {
"description": "Session identifier for grouping related requests",
"type": "string",
"maxLength": 128
}
},
"required": [
"model",
"query",
"documents"
],
"additionalProperties": {}
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"description": "Unique request identifier",
"type": "string"
},
"model": {
"description": "Canonical slug of the model that served the request",
"type": "string"
},
"results": {
"description": "Documents ranked by relevance, descending",
"type": "array",
"items": {
"type": "object",
"properties": {
"index": {
"description": "Position of the document in the request input array (0-based)",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"relevance_score": {
"description": "Relevance of the document to the query; higher is more relevant. Scores are model-specific and not comparable across models.",
"type": "number"
},
"document": {
"description": "Echo of the ranked document as {\"text\": \"...\"}, always present (reconstructed from your input)",
"type": "object",
"properties": {
"text": {
"type": "string"
}
},
"required": [
"text"
]
}
},
"required": [
"index",
"relevance_score",
"document"
]
}
},
"usage": {
"description": "Usage and cost statistics",
"type": "object",
"properties": {
"prompt_tokens": {
"description": "Number of input tokens (token-billed endpoints; rerank has no completion tokens)",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"total_tokens": {
"description": "Total tokens used (same as prompt_tokens for rerank)",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"search_units": {
"description": "Search units consumed (search-unit-billed endpoints; one unit covers up to 100 documents)",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"cost": {
"description": "Total request cost in native currency",
"type": "number"
},
"cost_currency": {
"description": "Currency of `cost` — the serving endpoint's native pricing currency",
"type": "string",
"enum": [
"USD",
"EUR"
]
},
"cost_eur": {
"description": "Cost converted to EUR — the amount debited from the account balance",
"type": "number"
},
"is_byok": {
"description": "Whether the request used a user-supplied provider key",
"type": "boolean"
},
"cost_details": {
"description": "Detailed upstream inference cost breakdown",
"type": "object",
"properties": {
"upstream_inference_cost": {
"type": "number"
},
"upstream_inference_prompt_cost": {
"type": "number"
},
"upstream_inference_completions_cost": {
"type": "number"
}
},
"required": [
"upstream_inference_cost",
"upstream_inference_prompt_cost",
"upstream_inference_completions_cost"
]
}
}
},
"provider": {
"description": "Provider that served the request",
"type": "string"
}
},
"required": [
"model",
"results",
"usage"
]
}
}
}
}
},
"operationId": "rerankDocuments"
}
}
```
---
# Responses
> API reference for Responses
Source: https://www.eurouter.ai/docs/api/responses
## POST /api/v1/responses
Create response
Generate a response using the Responses API. Supports text, structured output, tool calling, streaming response events, conversation continuity, provider routing, and fallback.
```json
{
"operation": {
"summary": "Create response",
"tags": [
"Responses"
],
"description": "Generate a response using the Responses API. Supports text, structured output, tool calling, streaming response events, conversation continuity, provider routing, and fallback.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"models": {
"description": "Fallback model list (EUrouter extension)",
"type": "array",
"items": {
"type": "string"
}
},
"rule_id": {
"description": "Routing rule ID to apply (EUrouter extension)",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"rule_name": {
"description": "Routing rule name to apply (EUrouter extension)",
"type": "string"
},
"provider": {
"description": "Provider routing preferences (EUrouter extension)",
"type": "object",
"properties": {
"order": {
"description": "Provider priority order - try these first, in order",
"type": "array",
"items": {
"type": "string"
}
},
"ignore": {
"description": "Providers to exclude from routing",
"type": "array",
"items": {
"type": "string"
}
},
"only": {
"description": "Only use these providers (exclusive list)",
"type": "array",
"items": {
"type": "string"
}
},
"allow_fallbacks": {
"description": "Allow fallback to other providers on failure (default: true)",
"type": "boolean"
},
"sort": {
"description": "Sort strategy: price (cheapest), latency (fastest), throughput (highest tokens/s)",
"type": "string",
"enum": [
"price",
"latency",
"throughput"
]
},
"require_parameters": {
"description": "Only use providers that support all request parameters",
"type": "boolean"
},
"quantizations": {
"description": "Filter by model quantization levels",
"type": "array",
"items": {
"description": "Model quantization level",
"type": "string",
"enum": [
"int4",
"int8",
"fp4",
"fp6",
"fp8",
"fp16",
"bf16",
"fp32"
]
}
},
"data_collection": {
"description": "Filter providers by data collection policy",
"type": "string",
"enum": [
"allow",
"deny"
]
},
"data_residency": {
"description": "Filter endpoints by geographic data processing region",
"type": "string",
"minLength": 2,
"maxLength": 10
},
"max_retention_days": {
"description": "Maximum data retention period in days (0 = ZDR only)",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"eu_owned": {
"description": "Only use EU-headquartered providers",
"type": "boolean"
}
}
},
"model": {
"description": "Model identifier (e.g., \"gpt-4o\")",
"type": "string"
},
"input": {
"description": "The input to generate a response for",
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"properties": {
"type": {
"description": "Input item type",
"type": "string",
"enum": [
"message"
]
},
"role": {
"description": "Message role",
"type": "string",
"enum": [
"system"
]
},
"content": {
"description": "System message content",
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"input_text"
]
},
"text": {
"description": "The text content",
"type": "string"
}
},
"required": [
"type",
"text"
]
}
}
]
}
},
"required": [
"type",
"role",
"content"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Input item type",
"type": "string",
"enum": [
"message"
]
},
"role": {
"description": "Message role",
"type": "string",
"enum": [
"user"
]
},
"content": {
"description": "User message content",
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"input_text"
]
},
"text": {
"description": "The text content",
"type": "string"
}
},
"required": [
"type",
"text"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"input_image"
]
},
"image_url": {
"description": "URL or base64 data URI of the image",
"type": "string"
},
"detail": {
"description": "Image detail level for vision models",
"type": "string",
"enum": [
"auto",
"low",
"high"
]
}
},
"required": [
"type",
"image_url"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"input_audio"
]
},
"data": {
"description": "Base64-encoded audio data",
"type": "string"
},
"format": {
"description": "Audio format",
"type": "string",
"enum": [
"wav",
"mp3",
"flac",
"m4a",
"ogg",
"pcm16"
]
}
},
"required": [
"type",
"data",
"format"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"input_file"
]
},
"file_id": {
"description": "ID of uploaded file",
"type": "string"
},
"file_data": {
"description": "Base64-encoded file data",
"type": "string"
},
"filename": {
"description": "Original filename",
"type": "string"
}
},
"required": [
"type"
]
},
{
"type": "object",
"properties": {
"type": {
"type": "string"
}
},
"required": [
"type"
],
"additionalProperties": {}
}
]
}
}
]
}
},
"required": [
"type",
"role",
"content"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Input item type",
"type": "string",
"enum": [
"message"
]
},
"role": {
"description": "Message role",
"type": "string",
"enum": [
"assistant"
]
},
"content": {
"description": "Assistant message content",
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {
"description": "Content type identifier",
"type": "string",
"enum": [
"input_text"
]
},
"text": {
"description": "The text content",
"type": "string"
}
},
"required": [
"type",
"text"
]
}
}
]
}
},
"required": [
"type",
"role",
"content"
]
},
{
"type": "object",
"properties": {
"type": {
"type": "string"
}
},
"additionalProperties": {}
}
]
}
}
]
},
"instructions": {
"description": "System-level instructions for the model",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"previous_response_id": {
"description": "ID of previous response for conversation continuity",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"stream": {
"description": "Enable streaming responses",
"anyOf": [
{
"default": false,
"type": "boolean"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"stream_options": {
"description": "Options for streaming responses",
"anyOf": [
{
"type": "object",
"properties": {
"include_obfuscation": {
"description": "Include OpenAI stream obfuscation fields",
"type": "boolean"
},
"include_usage": {
"description": "Include usage in stream events",
"type": "boolean"
}
}
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"max_output_tokens": {
"description": "Maximum tokens to generate. When omitted, the provider default applies; providers that require a limit receive the selected endpoint's catalogued maximum",
"anyOf": [
{
"type": "number",
"minimum": 1
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"temperature": {
"description": "Sampling temperature (0-2)",
"anyOf": [
{
"default": 1,
"type": "number",
"minimum": 0,
"maximum": 2
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"top_p": {
"description": "Nucleus sampling probability (0-1)",
"anyOf": [
{
"default": 1,
"type": "number",
"minimum": 0,
"maximum": 1
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"tools": {
"description": "Available tools for the model",
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"properties": {
"type": {
"description": "Tool type",
"type": "string",
"enum": [
"function"
]
},
"name": {
"description": "Function name (max 64 chars)",
"type": "string",
"maxLength": 64
},
"description": {
"description": "Description of what the function does",
"type": "string"
},
"parameters": {
"description": "JSON Schema for function parameters",
"type": "object",
"additionalProperties": {}
},
"strict": {
"description": "Enable strict schema validation",
"anyOf": [
{
"type": "boolean"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
}
},
"required": [
"type",
"name"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Web search tool type",
"type": "string",
"enum": [
"web_search_preview"
]
},
"search_context_size": {
"description": "Amount of context to retrieve",
"type": "string",
"enum": [
"low",
"medium",
"high"
]
},
"user_location": {
"description": "User location for localized search",
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"approximate"
]
},
"country": {
"type": "string"
},
"city": {
"type": "string"
},
"region": {
"type": "string"
}
},
"required": [
"type"
]
}
},
"required": [
"type"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "File search tool type",
"type": "string",
"enum": [
"file_search"
]
},
"vector_store_ids": {
"description": "Vector store IDs to search",
"type": "array",
"items": {
"type": "string"
}
},
"max_num_results": {
"description": "Maximum number of results",
"type": "number"
},
"ranking_options": {
"description": "Ranking configuration",
"type": "object",
"properties": {
"ranker": {
"type": "string",
"enum": [
"auto",
"default_2024_08_21"
]
},
"score_threshold": {
"type": "number",
"minimum": 0,
"maximum": 1
}
}
}
},
"required": [
"type"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Code interpreter tool type",
"type": "string",
"enum": [
"code_interpreter"
]
},
"container": {
"description": "Container configuration",
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"auto"
]
}
}
}
},
"required": [
"type"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Computer use tool type",
"type": "string",
"enum": [
"computer_use_preview"
]
},
"display_width": {
"description": "Display width in pixels",
"type": "number"
},
"display_height": {
"description": "Display height in pixels",
"type": "number"
},
"environment": {
"description": "Environment type",
"type": "string",
"enum": [
"browser",
"mac",
"windows",
"ubuntu"
]
}
},
"required": [
"type",
"display_width",
"display_height",
"environment"
]
},
{
"type": "object",
"properties": {
"type": {
"type": "string"
}
},
"required": [
"type"
],
"additionalProperties": {}
}
]
}
},
"tool_choice": {
"description": "Tool calling behavior",
"anyOf": [
{
"description": "Model decides whether to call tools",
"type": "string",
"enum": [
"auto"
]
},
{
"description": "Do not call any tools",
"type": "string",
"enum": [
"none"
]
},
{
"description": "Model must call at least one tool",
"type": "string",
"enum": [
"required"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Tool choice type",
"type": "string",
"enum": [
"function"
]
},
"name": {
"description": "Name of the function to call",
"type": "string"
}
},
"required": [
"type",
"name"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Hosted tool type",
"type": "string",
"enum": [
"file_search",
"code_interpreter",
"web_search_preview",
"computer_use_preview"
]
}
},
"required": [
"type"
]
}
]
},
"parallel_tool_calls": {
"description": "Allow parallel tool calls",
"type": "boolean"
},
"truncation": {
"description": "Context truncation strategy",
"type": "string",
"enum": [
"auto",
"disabled"
]
},
"metadata": {
"description": "Custom metadata",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"user": {
"description": "End-user identifier for abuse detection",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"store": {
"description": "Whether to store the response",
"anyOf": [
{
"type": "boolean"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"reasoning": {
"description": "Reasoning parameters (for reasoning models)",
"anyOf": [
{
"type": "object",
"properties": {
"effort": {
"description": "How much effort to spend on reasoning",
"anyOf": [
{
"description": "Reasoning effort level",
"type": "string",
"enum": [
"none",
"minimal",
"low",
"medium",
"high",
"xhigh",
"max"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"generate_summary": {
"description": "Deprecated reasoning summary verbosity",
"anyOf": [
{
"description": "Reasoning summary verbosity",
"type": "string",
"enum": [
"auto",
"concise",
"detailed"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"summary": {
"description": "Verbosity of reasoning summary",
"anyOf": [
{
"description": "Reasoning summary verbosity",
"type": "string",
"enum": [
"auto",
"concise",
"detailed"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
}
},
"additionalProperties": {}
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"reasoning_effort": {
"description": "OpenAI-compatible shorthand for reasoning.effort",
"anyOf": [
{
"description": "Reasoning effort level",
"type": "string",
"enum": [
"none",
"minimal",
"low",
"medium",
"high",
"xhigh",
"max"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"text": {
"description": "Text format specification",
"type": "object",
"properties": {
"format": {
"description": "Text format configuration",
"type": "object",
"properties": {
"type": {
"description": "Response format type",
"type": "string",
"enum": [
"text",
"json_object",
"json_schema"
]
},
"name": {
"description": "Schema name for json_schema format",
"type": "string",
"maxLength": 64
},
"description": {
"description": "Schema description",
"type": "string"
},
"schema": {
"description": "JSON Schema definition",
"type": "object",
"additionalProperties": {}
},
"strict": {
"description": "Enable strict schema validation",
"anyOf": [
{
"type": "boolean"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"json_schema": {
"type": "object",
"properties": {
"name": {
"description": "Schema name (max 64 chars)",
"type": "string",
"maxLength": 64
},
"description": {
"description": "Schema description",
"type": "string"
},
"schema": {
"description": "JSON Schema definition",
"type": "object",
"additionalProperties": {}
},
"strict": {
"description": "Enable strict schema validation",
"anyOf": [
{
"type": "boolean"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
}
},
"required": [
"name"
]
}
},
"required": [
"type"
]
},
"verbosity": {
"description": "Output verbosity level",
"type": "string",
"enum": [
"low",
"medium",
"high",
"auto",
"concise",
"detailed"
]
}
}
},
"background": {
"description": "Whether to run the response in the background",
"type": "boolean"
},
"conversation": {
"description": "OpenAI conversation continuation configuration"
},
"context_management": {
"description": "OpenAI context management configuration",
"type": "object",
"additionalProperties": {}
},
"frequency_penalty": {
"description": "Frequency penalty",
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"image_config": {
"description": "Image output configuration"
},
"include": {
"description": "Additional output data to include",
"type": "array",
"items": {
"type": "string",
"enum": [
"web_search_call.action.sources",
"code_interpreter_call.outputs",
"computer_call_output.output.image_url",
"file_search_call.results",
"message.input_image.image_url",
"message.output_text.logprobs",
"reasoning.encrypted_content"
]
}
},
"max_tool_calls": {
"description": "Maximum number of tool calls allowed",
"type": "number"
},
"modalities": {
"description": "Requested output modalities",
"type": "array",
"items": {
"type": "string"
}
},
"plugins": {
"description": "Optional plugins (e.g. { id: \"response-healing\", enabled?: boolean })",
"type": "array",
"items": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean"
}
},
"additionalProperties": {}
}
},
"presence_penalty": {
"description": "Presence penalty",
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"prompt": {
"description": "OpenAI prompt template reference",
"type": "object",
"additionalProperties": {}
},
"prompt_cache_key": {
"description": "Prompt cache key",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"prompt_cache_retention": {
"description": "Prompt cache retention policy",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"route": {
"description": "Routing descriptor"
},
"safety_identifier": {
"description": "Stable safety identifier",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"service_tier": {
"description": "Service tier for the request",
"type": "string",
"enum": [
"auto",
"default",
"flex",
"scale",
"priority"
]
},
"top_k": {
"description": "Top-k sampling parameter",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"top_logprobs": {
"description": "Number of top logprobs to return",
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"trace": {
"description": "Trace context for Broadcast observability",
"type": "object",
"properties": {
"trace_id": {
"description": "Groups multiple requests into a single trace",
"type": "string"
},
"trace_name": {
"description": "Custom name for the root trace",
"type": "string"
},
"span_name": {
"description": "Creates a parent span grouping LLM operations",
"type": "string"
},
"generation_name": {
"description": "Names the specific LLM generation span",
"type": "string"
},
"parent_span_id": {
"description": "Links to an existing external span in your trace hierarchy",
"type": "string"
}
},
"additionalProperties": {}
},
"session_id": {
"description": "Session identifier for grouping related requests",
"type": "string",
"maxLength": 128
}
},
"required": [
"input"
],
"additionalProperties": {}
},
"example": {
"model": "mistral-large-3",
"input": "Explain EU data residency in one sentence."
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"description": "Unique response identifier",
"type": "string"
},
"object": {
"description": "Object type",
"type": "string",
"enum": [
"response"
]
},
"created_at": {
"description": "Unix timestamp of creation",
"type": "number"
},
"status": {
"description": "Response status",
"type": "string",
"enum": [
"queued",
"in_progress",
"completed",
"incomplete",
"failed",
"cancelled"
]
},
"model": {
"description": "Model used for response",
"type": "string"
},
"provider": {
"description": "Provider that served the request",
"type": "string"
},
"output": {
"description": "Response output items",
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"properties": {
"type": {
"description": "Output item type",
"type": "string",
"enum": [
"message"
]
},
"id": {
"description": "Unique message ID",
"type": "string"
},
"role": {
"description": "Message role",
"type": "string",
"enum": [
"assistant"
]
},
"status": {
"description": "Message status",
"type": "string",
"enum": [
"in_progress",
"completed",
"incomplete"
]
},
"content": {
"description": "Message content items",
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"properties": {
"type": {
"description": "Output content type",
"type": "string",
"enum": [
"output_text"
]
},
"text": {
"description": "The generated text",
"type": "string"
},
"annotations": {
"description": "Text annotations (citations, etc.)",
"type": "array",
"items": {}
},
"logprobs": {
"description": "Log probabilities for tokens",
"type": "array",
"items": {}
}
},
"required": [
"type",
"text"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Output content type",
"type": "string",
"enum": [
"refusal"
]
},
"refusal": {
"description": "Refusal message",
"type": "string"
}
},
"required": [
"type",
"refusal"
]
},
{
"type": "object",
"properties": {
"type": {
"type": "string"
}
},
"required": [
"type"
],
"additionalProperties": {}
}
]
}
}
},
"required": [
"type",
"id",
"role",
"status",
"content"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Output item type",
"type": "string",
"enum": [
"function_call"
]
},
"id": {
"description": "Unique function call ID",
"type": "string"
},
"call_id": {
"description": "Tool call ID for matching response",
"type": "string"
},
"name": {
"description": "Function name",
"type": "string"
},
"arguments": {
"description": "JSON-encoded function arguments",
"type": "string"
},
"status": {
"description": "Function call status",
"type": "string",
"enum": [
"in_progress",
"completed",
"incomplete"
]
}
},
"required": [
"type",
"id",
"call_id",
"name",
"arguments",
"status"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Output item type",
"type": "string",
"enum": [
"web_search_call"
]
},
"id": {
"description": "Unique web search call ID",
"type": "string"
},
"status": {
"description": "Search status",
"type": "string",
"enum": [
"in_progress",
"searching",
"completed",
"failed"
]
},
"action": {
"description": "Web search action details",
"type": "object",
"properties": {
"type": {
"description": "Action type (e.g., \"search\")",
"type": "string"
},
"query": {
"description": "The search query",
"type": "string"
},
"queries": {
"description": "Array of search queries",
"type": "array",
"items": {
"type": "string"
}
},
"sources": {
"description": "Search result sources",
"type": "array",
"items": {}
}
},
"required": [
"type"
]
}
},
"required": [
"type",
"id",
"status"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Output item type",
"type": "string",
"enum": [
"file_search_call"
]
},
"id": {
"description": "Unique file search call ID",
"type": "string"
},
"queries": {
"description": "Search queries",
"type": "array",
"items": {
"type": "string"
}
},
"status": {
"description": "Search status",
"type": "string",
"enum": [
"in_progress",
"searching",
"completed",
"failed"
]
},
"results": {
"description": "Search results",
"type": "array",
"items": {}
}
},
"required": [
"type",
"id",
"status"
]
},
{
"type": "object",
"properties": {
"type": {
"description": "Output item type",
"type": "string",
"enum": [
"reasoning"
]
},
"id": {
"description": "Unique reasoning ID",
"type": "string"
},
"summary": {
"description": "Reasoning summary",
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"summary_text"
]
},
"text": {
"type": "string"
}
},
"required": [
"type",
"text"
]
}
}
},
"required": [
"type",
"id"
]
},
{
"type": "object",
"properties": {
"type": {
"type": "string"
}
},
"required": [
"type"
],
"additionalProperties": {}
}
]
}
},
"output_text": {
"description": "Concatenated text output convenience field",
"type": "string"
},
"usage": {
"description": "Token usage statistics",
"anyOf": [
{
"type": "object",
"properties": {
"input_tokens": {
"description": "Tokens in the input",
"type": "number"
},
"output_tokens": {
"description": "Tokens in the output",
"type": "number"
},
"total_tokens": {
"description": "Total tokens used",
"type": "number"
},
"cost": {
"description": "Upstream inference cost",
"type": "number"
},
"cost_currency": {
"description": "Currency of `cost` — the serving endpoint's native pricing currency",
"type": "string",
"enum": [
"USD",
"EUR"
]
},
"cost_eur": {
"description": "Cost converted to EUR — the amount debited from the account balance",
"type": "number"
},
"is_byok": {
"description": "Whether the request used a user-supplied provider key",
"type": "boolean"
},
"cost_details": {
"description": "Detailed upstream inference cost breakdown",
"type": "object",
"additionalProperties": {
"type": "number"
}
},
"input_tokens_details": {
"description": "Input token breakdown",
"type": "object",
"properties": {
"cached_tokens": {
"description": "Tokens served from cache",
"type": "number"
}
}
},
"output_tokens_details": {
"description": "Output token breakdown",
"type": "object",
"properties": {
"reasoning_tokens": {
"description": "Tokens used for reasoning",
"type": "number"
}
}
}
},
"required": [
"input_tokens",
"output_tokens",
"total_tokens"
],
"additionalProperties": {}
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"completed_at": {
"description": "Unix timestamp of completion",
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"error": {
"description": "Error information (if status is failed)",
"anyOf": [
{
"type": "object",
"properties": {
"code": {
"description": "Error code",
"type": "string"
},
"message": {
"description": "Error message",
"type": "string"
}
},
"required": [
"code",
"message"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"incomplete_details": {
"description": "Details about incomplete response",
"anyOf": [
{
"type": "object",
"properties": {
"reason": {
"description": "Reason for incomplete response",
"type": "string",
"enum": [
"max_output_tokens",
"content_filter"
]
}
},
"required": [
"reason"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"billing": {
"description": "Billing information",
"type": "object",
"properties": {
"payer": {
"description": "Billing payer",
"type": "string"
}
}
},
"frequency_penalty": {
"description": "Frequency penalty (echoed or defaulted)",
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"conversation": {
"description": "Conversation associated with this response",
"anyOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"additionalProperties": {}
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"instructions": {
"description": "System-level instructions (echoed from request)",
"anyOf": [
{
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {}
}
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"max_output_tokens": {
"description": "Maximum tokens (echoed from request)",
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"max_tool_calls": {
"description": "Maximum built-in tool calls allowed",
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"moderation": {
"description": "Moderation result metadata",
"type": "string",
"nullable": true,
"enum": [
null
]
},
"parallel_tool_calls": {
"description": "Allow parallel tool calls (echoed from request)",
"type": "boolean"
},
"presence_penalty": {
"description": "Presence penalty (echoed or defaulted)",
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"previous_response_id": {
"description": "Previous response ID (echoed from request)",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"prompt": {
"description": "Prompt template reference",
"anyOf": [
{
"type": "object",
"additionalProperties": {}
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"prompt_cache_key": {
"description": "Prompt cache key",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"prompt_cache_retention": {
"description": "Prompt cache retention policy",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"reasoning": {
"description": "Reasoning config (echoed from request)",
"anyOf": [
{
"type": "object",
"properties": {
"effort": {
"description": "How much effort to spend on reasoning",
"anyOf": [
{
"description": "Reasoning effort level",
"type": "string",
"enum": [
"none",
"minimal",
"low",
"medium",
"high",
"xhigh",
"max"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"generate_summary": {
"description": "Deprecated reasoning summary verbosity",
"anyOf": [
{
"description": "Reasoning summary verbosity",
"type": "string",
"enum": [
"auto",
"concise",
"detailed"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"summary": {
"description": "Verbosity of reasoning summary",
"anyOf": [
{
"description": "Reasoning summary verbosity",
"type": "string",
"enum": [
"auto",
"concise",
"detailed"
]
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
}
},
"additionalProperties": {}
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"safety_identifier": {
"description": "Safety identifier",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"store": {
"description": "Whether to store response (echoed from request)",
"type": "boolean"
},
"temperature": {
"description": "Temperature (echoed from request)",
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"text": {
"description": "Text format (echoed from request)",
"type": "object",
"properties": {
"format": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"text",
"json_object",
"json_schema"
]
},
"description": {
"description": "Schema description",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"name": {
"description": "Schema name",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"schema": {
"description": "Structured output schema"
},
"strict": {
"description": "Structured output strict mode",
"anyOf": [
{
"type": "boolean"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
}
},
"required": [
"type"
]
},
"verbosity": {
"description": "Output verbosity level",
"type": "string"
}
}
},
"tool_choice": {
"description": "Tool choice (echoed from request)",
"anyOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"type": {
"type": "string"
},
"name": {
"type": "string"
}
},
"required": [
"type"
]
}
]
},
"tools": {
"description": "Tools (echoed from request)",
"type": "array",
"items": {}
},
"top_logprobs": {
"description": "Top logprobs count",
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"top_p": {
"description": "Top-p (echoed from request)",
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"truncation": {
"description": "Truncation (echoed from request)",
"type": "string",
"enum": [
"auto",
"disabled"
]
},
"user": {
"description": "User ID (echoed from request)",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"metadata": {
"description": "Custom metadata",
"anyOf": [
{
"type": "object",
"additionalProperties": {
"type": "string"
}
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
},
"background": {
"description": "Whether running in background",
"type": "boolean"
},
"service_tier": {
"description": "Service tier used",
"anyOf": [
{
"type": "string"
},
{
"type": "string",
"nullable": true,
"enum": [
null
]
}
]
}
},
"required": [
"id",
"object",
"created_at",
"status",
"model",
"output",
"usage"
],
"additionalProperties": {}
}
}
}
}
},
"operationId": "createResponse"
}
}
```
---
# Routing Rules
> API reference for Routing Rules
Source: https://www.eurouter.ai/docs/api/routing-rules
## GET /api/v1/routing-rules
List routing rules
Retrieve all routing rules accessible to the authenticated user.
```json
{
"operation": {
"summary": "List routing rules",
"tags": [
"Routing Rules"
],
"description": "Retrieve all routing rules accessible to the authenticated user.",
"parameters": [
{
"schema": {
"type": "boolean"
},
"in": "query",
"name": "include_disabled",
"required": false,
"description": "Include disabled rules (default: false)"
},
{
"schema": {
"type": "string",
"enum": [
"all",
"user",
"org",
"workspace",
"api_key"
]
},
"in": "query",
"name": "scope",
"required": false,
"description": "Filter by scope type"
},
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "query",
"name": "workspace_id",
"required": false,
"description": "Filter routing rules by workspace ID. Omit to list all accessible rules; when set, account-wide rules (workspace_id null) are also included."
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "List of routing rules",
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"description": "Unique rule identifier",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"name": {
"description": "Display name for the rule",
"type": "string"
},
"description": {
"description": "Optional description of the rule",
"nullable": true,
"type": "string"
},
"user_id": {
"description": "User ID (always set - indicates rule owner)",
"nullable": true,
"type": "string"
},
"org_id": {
"description": "Organization ID if org-scoped",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"workspace_id": {
"description": "Workspace the rule is scoped to (null = applies account-wide)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"api_key_id": {
"description": "API key ID if key-scoped",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"model": {
"description": "Primary model (e.g., \"anthropic/claude-3-opus\")",
"nullable": true,
"type": "string"
},
"models": {
"description": "Fallback model chain",
"nullable": true,
"type": "array",
"items": {
"type": "string"
}
},
"provider": {
"description": "Provider routing preferences",
"nullable": true,
"type": "object",
"properties": {
"order": {
"description": "Provider priority order - try these first, in order",
"type": "array",
"items": {
"type": "string"
}
},
"ignore": {
"description": "Providers to exclude from routing",
"type": "array",
"items": {
"type": "string"
}
},
"only": {
"description": "Only use these providers (exclusive list)",
"type": "array",
"items": {
"type": "string"
}
},
"allow_fallbacks": {
"description": "Allow fallback to other providers on failure (default: true)",
"type": "boolean"
},
"sort": {
"description": "Sort strategy: price (cheapest), latency (fastest), throughput (highest tokens/s)",
"type": "string",
"enum": [
"price",
"latency",
"throughput"
]
},
"require_parameters": {
"description": "Only use providers that support all request parameters",
"type": "boolean"
},
"quantizations": {
"description": "Filter by model quantization levels",
"type": "array",
"items": {
"description": "Model quantization level",
"type": "string",
"enum": [
"int4",
"int8",
"fp4",
"fp6",
"fp8",
"fp16",
"bf16",
"fp32"
]
}
},
"data_collection": {
"description": "Filter providers by data collection policy",
"type": "string",
"enum": [
"allow",
"deny"
]
},
"data_residency": {
"description": "Filter endpoints by geographic data processing region",
"type": "string",
"minLength": 2,
"maxLength": 10
},
"max_retention_days": {
"description": "Maximum data retention period in days (0 = ZDR only)",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"eu_owned": {
"description": "Only use EU-headquartered providers",
"type": "boolean"
}
}
},
"enabled": {
"description": "Whether the rule is active",
"type": "boolean"
},
"created_at": {
"description": "ISO 8601 creation timestamp",
"type": "string"
},
"updated_at": {
"description": "ISO 8601 last update timestamp",
"type": "string"
}
},
"required": [
"id",
"name",
"description",
"user_id",
"org_id",
"workspace_id",
"api_key_id",
"model",
"models",
"provider",
"enabled",
"created_at",
"updated_at"
]
}
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "listRoutingRules"
}
}
```
## POST /api/v1/routing-rules
Create routing rule
Create a new routing rule. Rules can be scoped to user, organization, or specific API key.
```json
{
"operation": {
"summary": "Create routing rule",
"tags": [
"Routing Rules"
],
"description": "Create a new routing rule. Rules can be scoped to user, organization, or specific API key.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"description": "Display name for the rule (1-255 characters)",
"type": "string",
"minLength": 1,
"maxLength": 255
},
"description": {
"description": "Optional description (max 1000 characters)",
"nullable": true,
"type": "string",
"maxLength": 1000
},
"scope": {
"description": "Scope of the rule (defaults to user; persistence is driven by workspace_id/org_id/api_key_id)",
"type": "string",
"enum": [
"user",
"org",
"workspace",
"api_key"
]
},
"org_id": {
"description": "Organization ID if org-scoped",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"workspace_id": {
"description": "Workspace to scope the rule to (omit/null = applies account-wide)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"api_key_id": {
"description": "API key ID if key-scoped",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"model": {
"description": "Primary model (e.g., \"anthropic/claude-3-opus\")",
"type": "string"
},
"models": {
"description": "Fallback model chain",
"type": "array",
"items": {
"type": "string"
}
},
"provider": {
"description": "Provider routing preferences",
"type": "object",
"properties": {
"order": {
"description": "Provider priority order - try these first, in order",
"type": "array",
"items": {
"type": "string"
}
},
"ignore": {
"description": "Providers to exclude from routing",
"type": "array",
"items": {
"type": "string"
}
},
"only": {
"description": "Only use these providers (exclusive list)",
"type": "array",
"items": {
"type": "string"
}
},
"allow_fallbacks": {
"description": "Allow fallback to other providers on failure (default: true)",
"type": "boolean"
},
"sort": {
"description": "Sort strategy: price (cheapest), latency (fastest), throughput (highest tokens/s)",
"type": "string",
"enum": [
"price",
"latency",
"throughput"
]
},
"require_parameters": {
"description": "Only use providers that support all request parameters",
"type": "boolean"
},
"quantizations": {
"description": "Filter by model quantization levels",
"type": "array",
"items": {
"description": "Model quantization level",
"type": "string",
"enum": [
"int4",
"int8",
"fp4",
"fp6",
"fp8",
"fp16",
"bf16",
"fp32"
]
}
},
"data_collection": {
"description": "Filter providers by data collection policy",
"type": "string",
"enum": [
"allow",
"deny"
]
},
"data_residency": {
"description": "Filter endpoints by geographic data processing region",
"type": "string",
"minLength": 2,
"maxLength": 10
},
"max_retention_days": {
"description": "Maximum data retention period in days (0 = ZDR only)",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"eu_owned": {
"description": "Only use EU-headquartered providers",
"type": "boolean"
}
}
},
"enabled": {
"description": "Whether the rule is active (default: true)",
"default": true,
"type": "boolean"
}
},
"required": [
"name"
]
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "The routing rule",
"type": "object",
"properties": {
"id": {
"description": "Unique rule identifier",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"name": {
"description": "Display name for the rule",
"type": "string"
},
"description": {
"description": "Optional description of the rule",
"nullable": true,
"type": "string"
},
"user_id": {
"description": "User ID (always set - indicates rule owner)",
"nullable": true,
"type": "string"
},
"org_id": {
"description": "Organization ID if org-scoped",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"workspace_id": {
"description": "Workspace the rule is scoped to (null = applies account-wide)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"api_key_id": {
"description": "API key ID if key-scoped",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"model": {
"description": "Primary model (e.g., \"anthropic/claude-3-opus\")",
"nullable": true,
"type": "string"
},
"models": {
"description": "Fallback model chain",
"nullable": true,
"type": "array",
"items": {
"type": "string"
}
},
"provider": {
"description": "Provider routing preferences",
"nullable": true,
"type": "object",
"properties": {
"order": {
"description": "Provider priority order - try these first, in order",
"type": "array",
"items": {
"type": "string"
}
},
"ignore": {
"description": "Providers to exclude from routing",
"type": "array",
"items": {
"type": "string"
}
},
"only": {
"description": "Only use these providers (exclusive list)",
"type": "array",
"items": {
"type": "string"
}
},
"allow_fallbacks": {
"description": "Allow fallback to other providers on failure (default: true)",
"type": "boolean"
},
"sort": {
"description": "Sort strategy: price (cheapest), latency (fastest), throughput (highest tokens/s)",
"type": "string",
"enum": [
"price",
"latency",
"throughput"
]
},
"require_parameters": {
"description": "Only use providers that support all request parameters",
"type": "boolean"
},
"quantizations": {
"description": "Filter by model quantization levels",
"type": "array",
"items": {
"description": "Model quantization level",
"type": "string",
"enum": [
"int4",
"int8",
"fp4",
"fp6",
"fp8",
"fp16",
"bf16",
"fp32"
]
}
},
"data_collection": {
"description": "Filter providers by data collection policy",
"type": "string",
"enum": [
"allow",
"deny"
]
},
"data_residency": {
"description": "Filter endpoints by geographic data processing region",
"type": "string",
"minLength": 2,
"maxLength": 10
},
"max_retention_days": {
"description": "Maximum data retention period in days (0 = ZDR only)",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"eu_owned": {
"description": "Only use EU-headquartered providers",
"type": "boolean"
}
}
},
"enabled": {
"description": "Whether the rule is active",
"type": "boolean"
},
"created_at": {
"description": "ISO 8601 creation timestamp",
"type": "string"
},
"updated_at": {
"description": "ISO 8601 last update timestamp",
"type": "string"
}
},
"required": [
"id",
"name",
"description",
"user_id",
"org_id",
"workspace_id",
"api_key_id",
"model",
"models",
"provider",
"enabled",
"created_at",
"updated_at"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "createRoutingRule"
}
}
```
## POST /api/v1/routing-rules/dry-run
Dry-run routing test
Test a routing rule configuration and see which providers would be available. Returns provider count and names for each model.
```json
{
"operation": {
"summary": "Dry-run routing test",
"tags": [
"Routing Rules"
],
"description": "Test a routing rule configuration and see which providers would be available. Returns provider count and names for each model.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"rule_id": {
"description": "Rule ID to test",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"rule_name": {
"description": "Rule name to test",
"type": "string"
},
"model": {
"description": "Single model to simulate routing for",
"type": "string"
},
"models": {
"description": "Array of models to evaluate (fallback chain)",
"type": "array",
"items": {
"type": "string"
}
},
"preference_overrides": {
"description": "Override rule preferences for what-if testing",
"type": "object",
"properties": {
"order": {
"description": "Provider priority order - try these first, in order",
"type": "array",
"items": {
"type": "string"
}
},
"ignore": {
"description": "Providers to exclude from routing",
"type": "array",
"items": {
"type": "string"
}
},
"only": {
"description": "Only use these providers (exclusive list)",
"type": "array",
"items": {
"type": "string"
}
},
"allow_fallbacks": {
"description": "Allow fallback to other providers on failure (default: true)",
"type": "boolean"
},
"sort": {
"description": "Sort strategy: price (cheapest), latency (fastest), throughput (highest tokens/s)",
"type": "string",
"enum": [
"price",
"latency",
"throughput"
]
},
"require_parameters": {
"description": "Only use providers that support all request parameters",
"type": "boolean"
},
"quantizations": {
"description": "Filter by model quantization levels",
"type": "array",
"items": {
"description": "Model quantization level",
"type": "string",
"enum": [
"int4",
"int8",
"fp4",
"fp6",
"fp8",
"fp16",
"bf16",
"fp32"
]
}
},
"data_collection": {
"description": "Filter providers by data collection policy",
"type": "string",
"enum": [
"allow",
"deny"
]
},
"data_residency": {
"description": "Filter endpoints by geographic data processing region",
"type": "string",
"minLength": 2,
"maxLength": 10
},
"max_retention_days": {
"description": "Maximum data retention period in days (0 = ZDR only)",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"eu_owned": {
"description": "Only use EU-headquartered providers",
"type": "boolean"
}
}
}
}
}
}
}
},
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"rule_applied": {
"description": "Rule that was applied (null if none)",
"nullable": true,
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"name": {
"type": "string"
}
},
"required": [
"id",
"name"
]
},
"effective_preferences": {
"description": "Final merged preferences used for routing",
"nullable": true,
"type": "object",
"properties": {
"order": {
"description": "Provider priority order - try these first, in order",
"type": "array",
"items": {
"type": "string"
}
},
"ignore": {
"description": "Providers to exclude from routing",
"type": "array",
"items": {
"type": "string"
}
},
"only": {
"description": "Only use these providers (exclusive list)",
"type": "array",
"items": {
"type": "string"
}
},
"allow_fallbacks": {
"description": "Allow fallback to other providers on failure (default: true)",
"type": "boolean"
},
"sort": {
"description": "Sort strategy: price (cheapest), latency (fastest), throughput (highest tokens/s)",
"type": "string",
"enum": [
"price",
"latency",
"throughput"
]
},
"require_parameters": {
"description": "Only use providers that support all request parameters",
"type": "boolean"
},
"quantizations": {
"description": "Filter by model quantization levels",
"type": "array",
"items": {
"description": "Model quantization level",
"type": "string",
"enum": [
"int4",
"int8",
"fp4",
"fp6",
"fp8",
"fp16",
"bf16",
"fp32"
]
}
},
"data_collection": {
"description": "Filter providers by data collection policy",
"type": "string",
"enum": [
"allow",
"deny"
]
},
"data_residency": {
"description": "Filter endpoints by geographic data processing region",
"type": "string",
"minLength": 2,
"maxLength": 10
},
"max_retention_days": {
"description": "Maximum data retention period in days (0 = ZDR only)",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"eu_owned": {
"description": "Only use EU-headquartered providers",
"type": "boolean"
}
}
},
"results": {
"description": "Results per model",
"type": "array",
"items": {
"type": "object",
"properties": {
"model": {
"description": "Model slug",
"type": "string"
},
"provider_count": {
"description": "Number of available providers",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"providers": {
"description": "List of provider slugs",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"model",
"provider_count",
"providers"
]
}
},
"summary": {
"description": "Summary statistics",
"type": "object",
"properties": {
"total_models": {
"description": "Total number of models evaluated",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"models_with_providers": {
"description": "Models with at least one provider",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": [
"total_models",
"models_with_providers"
]
}
},
"required": [
"rule_applied",
"effective_preferences",
"results",
"summary"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "dryRunRoutingTest"
}
}
```
## GET /api/v1/routing-rules/eu-residency
Get EU residency data
Returns lists of EU, EEA, and EU-adequate countries for data residency routing decisions.
```json
{
"operation": {
"summary": "Get EU residency data",
"tags": [
"Routing Rules"
],
"description": "Returns lists of EU, EEA, and EU-adequate countries for data residency routing decisions.",
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"eu_countries": {
"description": "EU member states",
"type": "array",
"items": {
"type": "object",
"properties": {
"code": {
"description": "ISO 3166-1 alpha-2 country code",
"type": "string"
},
"name": {
"description": "Country name",
"type": "string"
}
},
"required": [
"code",
"name"
]
}
},
"eea_countries": {
"description": "EEA countries (EU + Norway, Iceland, Liechtenstein)",
"type": "array",
"items": {
"type": "object",
"properties": {
"code": {
"description": "ISO 3166-1 alpha-2 country code",
"type": "string"
},
"name": {
"description": "Country name",
"type": "string"
}
},
"required": [
"code",
"name"
]
}
},
"eu_adequate_countries": {
"description": "Countries with EU data adequacy status",
"type": "array",
"items": {
"type": "object",
"properties": {
"code": {
"description": "ISO 3166-1 alpha-2 country code",
"type": "string"
},
"name": {
"description": "Country name",
"type": "string"
}
},
"required": [
"code",
"name"
]
}
}
},
"required": [
"eu_countries",
"eea_countries",
"eu_adequate_countries"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "getEuResidencyData"
}
}
```
## GET /api/v1/routing-rules/{id}
Get routing rule
Retrieve details of a specific routing rule by its ID.
```json
{
"operation": {
"summary": "Get routing rule",
"tags": [
"Routing Rules"
],
"description": "Retrieve details of a specific routing rule by its ID.",
"parameters": [
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "id",
"required": true,
"description": "Routing rule UUID"
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "The routing rule",
"type": "object",
"properties": {
"id": {
"description": "Unique rule identifier",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"name": {
"description": "Display name for the rule",
"type": "string"
},
"description": {
"description": "Optional description of the rule",
"nullable": true,
"type": "string"
},
"user_id": {
"description": "User ID (always set - indicates rule owner)",
"nullable": true,
"type": "string"
},
"org_id": {
"description": "Organization ID if org-scoped",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"workspace_id": {
"description": "Workspace the rule is scoped to (null = applies account-wide)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"api_key_id": {
"description": "API key ID if key-scoped",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"model": {
"description": "Primary model (e.g., \"anthropic/claude-3-opus\")",
"nullable": true,
"type": "string"
},
"models": {
"description": "Fallback model chain",
"nullable": true,
"type": "array",
"items": {
"type": "string"
}
},
"provider": {
"description": "Provider routing preferences",
"nullable": true,
"type": "object",
"properties": {
"order": {
"description": "Provider priority order - try these first, in order",
"type": "array",
"items": {
"type": "string"
}
},
"ignore": {
"description": "Providers to exclude from routing",
"type": "array",
"items": {
"type": "string"
}
},
"only": {
"description": "Only use these providers (exclusive list)",
"type": "array",
"items": {
"type": "string"
}
},
"allow_fallbacks": {
"description": "Allow fallback to other providers on failure (default: true)",
"type": "boolean"
},
"sort": {
"description": "Sort strategy: price (cheapest), latency (fastest), throughput (highest tokens/s)",
"type": "string",
"enum": [
"price",
"latency",
"throughput"
]
},
"require_parameters": {
"description": "Only use providers that support all request parameters",
"type": "boolean"
},
"quantizations": {
"description": "Filter by model quantization levels",
"type": "array",
"items": {
"description": "Model quantization level",
"type": "string",
"enum": [
"int4",
"int8",
"fp4",
"fp6",
"fp8",
"fp16",
"bf16",
"fp32"
]
}
},
"data_collection": {
"description": "Filter providers by data collection policy",
"type": "string",
"enum": [
"allow",
"deny"
]
},
"data_residency": {
"description": "Filter endpoints by geographic data processing region",
"type": "string",
"minLength": 2,
"maxLength": 10
},
"max_retention_days": {
"description": "Maximum data retention period in days (0 = ZDR only)",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"eu_owned": {
"description": "Only use EU-headquartered providers",
"type": "boolean"
}
}
},
"enabled": {
"description": "Whether the rule is active",
"type": "boolean"
},
"created_at": {
"description": "ISO 8601 creation timestamp",
"type": "string"
},
"updated_at": {
"description": "ISO 8601 last update timestamp",
"type": "string"
}
},
"required": [
"id",
"name",
"description",
"user_id",
"org_id",
"workspace_id",
"api_key_id",
"model",
"models",
"provider",
"enabled",
"created_at",
"updated_at"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "getRoutingRule"
}
}
```
## PATCH /api/v1/routing-rules/{id}
Update routing rule
Update an existing routing rule. Only provided fields will be modified.
```json
{
"operation": {
"summary": "Update routing rule",
"tags": [
"Routing Rules"
],
"description": "Update an existing routing rule. Only provided fields will be modified.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"description": "New display name",
"type": "string",
"minLength": 1,
"maxLength": 255
},
"description": {
"description": "New description (null to remove)",
"nullable": true,
"type": "string",
"maxLength": 1000
},
"model": {
"description": "Primary model (null to remove)",
"nullable": true,
"type": "string"
},
"models": {
"description": "Fallback model chain (null to remove)",
"nullable": true,
"type": "array",
"items": {
"type": "string"
}
},
"provider": {
"description": "Provider preferences (null to remove)",
"nullable": true,
"type": "object",
"properties": {
"order": {
"description": "Provider priority order - try these first, in order",
"type": "array",
"items": {
"type": "string"
}
},
"ignore": {
"description": "Providers to exclude from routing",
"type": "array",
"items": {
"type": "string"
}
},
"only": {
"description": "Only use these providers (exclusive list)",
"type": "array",
"items": {
"type": "string"
}
},
"allow_fallbacks": {
"description": "Allow fallback to other providers on failure (default: true)",
"type": "boolean"
},
"sort": {
"description": "Sort strategy: price (cheapest), latency (fastest), throughput (highest tokens/s)",
"type": "string",
"enum": [
"price",
"latency",
"throughput"
]
},
"require_parameters": {
"description": "Only use providers that support all request parameters",
"type": "boolean"
},
"quantizations": {
"description": "Filter by model quantization levels",
"type": "array",
"items": {
"description": "Model quantization level",
"type": "string",
"enum": [
"int4",
"int8",
"fp4",
"fp6",
"fp8",
"fp16",
"bf16",
"fp32"
]
}
},
"data_collection": {
"description": "Filter providers by data collection policy",
"type": "string",
"enum": [
"allow",
"deny"
]
},
"data_residency": {
"description": "Filter endpoints by geographic data processing region",
"type": "string",
"minLength": 2,
"maxLength": 10
},
"max_retention_days": {
"description": "Maximum data retention period in days (0 = ZDR only)",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"eu_owned": {
"description": "Only use EU-headquartered providers",
"type": "boolean"
}
}
},
"enabled": {
"description": "Whether the rule is active",
"type": "boolean"
}
}
}
}
}
},
"parameters": [
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "id",
"required": true,
"description": "Routing rule UUID"
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"description": "The routing rule",
"type": "object",
"properties": {
"id": {
"description": "Unique rule identifier",
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"name": {
"description": "Display name for the rule",
"type": "string"
},
"description": {
"description": "Optional description of the rule",
"nullable": true,
"type": "string"
},
"user_id": {
"description": "User ID (always set - indicates rule owner)",
"nullable": true,
"type": "string"
},
"org_id": {
"description": "Organization ID if org-scoped",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"workspace_id": {
"description": "Workspace the rule is scoped to (null = applies account-wide)",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"api_key_id": {
"description": "API key ID if key-scoped",
"nullable": true,
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"model": {
"description": "Primary model (e.g., \"anthropic/claude-3-opus\")",
"nullable": true,
"type": "string"
},
"models": {
"description": "Fallback model chain",
"nullable": true,
"type": "array",
"items": {
"type": "string"
}
},
"provider": {
"description": "Provider routing preferences",
"nullable": true,
"type": "object",
"properties": {
"order": {
"description": "Provider priority order - try these first, in order",
"type": "array",
"items": {
"type": "string"
}
},
"ignore": {
"description": "Providers to exclude from routing",
"type": "array",
"items": {
"type": "string"
}
},
"only": {
"description": "Only use these providers (exclusive list)",
"type": "array",
"items": {
"type": "string"
}
},
"allow_fallbacks": {
"description": "Allow fallback to other providers on failure (default: true)",
"type": "boolean"
},
"sort": {
"description": "Sort strategy: price (cheapest), latency (fastest), throughput (highest tokens/s)",
"type": "string",
"enum": [
"price",
"latency",
"throughput"
]
},
"require_parameters": {
"description": "Only use providers that support all request parameters",
"type": "boolean"
},
"quantizations": {
"description": "Filter by model quantization levels",
"type": "array",
"items": {
"description": "Model quantization level",
"type": "string",
"enum": [
"int4",
"int8",
"fp4",
"fp6",
"fp8",
"fp16",
"bf16",
"fp32"
]
}
},
"data_collection": {
"description": "Filter providers by data collection policy",
"type": "string",
"enum": [
"allow",
"deny"
]
},
"data_residency": {
"description": "Filter endpoints by geographic data processing region",
"type": "string",
"minLength": 2,
"maxLength": 10
},
"max_retention_days": {
"description": "Maximum data retention period in days (0 = ZDR only)",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"eu_owned": {
"description": "Only use EU-headquartered providers",
"type": "boolean"
}
}
},
"enabled": {
"description": "Whether the rule is active",
"type": "boolean"
},
"created_at": {
"description": "ISO 8601 creation timestamp",
"type": "string"
},
"updated_at": {
"description": "ISO 8601 last update timestamp",
"type": "string"
}
},
"required": [
"id",
"name",
"description",
"user_id",
"org_id",
"workspace_id",
"api_key_id",
"model",
"models",
"provider",
"enabled",
"created_at",
"updated_at"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "updateRoutingRule"
}
}
```
## DELETE /api/v1/routing-rules/{id}
Delete routing rule
Permanently delete a routing rule. This action cannot be undone.
```json
{
"operation": {
"summary": "Delete routing rule",
"tags": [
"Routing Rules"
],
"description": "Permanently delete a routing rule. This action cannot be undone.",
"parameters": [
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "id",
"required": true,
"description": "Routing rule UUID"
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"success": {
"description": "Whether the deletion was successful",
"type": "boolean"
}
},
"required": [
"success"
]
}
},
"required": [
"data"
]
}
}
}
}
},
"operationId": "deleteRoutingRule"
}
}
```
---
# App Attribution
> Get your app featured in EUrouter rankings and analytics.
Source: https://www.eurouter.ai/docs/concepts/app-attribution
***
App attribution allows developers to associate their API usage with their application, enabling visibility in EUrouter's public rankings and detailed analytics. By including simple headers in your requests, your app can appear in our leaderboards and gain insights into your model usage patterns.
***
## Benefits of App Attribution [#benefits-of-app-attribution]
Attributed apps receive:
* **Public App Rankings** -- Your app appears in EUrouter's [public rankings](/rankings) with 7, 30, and 90-day leaderboards
* **Model Page Features** -- Your app is shown on individual model pages, displaying usage statistics
* **Comprehensive Analytics** -- Track your model usage, token consumption, and cost trends over time
* **Community Visibility** -- Gain exposure among the EUrouter developer community
***
## Attribution Headers [#attribution-headers]
Include these optional HTTP headers in your API requests to enable attribution:
### HTTP-Referer [#http-referer]
Identifies your app's URL and is used as the primary identifier for rankings.
| Detail | Value |
| -------- | ------------------------------------ |
| Header | `HTTP-Referer` |
| Required | Optional (recommended) |
| Format | Valid URL (e.g. `https://myapp.com`) |
### X-EUrouter-Title [#x-eurouter-title]
Sets or modifies your app's display name in rankings and analytics.
| Detail | Value |
| -------- | ----------------------------- |
| Header | `X-EUrouter-Title` |
| Required | Optional |
| Format | Plain text (e.g. `My AI App`) |
### X-EUrouter-Categories [#x-eurouter-categories]
Assigns your app to one or more marketplace categories.
| Detail | Value |
| -------- | -------------------------------------------------------------------- |
| Header | `X-EUrouter-Categories` |
| Required | Optional |
| Format | Comma-separated, lowercase, hyphen-separated, max 30 characters each |
***
## Categories [#categories]
Categories are organized into four groups:
### Coding [#coding]
| Category | Description |
| -------------------- | --------------------------- |
| `cli-agent` | Command-line AI agents |
| `ide-extension` | IDE plugins and extensions |
| `cloud-agent` | Cloud-hosted coding agents |
| `programming-app` | General programming tools |
| `native-app-builder` | Native application builders |
### Creative [#creative]
| Category | Description |
| ------------------ | ------------------------ |
| `creative-writing` | Writing and storytelling |
| `video-gen` | Video generation tools |
| `image-gen` | Image generation tools |
### Productivity [#productivity]
| Category | Description |
| ------------------- | ------------------------- |
| `writing-assistant` | Writing and editing tools |
| `general-chat` | General-purpose chat apps |
| `personal-agent` | Personal AI assistants |
### Entertainment [#entertainment]
| Category | Description |
| ---------- | -------------------- |
| `roleplay` | Roleplay experiences |
| `game` | AI-powered games |
***
## Implementation Examples [#implementation-examples]
All three headers are optional, but including them enables all attribution features. Apps using localhost URLs must
include a title to be tracked.
### TypeScript (OpenAI SDK) [#typescript-openai-sdk]
```typescript
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.eurouter.ai/api/v1",
apiKey: process.env.EUROUTER_API_KEY,
defaultHeaders: {
"HTTP-Referer": "https://myapp.com",
"X-EUrouter-Title": "My AI App",
"X-EUrouter-Categories": "general-chat,productivity",
},
});
const response = await client.chat.completions.create({
model: "mistral-large-3",
messages: [{ role: "user", content: "Hello!" }],
});
```
### Python (OpenAI SDK) [#python-openai-sdk]
```python
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.eurouter.ai/api/v1",
api_key=os.environ["EUROUTER_API_KEY"],
default_headers={
"HTTP-Referer": "https://myapp.com",
"X-EUrouter-Title": "My AI App",
"X-EUrouter-Categories": "general-chat,productivity",
},
)
response = client.chat.completions.create(
model="mistral-large-3",
messages=[{"role": "user", "content": "Hello!"}],
)
```
### Python (Direct API) [#python-direct-api]
```python
import os
import requests
response = requests.post(
"https://api.eurouter.ai/api/v1/chat/completions",
headers={
"Authorization": f"Bearer {os.environ['EUROUTER_API_KEY']}",
"Content-Type": "application/json",
"HTTP-Referer": "https://myapp.com",
"X-EUrouter-Title": "My AI App",
"X-EUrouter-Categories": "general-chat,productivity",
},
json={
"model": "mistral-large-3",
"messages": [{"role": "user", "content": "Hello!"}],
},
)
```
### TypeScript (fetch) [#typescript-fetch]
```typescript
const response = await fetch("https://api.eurouter.ai/api/v1/chat/completions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.EUROUTER_API_KEY}`,
"Content-Type": "application/json",
"HTTP-Referer": "https://myapp.com",
"X-EUrouter-Title": "My AI App",
"X-EUrouter-Categories": "general-chat,productivity",
},
body: JSON.stringify({
model: "mistral-large-3",
messages: [{ role: "user", content: "Hello!" }],
}),
});
```
### cURL [#curl]
```bash
curl https://api.eurouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $EUROUTER_API_KEY" \
-H "Content-Type: application/json" \
-H "HTTP-Referer: https://myapp.com" \
-H "X-EUrouter-Title: My AI App" \
-H "X-EUrouter-Categories: general-chat,productivity" \
-d '{
"model": "mistral-large-3",
"messages": [{"role": "user", "content": "Hello!"}]
}'
```
***
## Where Your App Appears [#where-your-app-appears]
### App Rankings [#app-rankings]
Your app is listed on the [Rankings page](/rankings) with 7, 30, and 90-day leaderboards. Rankings use completed UTC days, are based on percentage share of total token volume, and refresh hourly.
### Model Apps Tabs [#model-apps-tabs]
Individual model pages show which apps are using that model, giving your app additional exposure to developers browsing the model catalog.
### Individual App Analytics [#individual-app-analytics]
View detailed analytics for your app including model usage trends, token breakdowns, and historical patterns.
***
## Best Practices [#best-practices]
### URL Requirements [#url-requirements]
* Use a consistent, publicly accessible URL for `HTTP-Referer`
* Avoid query parameters or fragments that change between requests
* For localhost development, always include a title header
### Title Guidelines [#title-guidelines]
* Keep titles concise and descriptive (under 50 characters)
* Avoid special characters or excessive formatting
* The title can be updated at any time by sending a new `X-EUrouter-Title` header
### Privacy Considerations [#privacy-considerations]
* The `HTTP-Referer` URL and app title are publicly visible in rankings
* Usage statistics are aggregated and do not expose individual request details
* You can stop appearing in rankings by removing the attribution headers
---
# Authentication
> How to authenticate with the EUrouter API using API keys.
Source: https://www.eurouter.ai/docs/concepts/authentication
***
## API keys [#api-keys]
API keys authenticate your requests to EUrouter. Each key is tied to your account and tracks usage for billing.
### Creating a key [#creating-a-key]
1. Go to your [Dashboard](/dashboard)
2. Navigate to **API Keys**
3. Click **Create New Key**
4. Copy and store it securely — you won't see it again
### Key format [#key-format]
```
eur_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```
***
## Using your API key [#using-your-api-key]
Include your key in the `Authorization` header:
```bash
curl https://api.eurouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $EUROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "mistral-large-3",
"messages": [{"role": "user", "content": "Hello!"}]
}'
```
### Environment variables [#environment-variables]
Store your key in an environment variable — never hardcode it:
```bash
export EUROUTER_API_KEY="eur_your_key_here"
```
***
## Security [#security]
### Keep keys secret [#keep-keys-secret]
* Never commit keys to version control
* Don't expose keys in client-side code
* Use environment variables or secret managers
### Use separate keys [#use-separate-keys]
Create different keys for different environments or applications. This makes it easier to rotate keys and track usage.
### Rotate regularly [#rotate-regularly]
If a key may have been exposed, delete it immediately and create a new one.
***
## Rate limits [#rate-limits]
API keys are subject to rate limits based on your plan:
| Plan | Requests per minute |
| ---- | ------------------- |
| Free | 20 |
| Plus | 60 |
| Pro | 150 |
The [pricing page](/pricing) is the source of truth for current plan limits.
### Rate limit headers [#rate-limit-headers]
Rate-limited responses return `429 Too Many Requests`. They can also include:
| Header | Description |
| ------------- | ------------------------------------------ |
| Header | Description |
| ------------- | ------------------------------------------ |
| `Retry-After` | Seconds until you can retry, when provided |
### When rate limited [#when-rate-limited]
If you exceed your limit, wait for the `Retry-After` period when provided. Otherwise, retry with exponential backoff and jitter.
### Need higher limits? [#need-higher-limits]
[Contact us](/contact) to discuss custom rate limits for your use case.
***
## Revoking keys [#revoking-keys]
To revoke a key:
1. Go to **API Keys** in your [Dashboard](/dashboard)
2. Find the key
3. Click **Delete**
Revoked keys are invalidated immediately and cannot be restored.
***
---
# Credits
> Understanding EUrouter's credit system for API usage and billing.
Source: https://www.eurouter.ai/docs/concepts/credits
***
## How billing works [#how-billing-works]
EUrouter separates platform access from AI usage:
* **Subscription** — A monthly plan that gives you access to EUrouter's routing, fallbacks, and EU infrastructure
* **Credits** — Prepaid balance used to pay for AI tokens at cost
***
## Adding credits [#adding-credits]
1. Go to your [Dashboard](/dashboard)
2. Navigate to **Billing**
3. Select an amount
4. Complete payment
Credits are added instantly.
***
## Pricing [#pricing]
You're charged based on token usage:
* **Input tokens** — The tokens in your prompt
* **Output tokens** — The tokens in the response (typically more expensive)
Each model has its own pricing. Check the [Models page](/models) for current rates.
### Currency conversion [#currency-conversion]
All costs are calculated in EUR. If a provider charges in USD or another currency, we convert it using the daily ECB exchange rate.
### Cost calculation [#cost-calculation]
```
Cost = (Input Tokens × Input Price) + (Output Tokens × Output Price)
```
***
## Minimum balance [#minimum-balance]
A minimum balance of **€0.10** is required to make requests. This ensures your requests can complete without interruption.
If your balance is too low, you'll receive a `402 Payment Required` error:
```json
{
"error": {
"code": "payment_required",
"message": "Insufficient balance"
}
}
```
***
## Checking your balance [#checking-your-balance]
### Via dashboard [#via-dashboard]
View your balance and usage history in the [Dashboard](/dashboard).
### Via API [#via-api]
```bash
curl https://api.eurouter.ai/api/v1/credits \
-H "Authorization: Bearer $EUROUTER_API_KEY"
```
***
## Usage tracking [#usage-tracking]
The dashboard shows usage breakdowns:
* **By model** — Which models consume the most credits
* **By time** — Daily, weekly, and monthly trends
* **By request** — Individual request costs
***
## Cost control [#cost-control]
### Usage limits [#usage-limits]
Set monthly spending limits to cap your usage.
### Tips [#tips]
* Use smaller models for simple tasks
* Keep prompts concise
* Monitor usage regularly
***
---
# Concepts
> Learn how EUrouter routes your requests, manages providers, and handles billing.
Source: https://www.eurouter.ai/docs/concepts
***
## Providers [#providers]
EUrouter connects to multiple European AI providers, including [Scaleway](https://www.scaleway.com/), [Mistral](https://mistral.ai/), [GreenPT](https://www.greenpt.ai/), Microsoft Foundry, and others. Instead of managing separate integrations, you use one API and EUrouter handles provider selection.
[Learn more about Providers →](/docs/concepts/providers)
***
## Models [#models]
Access leading AI models through EU-hosted infrastructure. Each model has specific capabilities, pricing, and context limits. Use the model catalog to find the right one for your use case.
[Learn more about Models →](/docs/concepts/models)
***
## Routing [#routing]
EUrouter automatically selects the best provider for each request based on availability, costs and performance. If a provider fails or is rate limited, we route to alternatives automatically.
[Learn more about Routing →](/docs/concepts/routing)
***
## Authentication [#authentication]
Secure your API access with API keys. Create keys in your dashboard, set usage limits, and monitor.
[Learn more about Authentication →](/docs/concepts/authentication)
***
## Credits [#credits]
EUrouter uses a prepaid credit system. Add credits to your account and pay only for what you use. Track spending in real-time through the dashboard.
[Learn more about Credits →](/docs/concepts/credits)
***
## Plugins [#plugins]
Configure account-level defaults for optional features such as Response Healing. Set defaults in the dashboard, override per request when allowed, and lock settings down with Prevent overrides.
[Learn more about Plugins →](/docs/concepts/plugins)
***
## Broadcast [#broadcast]
Automatically send traces from your API requests to external observability platforms like Langfuse, Datadog, and PostHog. Monitor and debug your LLM usage without any additional instrumentation.
[Learn more about Broadcast →](/docs/concepts/broadcast)
---
# Models
> Understanding AI models available through EUrouter.
Source: https://www.eurouter.ai/docs/concepts/models
***
## What are models? [#what-are-models]
Models are large language models (LLMs) — AI systems trained on vast amounts of text data to understand and generate human-like responses. When you send a prompt to EUrouter, a model processes your input and generates a completion.
Different models excel at different tasks. Some are optimized for speed, while others focus on complex reasoning, image understanding, or code generation. The live catalog is the source of truth for models currently available through EU-hosted infrastructure.
Browse all available models on the [Models page](/models).
***
## Model identifiers [#model-identifiers]
Each model has a unique identifier that you use in API requests:
```bash
curl https://api.eurouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $EUROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "mistral-large-3",
"messages": [{"role": "user", "content": "Hello!"}]
}'
```
EUrouter handles routing to the appropriate EU-based provider automatically.
***
## Capabilities [#capabilities]
Models support different capabilities depending on their architecture and training.
### Vision [#vision]
Vision-enabled models can process images alongside text. Send images in your messages and the model can describe, analyze, or answer questions about them.
### Tool calling [#tool-calling]
Models with tool calling (also known as function calling) can invoke external functions you define. This lets models interact with APIs, databases, or other systems.
### Streaming [#streaming]
Streaming returns tokens as they're generated instead of waiting for the full response. This creates a more responsive experience for chat applications.
### JSON output [#json-output]
Some models can reliably output structured JSON, making it easier to parse responses programmatically.
### Reasoning [#reasoning]
Reasoning-capable models spend additional compute before responding. They are useful for complex problems that benefit from multi-step analysis.
***
## Pricing [#pricing]
Model pricing is based on token usage:
* **Input tokens** — The tokens in your prompt
* **Output tokens** — The tokens in the model's response (typically more expensive)
Prices are in EUR credits. More capable models generally cost more per token. Check the [Models page](/models) for current pricing.
***
## Context length [#context-length]
Each model has a maximum context length — the total number of tokens it can process in a single request (input + output combined).
Larger context windows let you include more information in your prompts, but may come at higher cost.
***
## Choosing a model [#choosing-a-model]
Consider these factors:
* **Task complexity** — More capable models for complex reasoning
* **Speed** — Smaller models respond faster
* **Cost** — Balance capability with your budget
* **Features** — Check required capabilities (vision, tools, etc.)
***
## Browse models [#browse-models]
See all available models, capabilities, and pricing on the [Models page](/models).
***
---
# OAuth PKCE
> Let users authorize your app to use their EUrouter account and credits via OAuth PKCE.
Source: https://www.eurouter.ai/docs/concepts/oauth
OAuth PKCE (Proof Key for Code Exchange) lets third-party apps request API keys on behalf of EUrouter users. When a user authorizes your app, you receive an API key linked to their account. The user pays for their own usage with their credits.
***
## How it works [#how-it-works]
1. Your app generates a PKCE pair (a random `code_verifier` and its SHA-256 hash)
2. Your app redirects the user to EUrouter with the code challenge
3. The user sees a consent screen and approves access
4. EUrouter redirects back to your app with an authorization code
5. Your app exchanges the code and verifier for an API key
6. You use the key for API calls, billed to the user's credits
***
## Quick start [#quick-start]
This end-to-end example shows the full flow in JavaScript (Node.js):
```javascript
import { randomBytes, createHash } from "crypto";
// 1. Generate PKCE pair
const codeVerifier = randomBytes(32).toString("base64url");
const codeChallenge = createHash("sha256").update(codeVerifier).digest("base64url");
// 2. Redirect user to EUrouter (in your web app)
const authUrl = new URL("https://api.eurouter.ai/api/v1/auth");
authUrl.searchParams.set("callback_url", "https://your-app.com/callback");
authUrl.searchParams.set("code_challenge", codeChallenge);
authUrl.searchParams.set("code_challenge_method", "S256");
// redirect user to authUrl.toString()
// 3. On your /callback endpoint, extract the code
const code = new URL(request.url).searchParams.get("code");
// 4. Exchange code for API key (server-side)
const response = await fetch("https://api.eurouter.ai/api/v1/auth/keys", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
code,
code_verifier: codeVerifier,
code_challenge_method: "S256",
}),
});
const { key, user_id } = await response.json();
// Store the key securely — it's shown only once
```
***
## Step-by-step guide [#step-by-step-guide]
### Step 1: Generate PKCE credentials [#step-1-generate-pkce-credentials]
Create a `code_verifier` (a random string, 43-128 characters) and derive a `code_challenge` by hashing it with SHA-256.
#### JavaScript (Node.js) [#javascript-nodejs]
```javascript
import { randomBytes, createHash } from "crypto";
const codeVerifier = randomBytes(32).toString("base64url");
const codeChallenge = createHash("sha256").update(codeVerifier).digest("base64url");
// Store codeVerifier securely on your server — you'll need it in Step 4
```
#### Python [#python]
```python
import secrets
import hashlib
import base64
code_verifier = secrets.token_urlsafe(32)
code_challenge = (
base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode()).digest()
)
.decode()
.rstrip("=")
)
```
***
### Step 2: Redirect user to EUrouter [#step-2-redirect-user-to-eurouter]
Send the user's browser to the authorization endpoint with your PKCE challenge:
```
https://api.eurouter.ai/api/v1/auth
?callback_url=https://your-app.com/callback
&code_challenge={code_challenge}
&code_challenge_method=S256
```
| Parameter | Required | Description |
| ----------------------- | -------- | ------------------------------------------------------------------------------------------------------- |
| `callback_url` | Yes | Where to redirect after authorization. Must be HTTPS (HTTP allowed for `localhost` during development). |
| `code_challenge` | Yes | Base64url-encoded SHA-256 hash of the code verifier (43-128 characters). |
| `code_challenge_method` | No | `S256` (default, recommended) or `plain`. |
The user will see a consent screen showing your app's domain and what access is being requested.
***
### Step 3: Receive the authorization code [#step-3-receive-the-authorization-code]
After the user approves, they're redirected to your callback URL with a `code` parameter:
```
https://your-app.com/callback?code=abc123...
```
If the user denies the request:
```
https://your-app.com/callback?error=access_denied
```
***
### Step 4: Exchange code for API key [#step-4-exchange-code-for-api-key]
Make a server-side POST request to exchange the authorization code for an API key:
```bash
curl -X POST https://api.eurouter.ai/api/v1/auth/keys \
-H "Content-Type: application/json" \
-d '{
"code": "abc123...",
"code_verifier": "your_original_verifier",
"code_challenge_method": "S256"
}'
```
| Field | Required | Description |
| ----------------------- | -------- | ----------------------------------------------------------------------------------- |
| `code` | Yes | The authorization code received on the callback URL. |
| `code_verifier` | Yes | The original random string used to generate the code challenge (43-128 characters). |
| `code_challenge_method` | Yes | Must match the method used in Step 2 (`S256` or `plain`). |
**Response (200):**
```json
{
"key": "eur_abc123.secretxyz",
"user_id": "e1faa70b-..."
}
```
The `key` is shown only once. Store it securely.
***
### Step 5: Use the API key [#step-5-use-the-api-key]
The returned key works like any other EUrouter API key:
```bash
curl https://api.eurouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer eur_abc123.secretxyz" \
-H "Content-Type: application/json" \
-d '{
"model": "mistral-large-3",
"messages": [{"role": "user", "content": "Hello!"}]
}'
```
API usage is billed to the authorizing user's credits.
***
## Python example [#python-example]
Full flow in Python:
```python
import secrets
import hashlib
import base64
import requests
# Step 1: Generate PKCE pair
code_verifier = secrets.token_urlsafe(32)
code_challenge = (
base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode()).digest()
)
.decode()
.rstrip("=")
)
# Step 2: Build auth URL and redirect user
auth_url = (
f"https://api.eurouter.ai/api/v1/auth"
f"?callback_url=https://your-app.com/callback"
f"&code_challenge={code_challenge}"
f"&code_challenge_method=S256"
)
# Step 3: After user approves, extract code from callback URL
# Step 4: Exchange code for API key
resp = requests.post(
"https://api.eurouter.ai/api/v1/auth/keys",
json={
"code": code,
"code_verifier": code_verifier,
"code_challenge_method": "S256",
},
)
data = resp.json()
api_key = data["key"]
user_id = data["user_id"]
```
***
## Consent screen [#consent-screen]
When a user is redirected to EUrouter, they see a consent screen that shows:
* **Your app's domain** and a clear description of what's being requested
* **Permissions being granted**: an API key linked to their account that uses their credits
* **Where they'll be redirected** after authorizing
* **Deny** and **Authorize** buttons
Users must be signed in to their EUrouter account to authorize. If they're not signed in, they'll be prompted to sign in first.
***
## Error reference [#error-reference]
| Status | When | Message |
| ------ | -------------------------------------------------------------------------------- | ------------------------------- |
| `400` | `code_challenge_method` at exchange doesn't match what was used at authorization | `Invalid code_challenge_method` |
| `403` | Code is invalid, expired, already used, or the PKCE verifier is wrong | `Invalid code or code_verifier` |
| `405` | Wrong HTTP method (e.g., GET instead of POST on the exchange endpoint) | `Method Not Allowed` |
***
## Security notes [#security-notes]
* **Use S256** rather than `plain` for the code challenge method. Only use `plain` in environments that genuinely cannot compute SHA-256.
* **HTTPS required** for all callback URLs in production. `http://localhost` is allowed during development.
* **Authorization codes expire** after 10 minutes and are single-use. If the exchange fails, you must start the flow over.
* **Store the code verifier** on your server, never expose it in client-side code.
* **The API key is shown only once** in the exchange response. If you lose it, the user must go through the authorization flow again.
***
## FAQ [#faq]
Yes. Users can revoke OAuth-created keys from their [EUrouter dashboard](/dashboard), just like any other API key. Once revoked, the key stops working immediately.
API requests made with the key will return a `402 Payment Required` error. The user needs to add more credits to their
account. See [Credits](/docs/concepts/credits) for details.
Yes. HTTP is allowed for `localhost` callback URLs during development. All other callback URLs must use HTTPS.
OAuth-created keys follow the standard EUrouter key format: `eur_.`. They work with all EUrouter API endpoints and are indistinguishable from keys created manually in the dashboard.
Authorization codes are single-use and expire after 10 minutes. If the exchange fails for any reason, you need to start the entire flow over from Step 1 with a new PKCE pair.
***
---
# Plugins
> Configure account-level plugin defaults such as Response Healing.
Source: https://www.eurouter.ai/docs/concepts/plugins
***
## Overview [#overview]
Plugins let you set account-wide defaults for optional request-time features. Today EUrouter supports **Response Healing**, which repairs malformed JSON from structured-output requests.
These settings apply as defaults to all API requests for the active account:
* A **personal account** when your personal workspace is active
* An **organization account** when an organization workspace is active and you have admin access
Individual requests can override account defaults with the `plugins` parameter unless you enable **Prevent overrides** for a plugin.
***
## Response Healing [#response-healing]
Response Healing attempts to fix syntactically invalid JSON returned by supported structured-output requests. It does **not** validate against your JSON Schema or force missing fields — it only repairs JSON syntax when the model output is close enough to parse after repair.
### Dashboard default [#dashboard-default]
In **Plugins**, enable Response Healing for your account and optionally turn on **Prevent overrides** so per-request `plugins` settings are ignored.
### Per-request activation [#per-request-activation]
Enable Response Healing on a single request with the `plugins` array:
```json
{
"model": "gpt-4o",
"messages": [{ "role": "user", "content": "Return a JSON object with name and age." }],
"response_format": { "type": "json_object" },
"plugins": [{ "id": "response-healing" }]
}
```
Disable it explicitly for one request even when your account default is on:
```json
{
"plugins": [{ "id": "response-healing", "enabled": false }]
}
```
### Eligibility [#eligibility]
Response Healing runs only for **non-streaming** structured-output requests:
| API | Supported structured output |
| ---------------- | ---------------------------------------------------------- |
| Chat Completions | `response_format.type` of `json_object` or `json_schema` |
| Responses | the supported structured JSON equivalent for that endpoint |
It does not run for plain text completions, streaming responses, or requests without structured JSON output configured.
### Precedence [#precedence]
1. If **Prevent overrides** is enabled on the account default, the account setting always wins and request-level `plugins` entries for Response Healing are ignored.
2. Otherwise, an explicit per-request `plugins` entry overrides the account default.
3. If there is no per-request entry, the account default applies.
4. If neither is set, Response Healing stays off.
### Personal vs organization scope [#personal-vs-organization-scope]
* **Personal workspace:** any signed-in user can read and update their personal plugin defaults.
* **Organization workspace:** only organization admins (`org:manage`) can change organization plugin defaults. Non-admins cannot access the settings controls.
The active workspace in the dashboard determines which account owns the default being edited.
### Behavior and limitations [#behavior-and-limitations]
* Repairs are **best-effort JSON syntax fixes**, not schema validation.
* Valid JSON is returned unchanged.
* Unrepairable output is returned unchanged.
* Response Healing does **not** make an additional model call and does **not** add a separate charge.
### Example: account default on, request override allowed [#example-account-default-on-request-override-allowed]
Account default:
```json
{
"enabled": true,
"preventOverrides": false
}
```
Request that turns healing off for one call:
```json
{
"model": "gpt-4o",
"messages": [{ "role": "user", "content": "Return JSON." }],
"response_format": { "type": "json_object" },
"plugins": [{ "id": "response-healing", "enabled": false }]
}
```
### Example: prevent overrides enabled [#example-prevent-overrides-enabled]
Account default:
```json
{
"enabled": true,
"preventOverrides": true
}
```
A request that tries to disable healing is ignored — the account default remains in effect.
***
## Related settings [#related-settings]
* Configure defaults in the dashboard under **Plugins**
* API routes are proxied through the webapp; settings are stored and enforced by EUrouter core
---
# Providers
> How EUrouter connects to AI providers and routes your requests.
Source: https://www.eurouter.ai/docs/concepts/providers
***
## What are providers? [#what-are-providers]
Providers are the infrastructure companies that host and run the models you access through EUrouter. The live [Providers page](/providers) shows which providers and models are currently available.
***
## EU-based infrastructure [#eu-based-infrastructure]
EUrouter routes model inference to endpoints hosted in the European Union. Provider ownership, processing location, data collection, and retention are separate attributes; use routing preferences when your workload has stricter requirements.
***
## One API, multiple providers [#one-api-multiple-providers]
Each model available on EUrouter may be hosted by one or more providers. When you make a request, EUrouter automatically selects the best available provider based on:
* **Availability** — Is the provider currently operational?
* **Performance** — Which provider has the lowest latency?
* **Cost** — Which provider offers the best price?
* **Capacity** — Which provider has available capacity?
You don't need to think about providers when making requests. Just specify the model you want and EUrouter handles the rest.
### Provider order [#provider-order]
Use `provider.order` to try preferred providers first. Providers in the list are attempted in order before other eligible fallbacks.
### Restricting providers [#restricting-providers]
Use `provider.only` to restrict a request to an allowlist, or `provider.ignore` to exclude providers. You can also filter by EU ownership, processing region, collection policy, or retention period.
### Automatic failover [#automatic-failover]
When `allow_fallbacks` is enabled, EUrouter retries eligible providers for retryable failures such as timeouts, rate limits, and server errors. Disable fallbacks when strict provider pinning matters more than availability.
### Rate limiting [#rate-limiting]
Providers can apply their own capacity and rate limits. EUrouter accounts for provider health during routing and can fall back when a provider returns a retryable rate-limit response.
### Setting up your preferred and fallback providers [#setting-up-your-preferred-and-fallback-providers]
Set reusable defaults with [Routing Rules](/docs/concepts/routing), or pass a `provider` object in an individual request.
***
## Browse providers [#browse-providers]
See all available providers and their models on the [Providers page](/providers).
---
# Routing
> How EUrouter intelligently routes requests to the best available provider.
Source: https://www.eurouter.ai/docs/concepts/routing
***
## How routing works [#how-routing-works]
When you send a request to EUrouter, we don't just forward it to a single provider. Instead, we select the best available provider for your specific request based on health, price, and performance — then automatically retry with alternatives if something goes wrong.
This happens transparently. You specify a model, and EUrouter handles the rest.
***
## Provider selection [#provider-selection]
EUrouter selects providers in this order:
1. Find all providers that host the requested model
2. Filter out disabled or unhealthy providers
3. Apply your routing preferences (if specified)
4. Score remaining candidates by health and price
5. Select the highest-scoring provider
### Default scoring [#default-scoring]
By default, providers are scored using:
```
score = healthScore / (price)²
```
This balances reliability with a strong preference for cost-effective providers.
***
## Routing preferences [#routing-preferences]
You can control routing by adding a `provider` object to your request:
```json
{
"model": "mistral-large-3",
"messages": [{ "role": "user", "content": "Hello!" }],
"provider": {
"order": ["scaleway", "azure"],
"allow_fallbacks": true
}
}
```
### Available parameters [#available-parameters]
| Parameter | Type | Description |
| ----------------- | --------- | ------------------------------------------- |
| `order` | string\[] | Try providers in this order |
| `only` | string\[] | Only use these providers |
| `ignore` | string\[] | Never use these providers |
| `allow_fallbacks` | boolean | Fall back on failure (default: `true`) |
| `sort` | string | Sort by `price`, `latency`, or `throughput` |
### Provider order [#provider-order]
Use `order` to specify which providers to try first:
```json
{
"provider": {
"order": ["scaleway", "mistral", "azure"]
}
}
```
Providers in the list are tried in order. If all fail and `allow_fallbacks` is true, other providers are tried as fallbacks.
### Exclusive providers [#exclusive-providers]
Use `only` to restrict to specific providers:
```json
{
"provider": {
"only": ["scaleway"]
}
}
```
No other providers will be used, even as fallbacks.
### Excluding providers [#excluding-providers]
Use `ignore` to exclude specific providers:
```json
{
"provider": {
"ignore": ["azure"]
}
}
```
***
## Model variants [#model-variants]
Append a variant suffix to the model name for quick routing shortcuts:
| Variant | Example | Behavior |
| -------- | ----------------------- | ------------------------ |
| `:floor` | `mistral-large-3:floor` | Cheapest provider first |
| `:nitro` | `mistral-large-3:nitro` | Fastest throughput first |
| `:free` | `llama-3.1-8b:free` | Only free providers |
```json
{
"model": "mistral-large-3:floor",
"messages": [{ "role": "user", "content": "Hello!" }]
}
```
Variants are a shorthand — you can achieve the same with explicit `provider` parameters.
***
## Data residency [#data-residency]
By default, inference traffic is eligible only for providers configured with EU-hosted endpoints. Provider ownership, retention, and any [Broadcast](/docs/concepts/broadcast) destinations are separate controls. Use these request parameters when your policy is more specific:
| Parameter | Type | Description |
| -------------------- | ------- | ----------------------------------------------- |
| `data_residency` | string | Specific region (`eu`, `eea`, `de`, `fr`, etc.) |
| `eu_owned` | boolean | Only EEA-headquartered providers |
| `max_retention_days` | number | Maximum data retention (`0` = zero retention) |
| `data_collection` | string | `allow` or `deny` training on your data |
```json
{
"provider": {
"data_residency": "de",
"eu_owned": true,
"max_retention_days": 0
}
}
```
***
## Automatic fallbacks [#automatic-fallbacks]
If a provider fails, EUrouter automatically tries the next available provider. This happens for:
* Server errors (5xx)
* Rate limits (429)
* Timeouts (408)
* Network failures
Non-retryable errors (authentication failures, bad requests) fail immediately without fallback.
### Disabling fallbacks [#disabling-fallbacks]
Set `allow_fallbacks` to `false` to disable automatic retries:
```json
{
"provider": {
"order": ["scaleway"],
"allow_fallbacks": false
}
}
```
If Scaleway fails, the request fails — no other providers are tried.
### Streaming requests [#streaming-requests]
For streaming responses, fallback can only happen before the stream starts. Once tokens begin streaming, the connection is committed to that provider.
***
## Health monitoring [#health-monitoring]
EUrouter continuously monitors provider health:
* **Success rate** — Recent request success/failure ratio
* **Latency** — Response times
* **Error patterns** — Recurring issues
Unhealthy providers enter a cooldown period:
| Event | Cooldown |
| ------------------ | ----------- |
| Server error (5xx) | 30 seconds |
| Rate limit (429) | 60 seconds |
| Repeated failures | 120 seconds |
During cooldown, providers are deprioritized but not completely excluded.
***
## Response headers [#response-headers]
Every response includes routing information:
| Header | Description |
| -------------------- | ---------------------------------------------- |
| `x-provider-slug` | Provider that served the request |
| `x-routing-strategy` | Strategy used (`default`, `ordered`, `sorted`) |
| `x-model-variant` | Variant if specified |
| `x-fallback-count` | Number of fallback attempts |
Use these headers to understand routing decisions and debug issues.
***
---
# Error handling
> Handle API errors, retries, and rate limits safely.
Source: https://www.eurouter.ai/docs/guides/error-handling
EUrouter uses standard HTTP status codes. Read the response body for the error
message and keep the request ID from the response headers when contacting
support.
| Status | Meaning | Recommended action |
| ------ | ----------------------------------- | ------------------------------------------------------ |
| `400` | Invalid request | Fix the request; do not retry unchanged. |
| `401` | Missing or invalid API key | Check the `Authorization` header and key. |
| `402` | Insufficient credits | Add credits or change your billing setup. |
| `404` | Resource or model not found | Check the endpoint and live model catalog. |
| `408` | Request timed out | Retry with backoff if the operation is safe to replay. |
| `429` | Rate limit reached | Wait, honor `Retry-After` when present, then retry. |
| `5xx` | Temporary service or provider error | Retry with exponential backoff and jitter. |
## Retry example [#retry-example]
```javascript
async function requestWithRetry(url, options, maxAttempts = 4) {
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
const response = await fetch(url, options);
if (response.ok) return response;
const retryable = response.status === 408 || response.status === 429 || response.status >= 500;
if (!retryable || attempt === maxAttempts) {
const body = await response.text();
throw new Error(`EUrouter error ${response.status}: ${body}`);
}
const retryAfter = Number(response.headers.get("retry-after"));
const delay = Number.isFinite(retryAfter) ? retryAfter * 1_000 : 500 * 2 ** (attempt - 1) + Math.random() * 250;
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
```
Only retry operations that are safe to replay. For streaming requests, retry
only before the first response token arrives.
---
# OpenAI SDKs
> Use EUrouter with the official OpenAI JavaScript and Python SDKs.
Source: https://www.eurouter.ai/docs/guides/openai-sdk
EUrouter implements the OpenAI-compatible chat completions API. Point an OpenAI
SDK at EUrouter's base URL and keep the rest of your integration familiar.
Install the SDK:
```bash
npm install openai
```
Then create a client:
```javascript
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.EUROUTER_API_KEY,
baseURL: "https://api.eurouter.ai/api/v1",
});
const response = await client.chat.completions.create({
model: "mistral-large-3",
messages: [{ role: "user", content: "Why is the sky blue?" }],
});
console.log(response.choices[0].message.content);
```
Install the SDK:
```bash
pip install openai
```
Then create a client:
```python
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["EUROUTER_API_KEY"],
base_url="https://api.eurouter.ai/api/v1",
)
response = client.chat.completions.create(
model="mistral-large-3",
messages=[{"role": "user", "content": "Why is the sky blue?"}],
)
print(response.choices[0].message.content)
```
Keep API keys on the server. Never expose one in browser or mobile application
code.
## What changes from OpenAI? [#what-changes-from-openai]
* Set `baseURL` or `base_url` to `https://api.eurouter.ai/api/v1`.
* Use a model ID from the [live model catalog](/models).
* Use an EUrouter API key created in the [dashboard](/dashboard/keys).
Most chat-completions parameters work without other changes. Provider routing
controls are available through the request's `provider` field.
---
# Streaming responses
> Stream chat completion tokens from EUrouter using server-sent events.
Source: https://www.eurouter.ai/docs/guides/streaming
Set `stream` to `true` to receive tokens as they are generated. The endpoint
returns an SSE stream and ends it with `data: [DONE]`.
```javascript
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.EUROUTER_API_KEY,
baseURL: "https://api.eurouter.ai/api/v1",
});
const stream = await client.chat.completions.create({
model: "mistral-large-3",
messages: [{ role: "user", content: "Explain EU AI regulation briefly." }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
```
Use `--no-buffer` so cURL prints each event immediately:
```bash
curl --no-buffer https://api.eurouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $EUROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "mistral-large-3",
"messages": [{"role": "user", "content": "Explain EU AI regulation briefly."}],
"stream": true
}'
```
## Production considerations [#production-considerations]
* Stop reading after the `[DONE]` event.
* Handle a client disconnect by aborting the upstream request.
* Apply a connection timeout and an inactivity timeout separately.
* Retry only if no response tokens have been emitted. Once a stream starts,
replaying the request can duplicate output.
---
# Tool calling
> Let supported models request functions from your application.
Source: https://www.eurouter.ai/docs/guides/tool-calling
Tool calling lets a model produce structured arguments for a function your
application controls. Your code remains responsible for validating the
arguments, running the function, and sending its result back to the model.
```javascript
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.EUROUTER_API_KEY,
baseURL: "https://api.eurouter.ai/api/v1",
});
const messages = [{ role: "user", content: "What is the weather in Amsterdam?" }];
const first = await client.chat.completions.create({
model: "mistral-large-3",
messages,
tools: [
{
type: "function",
function: {
name: "get_weather",
description: "Get the current weather for a city",
parameters: {
type: "object",
properties: {
city: { type: "string" },
},
required: ["city"],
additionalProperties: false,
},
},
},
],
});
const assistantMessage = first.choices[0].message;
messages.push(assistantMessage);
for (const toolCall of assistantMessage.tool_calls ?? []) {
const args = JSON.parse(toolCall.function.arguments);
// Validate args before calling your own trusted function.
const result = await getWeather(args.city);
messages.push({
role: "tool",
tool_call_id: toolCall.id,
content: JSON.stringify(result),
});
}
const final = await client.chat.completions.create({
model: "mistral-large-3",
messages,
});
console.log(final.choices[0].message.content);
```
## Safety checklist [#safety-checklist]
* Treat tool arguments as untrusted input and validate them against a schema.
* Use an allowlist of tools; never execute a function name supplied directly by
the model.
* Require explicit user confirmation before destructive or costly actions.
* Apply authorization checks in the tool implementation, not in the prompt.
* Set timeouts and record tool outcomes for debugging.
Tool support varies by model. Check the [model catalog](/models) before relying
on it in production.
---
# Quickstart
> Get started with EUrouter in under 5 minutes.
Source: https://www.eurouter.ai/docs/quickstart
***
### Create an account [#create-an-account]
[Create an account](/sign-up) if you haven't already.
### Get your API key [#get-your-api-key]
1. Go to your [Dashboard](/dashboard)
2. Navigate to **API Keys**
3. Click **Create New Key**
4. Copy and store it securely — you won't see it again
Your key looks like this: `eur_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
### Set your environment variable [#set-your-environment-variable]
```bash
export EUROUTER_API_KEY="eur_your_key_here"
```
### Make your first request [#make-your-first-request]
```bash
curl https://api.eurouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $EUROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "mistral-large-3",
"messages": [
{"role": "user", "content": "Say hello in three languages!"}
]
}'
```
```javascript
const response = await fetch("https://api.eurouter.ai/api/v1/chat/completions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.EUROUTER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "mistral-large-3",
messages: [{ role: "user", content: "Say hello in three languages!" }],
}),
});
if (!response.ok) throw new Error(`EUrouter request failed: ${response.status}`);
console.log(await response.json());
```
```python
import os
import requests
response = requests.post(
"https://api.eurouter.ai/api/v1/chat/completions",
headers={"Authorization": f"Bearer {os.environ['EUROUTER_API_KEY']}"},
json={
"model": "mistral-large-3",
"messages": [{"role": "user", "content": "Say hello in three languages!"}],
},
timeout=60,
)
response.raise_for_status()
print(response.json())
```
### Verify the response [#verify-the-response]
A successful request returns `200 OK` with the generated message in `choices[0].message.content`. It also includes token usage and the provider selected by EUrouter.
If the request fails, confirm that the API key is present, the model exists in the [live catalog](/models), and your account has sufficient credits. See [Authentication](/docs/concepts/authentication) for `401` and `429` guidance.
***
## FAQ [#faq]
EUrouter provides access to 100+ models from OpenAI, Anthropic, Google, and more. Browse the full list in the [Model
Catalog](/models).
Model inference is routed to EU-hosted infrastructure. Optional features can send data elsewhere when you configure
them—for example, Broadcast forwards selected trace data to your chosen observability destination.
EUrouter uses a prepaid credit system. Add credits to your account and pay only for what you use. See
[Credits](/docs/concepts/credits) for details.
***
## Next steps [#next-steps]
Full endpoint documentation.
Learn more about the concept of models and how to use them.
Learn how EUrouter routes to providers.
***
---
# Claude Code Skill
> Add EUrouter integration knowledge to your AI coding assistant.
Source: https://www.eurouter.ai/docs/skill
***
## What is the EUrouter skill? [#what-is-the-eurouter-skill]
The EUrouter skill gives [Claude Code](https://claude.ai/code) full context on how to integrate EUrouter into your application. Once installed, your AI coding assistant can generate correct EUrouter code, configure GDPR-compliant routing, and answer integration questions — without you needing to look up docs.
***
## Install [#install]
```bash
npx skills add eurouter/eurouter-skill
```
That's it. The skill is now available in your Claude Code sessions.
***
## What you can ask [#what-you-can-ask]
With the skill installed, you can prompt Claude Code naturally:
* "Help me integrate EUrouter into my Python app"
* "Set up EUrouter with strict GDPR compliance"
* "Migrate my OpenAI calls to use EUrouter"
* "Show me how to use EUrouter streaming with EU data residency"
* "Create a routing rule that prefers Scaleway, then falls back to OVHcloud"
The skill covers the full EUrouter API surface — chat completions, embeddings, responses, routing rules, provider preferences, and key management.
***
## What the skill knows [#what-the-skill-knows]
How to switch from OpenAI or OpenRouter by changing two lines.
Provider preferences for data residency, EU-owned providers, zero retention, and more.
Every endpoint, field, and response header — chat, completions, embeddings, responses, models, keys, credits, and
routing rules.
Ready-to-use examples in Python, Node.js/TypeScript, and curl.
***
## How it works [#how-it-works]
The skill is a set of reference files that Claude Code loads automatically when relevant. It contains no executable code — just structured documentation that the assistant uses to generate accurate, up-to-date EUrouter integrations.
The reference files cover:
| File | Contents |
| ------------------------- | ------------------------------------------------------ |
| `endpoints.md` | Full API endpoint schemas and parameters |
| `provider-preferences.md` | Provider filtering, GDPR profiles, and routing options |
| `routing-rules.md` | Routing rules CRUD API |
| `code-examples-python.md` | 10 Python integration examples |
| `code-examples-node.md` | 10 Node.js/TypeScript integration examples |
| `code-examples-curl.md` | 9 curl examples |
***
## Example [#example]
After installing the skill, ask Claude Code to set up a GDPR-compliant integration:
```
> Help me add EUrouter to my Express app with strict EU data residency
```
Claude Code will generate working code using the correct base URL, authentication pattern, and provider preferences — no copy-pasting from docs required.
***
## Source [#source]
The skill is open source and available on GitHub:
[github.com/EUrouter/eurouter-skill](https://github.com/EUrouter/eurouter-skill)
***
---
# Datadog
> Send LLM traces to Datadog for monitoring and LLM Observability.
Source: https://www.eurouter.ai/docs/concepts/broadcast/datadog
***
[Datadog](https://www.datadoghq.com) is a cloud monitoring and analytics platform. With its [LLM Observability](https://www.datadoghq.com/product/llm-observability/) feature, you can track costs, latency, and quality of your LLM calls.
***
## Setup [#setup]
### Get your Datadog API key [#get-your-datadog-api-key]
1. Sign in to [Datadog](https://app.datadoghq.com)
2. Go to **Organization Settings > API Keys**
3. Create or copy an API key with **LLM Observability** permissions
See [Datadog API and Application Keys](https://docs.datadoghq.com/account_management/api-app-keys/) for details.
### Add the destination in EUrouter [#add-the-destination-in-eurouter]
1. Go to [Broadcast](/dashboard/broadcast) in your dashboard
2. Click **Add Destination** next to Datadog
3. Enter your **API key**
4. Set your **ML App** name to identify your application in Datadog
5. Update the **URL** if you're not in the EU region
6. Click **Test Connection** to verify
7. Click **Create**
***
## Configuration [#configuration]
| Field | Required | Description |
| ------- | -------- | ---------------------------------------------------------------------------- |
| API key | Yes | Datadog API key with LLM Observability permissions |
| ML App | No | Name for your application in Datadog LLM Observability |
| URL | No | Datadog API URL for your region. Default: `https://trace.agent.datadoghq.eu` |
| Headers | No | Custom HTTP headers (comma-separated `key=value` pairs) |
### Regional endpoints [#regional-endpoints]
| Region | URL |
| ------ | -------------------------------------------- |
| EU | `https://trace.agent.datadoghq.eu` (default) |
| US1 | `https://trace.agent.datadoghq.com` |
| US3 | `https://trace.agent.us3.datadoghq.com` |
| US5 | `https://trace.agent.us5.datadoghq.com` |
***
## What you'll see in Datadog [#what-youll-see-in-datadog]
Once connected, your LLM requests appear in Datadog LLM Observability with:
* Model and provider information
* Input/output messages (unless Privacy Mode is on)
* Token usage and estimated cost
* Latency metrics
* Your configured ML App name for filtering
***
## Learn more [#learn-more]
* [Datadog LLM Observability](https://www.datadoghq.com/product/llm-observability/)
* [Datadog API keys documentation](https://docs.datadoghq.com/account_management/api-app-keys/)
---
# Broadcast
> Automatically send traces of your LLM requests to external observability platforms.
Source: https://www.eurouter.ai/docs/concepts/broadcast
***
Broadcast allows you to automatically send traces from your EUrouter requests to external observability and analytics platforms. Monitor, debug, and analyze your LLM usage across your preferred tools without any additional instrumentation in your application code.
Broadcast is currently in **Beta**. We're actively adding new destinations and improving the feature.
***
## How it works [#how-it-works]
When you enable Broadcast, EUrouter captures trace data from your API requests and forwards it to your configured destinations. This happens asynchronously after each request completes, so it adds no latency to your API responses.
Each trace includes:
* **Request and response data** -- the input messages and model output
* **Token usage** -- prompt tokens, completion tokens, and totals
* **Cost information** -- the total cost of the request
* **Timing** -- request start time, end time, and latency
* **Model information** -- the model and provider used
***
## Getting started [#getting-started]
1. Go to [Broadcast](/dashboard/broadcast) in your dashboard
2. Click **Add Destination** next to the platform you want to connect
3. Enter your credentials (API keys, endpoints, etc.)
4. Use **Test Connection** to verify your setup
5. Click **Create** to save
Once saved, traces are sent automatically for all your API requests.
***
## Supported destinations [#supported-destinations]
| Destination | Description |
| -------------------------------------------------------- | ------------------------------------------ |
| [Langfuse](/docs/concepts/broadcast/langfuse) | Open-source LLM engineering platform |
| [LangWatch](/docs/concepts/broadcast/langwatch) | LLM observability and analytics |
| [Datadog](/docs/concepts/broadcast/datadog) | Cloud monitoring and analytics |
| [PostHog](/docs/concepts/broadcast/posthog) | Product analytics with LLM observability |
| [OpenTelemetry Collector](/docs/concepts/broadcast/otel) | Send traces to any OTLP-compatible backend |
| [Webhook](/docs/concepts/broadcast/webhook) | Raw OTLP JSON to any HTTPS endpoint |
***
## Configuration options [#configuration-options]
Every destination supports these settings:
### Sampling rate [#sampling-rate]
Control what percentage of traces are sent. A rate of 100% sends all traces, 50% sends roughly half. Useful for high-volume applications where you want to reduce costs on your observability platform.
### Privacy mode [#privacy-mode]
When enabled, prompt and completion text is stripped from traces before sending. Only metadata (model, tokens, cost, latency) is included. Useful for complying with data privacy regulations while still tracking usage metrics.
### API key filter [#api-key-filter]
Restrict a destination to only receive traces from specific API keys. This lets you:
* Route traces from different environments to different platforms
* Send production traces at a lower sampling rate than development
* Isolate monitoring for specific use cases
If no keys are selected, the destination receives traces from all your API keys.
***
## Security [#security]
Your destination credentials are encrypted before storage and only decrypted when sending traces. Traces are sent asynchronously, so enabling Broadcast does not affect your API response times.
---
# Langfuse
> Send LLM traces to Langfuse for observability, evaluation, and debugging.
Source: https://www.eurouter.ai/docs/concepts/broadcast/langfuse
***
[Langfuse](https://langfuse.com) is an open-source LLM engineering platform for tracing, evaluation, prompt management, and metrics. Connect it to EUrouter to automatically capture every request as a Langfuse trace.
***
## Setup [#setup]
### Get your Langfuse credentials [#get-your-langfuse-credentials]
1. Sign in to [Langfuse](https://cloud.langfuse.com) (or your self-hosted instance)
2. Go to **Settings** in your project
3. Copy your **Secret Key** and **Public Key**
For more details, see [Where are my Langfuse API keys?](https://langfuse.com/faq/all/where-are-langfuse-api-keys)
### Add the destination in EUrouter [#add-the-destination-in-eurouter]
1. Go to [Broadcast](/dashboard/broadcast) in your dashboard
2. Click **Add Destination** next to Langfuse
3. Enter your **Secret Key** and **Public Key**
4. If you're self-hosting, update the **Base URL** (default: `https://cloud.langfuse.com`)
5. Click **Test Connection** to verify
6. Click **Create**
***
## Configuration [#configuration]
| Field | Required | Description |
| ---------- | -------- | ------------------------------------------------------------------------------- |
| Secret Key | Yes | Your Langfuse secret key (`sk-lf-...`) |
| Public Key | Yes | Your Langfuse public key (`pk-lf-...`) |
| Base URL | No | Custom endpoint for self-hosted Langfuse. Default: `https://cloud.langfuse.com` |
***
## What you'll see in Langfuse [#what-youll-see-in-langfuse]
Once connected, each EUrouter request appears as a trace in Langfuse with:
* Model name and provider
* Input/output messages (unless Privacy Mode is on)
* Token usage and cost
* Latency and timing breakdown
* Any custom metadata passed via the `trace` field
***
## Custom metadata [#custom-metadata]
You can enrich Langfuse traces by including a `trace` field in your EUrouter requests:
```json
{
"model": "mistral-large-3",
"messages": [{ "role": "user", "content": "Hello!" }],
"trace": {
"trace_id": "workflow_123",
"trace_name": "Customer Support",
"generation_name": "Initial Response",
"user_id": "user_456",
"session_id": "session_789"
}
}
```
Langfuse recognizes these keys:
| Key | Description |
| ----------------- | ---------------------------------------------------- |
| `trace_id` | Group multiple requests into a single Langfuse trace |
| `trace_name` | Display name for the trace (defaults to model name) |
| `generation_name` | Name for the specific LLM generation |
| `user_id` | Associate the trace with a specific user |
| `session_id` | Group traces into a Langfuse session |
***
## Learn more [#learn-more]
* [Langfuse documentation](https://langfuse.com/docs)
* [Langfuse API keys FAQ](https://langfuse.com/faq/all/where-are-langfuse-api-keys)
---
# LangWatch
> Send LLM traces to LangWatch for observability and analytics.
Source: https://www.eurouter.ai/docs/concepts/broadcast/langwatch
***
[LangWatch](https://langwatch.ai) is an LLM observability and analytics platform that helps you monitor quality, costs, and performance of your AI applications.
***
## Setup [#setup]
### Get your LangWatch API key [#get-your-langwatch-api-key]
1. Sign in to [LangWatch](https://app.langwatch.ai)
2. Go to your project settings
3. Copy your **API key** (starts with `lw-`)
### Add the destination in EUrouter [#add-the-destination-in-eurouter]
1. Go to [Broadcast](/dashboard/broadcast) in your dashboard
2. Click **Add Destination** next to LangWatch
3. Enter your **API key**
4. Optionally update the **Endpoint** if using a custom instance
5. Click **Test Connection** to verify
6. Click **Create**
***
## Configuration [#configuration]
| Field | Required | Description |
| -------- | -------- | ---------------------------------------------------- |
| API key | Yes | Your LangWatch API key (`lw-...`) |
| Endpoint | No | Custom endpoint. Default: `https://app.langwatch.ai` |
***
## Learn more [#learn-more]
* [LangWatch documentation](https://docs.langwatch.ai)
---
# OpenTelemetry Collector
> Send LLM traces to any OTLP-compatible backend via an OpenTelemetry Collector.
Source: https://www.eurouter.ai/docs/concepts/broadcast/otel
***
The [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) is a vendor-agnostic proxy that can receive, process, and export telemetry data. Use this destination to forward EUrouter traces to any backend that supports OTLP, including Grafana Tempo, Jaeger, Zipkin, and more.
***
## Setup [#setup]
### Configure your OpenTelemetry Collector [#configure-your-opentelemetry-collector]
Make sure your collector is running and has an OTLP HTTP receiver enabled. A minimal config:
```yaml
receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4318
exporters:
# your backend exporter here
service:
pipelines:
traces:
receivers: [otlp]
exporters: [your-exporter]
```
### Add the destination in EUrouter [#add-the-destination-in-eurouter]
1. Go to [Broadcast](/dashboard/broadcast) in your dashboard
2. Click **Add Destination** next to OpenTelemetry Collector
3. Enter your collector's **Endpoint** (e.g., `https://otel.example.com:4318`)
4. Add an **API key** if your collector requires authentication
5. Add **Custom headers** if needed
6. Click **Test Connection** to verify
7. Click **Create**
***
## Configuration [#configuration]
| Field | Required | Description |
| -------------- | -------- | ----------------------------------------------------------------------- |
| Endpoint | Yes | OTLP HTTP endpoint of your collector (default: `http://localhost:4318`) |
| API key | No | Authentication key, if required |
| Custom headers | No | Additional HTTP headers (comma-separated `key=value` pairs) |
***
## Learn more [#learn-more]
* [OpenTelemetry Collector documentation](https://opentelemetry.io/docs/collector/)
* [OTLP specification](https://opentelemetry.io/docs/specs/otlp/)
---
# PostHog
> Send LLM traces to PostHog for product analytics and LLM observability.
Source: https://www.eurouter.ai/docs/concepts/broadcast/posthog
***
[PostHog](https://posthog.com) is an open-source product analytics platform. Connect it to EUrouter to track LLM usage alongside your other product events.
***
## Setup [#setup]
### Get your PostHog project API key [#get-your-posthog-project-api-key]
1. Sign in to [PostHog](https://app.posthog.com)
2. Go to **Settings > Project**
3. Copy your **Project API key** (starts with `phc_`)
### Add the destination in EUrouter [#add-the-destination-in-eurouter]
1. Go to [Broadcast](/dashboard/broadcast) in your dashboard
2. Click **Add Destination** next to PostHog
3. Enter your **Project API key**
4. Select your **Region** (EU or US), or enter a custom URL for self-hosted instances
5. Click **Test Connection** to verify
6. Click **Create**
***
## Configuration [#configuration]
| Field | Required | Description |
| --------------- | -------- | --------------------------------------------------------------------------------- |
| Project API key | Yes | Your PostHog project API key (`phc_...`) |
| Region | Yes | EU (`https://eu.i.posthog.com`), US (`https://us.i.posthog.com`), or a custom URL |
***
## Learn more [#learn-more]
* [PostHog documentation](https://posthog.com/docs)
---
# Webhook
> Send raw OTLP JSON traces to any HTTPS endpoint.
Source: https://www.eurouter.ai/docs/concepts/broadcast/webhook
***
The Webhook destination sends raw OTLP JSON payloads to any HTTPS endpoint you control. Use this when you want to build custom integrations or send traces to a platform that isn't directly supported.
***
## Setup [#setup]
### Prepare your endpoint [#prepare-your-endpoint]
Set up an HTTPS endpoint that accepts POST requests with a JSON body. The payload follows the [OTLP JSON format](https://opentelemetry.io/docs/specs/otlp/).
### Add the destination in EUrouter [#add-the-destination-in-eurouter]
1. Go to [Broadcast](/dashboard/broadcast) in your dashboard
2. Click **Add Destination** next to Webhook
3. Enter your **Endpoint** URL
4. Add an **API key** if your endpoint requires authentication
5. Add **Custom headers** if needed
6. Click **Test Connection** to verify
7. Click **Create**
***
## Configuration [#configuration]
| Field | Required | Description |
| -------------- | -------- | ----------------------------------------------------------- |
| Endpoint | Yes | HTTPS URL that accepts POST requests |
| API key | No | Authentication key, sent as a bearer token |
| Custom headers | No | Additional HTTP headers (comma-separated `key=value` pairs) |
***
## Payload format [#payload-format]
Each request sends an OTLP JSON payload containing trace spans with:
* Span attributes for model, provider, token usage, cost, and timing
* Resource attributes identifying EUrouter as the source
* Input/output events with message content (unless Privacy Mode is on)
***
## Learn more [#learn-more]
* [OTLP specification](https://opentelemetry.io/docs/specs/otlp/)