# Introduction

Run language models on Europe's cloud.

<figure><img src="/files/fPfpsHNb25QgguNIlbQL" alt=""><figcaption></figcaption></figure>

Built for developers and teams deploying AI applications, **Cortecs** combines **performance and compliance** in a unified platform. It provides a gateway to run large language models across a sovereign, scalable, and privacy-first network.

Built on the principles of [Sky Computing](https://sigops.org/s/conferences/hotos/2021/papers/hotos21-s02-stoica.pdf), it treats the cloud as a global utility instead of a single-vendor solution. Workloads are dynamically routed across multiple clouds, continuously optimized for speed, cost, and availability.

## Key benefits

Sky Inference brings the vision of Sky Computing into practical use, giving you a simple, unified way to run AI workloads across many clouds.

| Feature                        | Description                                                  |
| ------------------------------ | ------------------------------------------------------------ |
| **Unified API**                | One endpoint to access multiple cloud providers              |
| **Resilient by design**        | If a provider goes down, traffic automatically reroutes      |
| **Compliant by design**        | Fully compliant with GDPR and custom regulatory requirements |
| **Cost and performance aware** | Dynamically optimized routing for latency or cost-efficiency |
| **No subscription**            | Only pay for what you use. No subscription needed.           |

## Key concept

Our managed approach breaks with traditional routers, making Cortecs the only default GDPR-ready AI gateway. While other routers often do claim compliance, it is conventionally restricted to their routing only, leaving you liable for downstream transfers and triggering **legal reviews for every new model.**

Cortecs eliminates this risk by acting as your primary Data Processor and legally integrating these foundational models under our umbrella as Subprocessors. With just one DPA, you get instant access to the world's best AI models while we absorb the legal overhead and cross-border compliance, turning months of paperwork into immediate, compliant usage.

<figure><img src="/files/A1xIZEiuZFBRepxzKkWo" alt=""><figcaption></figcaption></figure>

## First steps

Ready to try **cortecs**? Here's how to get started:

1. Register at [cortecs.ai](https://cortecs.ai)
2. Explore the [Quick Start](https://docs.cortecs.ai/serverless-inference/quickstart) Guide
3. Join the Community:
   * 💬 [Join us on Discord](https://discord.gg/bPFEFcWBhp)
   * 📩 [Contact Support](mailto:support@cortecs.ai)
   * 🔐 [View our Privacy Policy](https://cortecs.ai/privacyPolicy)


# Quickstart

Get started using Europe's LLM Router

### 1. Register & Fund

Register at [cortecs.ai](https://cortecs.ai) and follow these steps to set up your account:

* Fill in your billing address on the [billing page](https://cortecs.ai/userArea/console?tab=billing) and press **Save**.
* Choose a payment method. Credit card is recommended for instant access to funds.
* Top up your account balance.
* Generate an **API key**.

For more detail, see [Payments & Billing](/features/payments-and-billing).

{% hint style="warning" %}
If your balance reaches zero, your requests will fail. To avoid this, use **Auto top-up** to set an amount that is automatically transferred when your balance falls below a specified threshold.
{% endhint %}

### 2. Choose a Model

Browse the [**Model Catalog**](https://cortecs.ai/serverlessModels) and select the model that fits your use case. Once you’re confident with the model's performance, you can proceed to obtain your access token and start sending requests via the API.

### 3. Send Your First Request

Sky Inference supports OpenAI-compatible calls. Here's are some usage examples:

{% tabs %}
{% tab title="Python" %}

```python
from openai import OpenAI

client = OpenAI(
  base_url="https://api.cortecs.ai/v1/",
  api_key="<API_KEY>",
)

completion = client.chat.completions.create(
  model="<MODEL_NAME>",
  messages=[
    {
      "role": "user",
      "content": "Tell me a joke."
    }
  ],
  extra_body={
    "preference": "balanced"
  }
)

print(completion.choices[0].message.content)
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
import OpenAI from "openai";

const openai = new OpenAI({
    baseURL: 'https://api.cortecs.ai/v1',
    apiKey: '<API_KEY>'
});

const completion = await openai.chat.completions.create({
  model: "<MODEL_NAME>",
  messages: [
    {
      role: "user",
      content: "Tell me a joke.",
    }
  ],
  extra_body: {
    "preference": "balanced"
  }
});

console.log(completion.choices[0].message.content);
```

{% endtab %}

{% tab title="Curl" %}

```bash
curl 'https://api.cortecs.ai/v1/chat/completions' \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer <API_KEY>' \
    -d '{
      "model": "<MODEL_NAME>",
      "messages": [
        { "role": "user", "content": "Tell me a joke." }
      ],
      "preference": "balanced"
    }'
```

{% endtab %}
{% endtabs %}

> When using the OpenAI compatible wrapper, **router** specific parameters need to be passed inside the `extra_body` parameter (eg. `preference` and `allowed_providers`). Find out more about supported parameters [here](/routing/advanced-usage#parameter-handling).

> Tip: Set `"preference"` to `"speed"`, `"cost"` or `"balanced"` to control routing behavior.

➡️ For more details on how routing and preferences work, check the [next chapter](/routing/advanced-usage).


# Web Console


# Billing

Add funds, manage payment methods, and review invoices

Add funds before sending API requests. Requests are charged against the available project balance. If the balance reaches zero, API requests fail until more funds are added.

Open [**Console > Billing**](https://cortecs.ai/userArea/console?tab=billing) to manage billing details, payment methods, top-ups, and invoices.

### Billing address

Fill in your billing address before adding funds. The Billing page supports **Private** and **Business** customer types. Business billing details include company and tax ID fields.

After entering the required details, click **Save**.

{% hint style="info" %}
For business accounts, tax IDs are validated by our payment provider through the official VIES VAT system of the European Commission. Validation may not be instant.
{% endhint %}

### Payment methods

Cortecs supports two top-up methods:

| Method                 | Best for                                                    | Balance availability                                                                                                   |
| ---------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **Credit Card**        | Most top-ups and immediate access                           | Funds are added after the card payment is validated in real time                                                       |
| **Pay by Wire (SEPA)** | Larger transactions or invoice-based enterprise procurement | Clearance is not instant and may take up to two business days after your bank has successfully transferred the payment |

#### Credit card

Credit card is the recommended payment method when you need immediate access to funds.

1. Select **Credit Card** under **Payment Methods**.
2. Add your card details.
3. Enter the top-up amount under **Balance Overview**.
4. Click **Top up**.

Once the card payment is validated, the top-up is applied to your balance.

{% hint style="info" %}
Auto top-up is available with credit card payments. Set an amount and threshold to automatically add funds when the balance drops below the configured threshold.
{% endhint %}

#### Pay by Wire (SEPA)

Pay by Wire is available for teams that prefer invoice-based payment and is recommended for larger transactions.

1. Select **Pay by Wire (SEPA)** under **Payment Methods**.
2. Enter the top-up amount under **Balance Overview**.
3. Click **Top up**.
4. Use the generated invoice details to complete the bank transfer.

Wire transfers are not validated in real time. Even after your bank has transferred the payment successfully, it may take up to two business days for Cortecs to clear it and add the funds to your balance.

{% hint style="warning" %}
Auto top-up is deactivated when using Pay by Wire. Use credit card if you need automatic refills or instant access to funds.
{% endhint %}

### Billing email and history

Set the **Billing Email** to choose where invoices and payment receipts are sent.

The **Billing History** table shows past top-ups with invoice and receipt downloads. Wire payments may appear as **Pending** until the payment has cleared.


# Bring Your Own Key \[BETA]

Bring your own provider API keys

{% hint style="warning" %}
This feature is currently in beta. For any issues or feedback, please contact us via [Discord](https://discord.com/invite/bPFEFcWBhp) or <support@cortecs.ai>.
{% endhint %}

BYOK lets you connect your own provider credentials to Cortecs, allowing requests to be routed through your own provider account.

When BYOK is enabled for a provider, Cortecs can use your API key either before or after the Cortecs-managed endpoints, depending on the selected usage mode. This gives you more control over provider billing and quota while still using Cortecs routing, model selection, and API interface.

### Adding a Provider Key

To add your own provider key:

1. Go to [**Settings**](https://cortecs.ai/userArea/console)
2. Select the [**BYOK**](https://cortecs.ai/userArea/console?tab=byok) tab
3. Click **Add provider key**
4. Select the provider
5. Enter the required credential fields
6. Choose a usage mode
7. Click **Save**

Only project administrators can add, update, or delete provider keys.

### BYOK Usage Modes

Cortecs supports two BYOK modes:

<table><thead><tr><th>Mode</th><th width="187">Behavior</th><th>Platform Key Used?</th><th>Balance Check</th></tr></thead><tbody><tr><td><strong>Prefer my key</strong></td><td>Cortecs tries your provider key first. If the request fails, Cortecs retries using the Cortecs-managed endpoints.</td><td>Yes, as backup</td><td>Required</td></tr><tr><td><strong>Fallback to my key</strong></td><td>Cortecs first tries its managed endpoints. If those endpoints fail, Cortecs retries the request using your provider key.</td><td>Yes, first</td><td>Required</td></tr></tbody></table>

### Billing

{% hint style="info" %}
There is currently no Cortecs usage fee for requests served using your own BYOK key. BYOK is currently available at no additional cost on the Cortecs platform.
{% endhint %}

### Supported Providers

#### Providers Requiring Only an API Key

For the following providers, you only need to provide the provider API key:

* Mistral
* OVH
* Nebius
* Tensorix
* Inceptron
* Infercom
* Ionos
* Scaleway
* AKI
* Berget

#### Amazon Bedrock

Cortecs currently supports Bedrock API keys for BYOK. AWS key authentication is not supported yet for BYOK, but may be added in the future.

#### Google Vertex AI

For Google Vertex AI, you need to provide a **Google service account JSON** file. You can download this file from the *Google Cloud Console*.

{% hint style="warning" %}
Ensure the service account has permission to access Vertex AI and the models you intend to use.
{% endhint %}

You do not need to specify a region. Cortecs automatically routes through supported EU regions. Ensure the models you plan to use are enabled in the appropriate EU regions of your Google Cloud project.

#### Azure OpenAI

Cortecs currently supports Azure OpenAI resources for BYOK using:

```
*.openai.azure.com
```

You need to provide:

* Resource name
* API key
* API version, optional

Cortecs automatically constructs the Azure endpoint from the resource name.

Example:

```
Resource name: my-azure-resource
Endpoint used: https://my-azure-resource.openai.azure.com
```

{% hint style="warning" %}
Azure OpenAI requires explicit model deployments. The deployment name in your Azure resource must match the Cortecs model ID you are requesting.
{% endhint %}

{% hint style="info" %}
More advanced BYOK configuration options will be added over time based on user needs.
{% endhint %}


# Budgets

Budgets let you control how much your project spends on AI requests. You can set spending limits at different levels for the whole project, per user, or per API key and choose daily, weekly, or monthly time windows. When a limit is reached, further requests are blocked until the window resets.

***

### Budget Scopes

A budget rule always targets a specific **scope** that determines what it applies to:

| Scope                      | What It Controls                                                    |
| -------------------------- | ------------------------------------------------------------------- |
| **Project**                | Total combined spend across the entire project                      |
| **User - Each user**       | A shared limit applied individually to every user in the project    |
| **User - Specific user**   | A limit for one specific user                                       |
| **API Key - Each API key** | A shared limit applied individually to every API key in the project |
| **API Key - Specific key** | A limit for one specific API key                                    |

{% hint style="info" %}
**"Each user"** and **"Each API key"** rules are especially useful as defaults. For example, setting an "Each user" monthly limit of €50 means every user in your project gets their own individual €50/month allowance without having to create a rule for each person.
{% endhint %}

{% hint style="warning" %}
**DEPRECATION NOTE** If you created your API key before the 1st of May 2026, you need to rotate it (delete and recreate) for API key-level budget tracking to work correctly. Keys created after that date work automatically.
{% endhint %}

***

### Budget Periods

Each rule uses one of three time windows. Spend counters reset automatically at the start of each window (UTC time):

| Period      | Resets At                   |
| ----------- | --------------------------- |
| **Daily**   | Midnight UTC                |
| **Weekly**  | Monday 00:00 UTC            |
| **Monthly** | 1st of the month, 00:00 UTC |

You can combine multiple periods on the same target. For instance, you could set both a daily limit of €5 and a monthly limit of €100 for a user.

***

### Viewing Budget Rules

To view the rules defined you need to:

1. Navigate to **Settings**
2. Select the [Budgets](https://cortecs.ai/userArea/console?tab=budgets) tab.

The Budgets tab in your project settings shows all active budget rules as cards. Each card displays:

* A **scope** (blue for Project, purple for User, amber for API Key)
* The **target** (e.g. Project, a user's name, or an API Key)
* The **period** (Monthly, Weekly, or Daily)
* The **current limit** in EUR
* A **utilization bar** showing how much of the budget has been used

<figure><img src="/files/Fa0BTngAbqPRIRx1z9bj" alt=""><figcaption></figcaption></figure>

***

### Creating a Budget Rule

{% hint style="warning" %}
Only project administrators can create, edit, or delete budget rules. Regular users can view the rules that apply to them and their own utilization.
{% endhint %}

1. Click the **"Add budget rule"** button at the bottom of the budget rules list
2. Configure the **Target** section:
   * **Scope**: Choose Project, User, or API Key
   * **User** *(appears for User and API Key scopes):* Select a specific user, or leave as "Each user" / "Each API key" to create a default rule
   * **API Key** *(appears when a specific user is selected under API Key scope):* Pick one of the user's API keys
3. Configure the **Limit** section:
   * **Period**: Choose Daily, Weekly, or Monthly
   * **Amount (EUR)**: Enter the spending cap (minimum €0.01)
4. Click **Create**

If a rule already exists for the same target, the new period will be added alongside existing ones rather than replacing them.

<figure><img src="/files/7km0k5WuhcLwoes0zHDx" alt=""><figcaption></figcaption></figure>

***

### Editing a Budget Rule

To update an existing rule's limit:

1. Change the **EUR amount** in the input field on the rule card
2. Click **Save**

The new limit takes effect immediately. Current utilization is not reset, only the cap changes.

***

### Deleting a Budget Rule

To remove a rule:

1. Click the **trash icon** on the rule card
2. The rule is removed immediately

If the rule was the last period on a target (e.g. you delete a user's only monthly limit), the entire budget configuration for that target is cleaned up automatically.

***

### What Happens When a Budget Is Exceeded

When a request would cause spending to exceed a budget limit:

* The request is **blocked** with an error message indicating which budget was exceeded
* The message includes the **time remaining** until the budget window resets
* Once the window resets (e.g. a new day, week, or month), spending is allowed again

{% hint style="info" %}
Budget limits are enforced across all applicable scopes. A request can be blocked by any matching rule for example, even if a user's personal budget has room, the request will be blocked if the project-wide budget is exhausted.
{% endhint %}

***

### Visibility for Non-Admin Users

Regular (non-admin) users can see:

* ✅ Project-wide budget rules and utilization
* ✅ Default rules ("Each user" / "Each API key") with **their own** utilization only
* ✅ Budget rules that specifically target them

They **cannot** see budget rules or utilization data for other users.

***

### Automatic Cleanup

Budget rules are automatically removed when their target no longer exists:

* Removing a **user** from the project deletes all budget rules targeting that user
* Deleting an **API key** deletes the budget rule for that key
* Deleting a **project** removes all associated budget rules


# Examples


# Structured Outputs

**Structured outputs** are a way to ensure that language model responses follow a **predefined format**. Instead of returning free-form text, the model is guided to generate responses in a consistent, machine-readable structure, making it easier to parse, validate, and integrate into applications.

{% tabs %}
{% tab title="Python" %}

```python
from openai import OpenAI
from pydantic import BaseModel

client = OpenAI(
  base_url="https://api.cortecs.ai/v1",
  api_key="<API_KEY>",
)

class CalendarEvent(BaseModel):
    name: str
    date: str
    participants: list[str]

completion = client.beta.chat.completions.parse(
  model="<MODEL_NAME>",
  messages=[
        {"role": "system", "content": "Extract the event information."},
        {"role": "user", "content": "Alice and Bob are going to a science fair on Friday."},
    ],
  response_format=CalendarEvent,
)

print(completion.choices[0].message.content)
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
import OpenAI from "openai";
import { zodResponseFormat } from "openai/helpers/zod";
import { z } from "zod";

const openai = new OpenAI({
    baseURL: 'https://api.cortecs.ai/v1',
    apiKey: '<API_KEY>'
});

const CalendarEvent = z.object({
  name: z.string(),
  date: z.string(),
  participants: z.array(z.string()),
});

const completion = await openai.chat.completions.parse({
  model: "<MODEL_NAME>",
  messages: [
    { role: "system", content: "Extract the event information." },
    { role: "user", content: "Alice and Bob are going to a science fair on Friday." },
  ],
  response_format: zodResponseFormat(CalendarEvent, "event"),
});

console.log(completion.choices[0].message.parsed);
```

{% endtab %}
{% endtabs %}


# Tool Calling

**Tool calls** (sometimes also called **function calls**) allow a language model to **suggest the use of external tools**. The model doesn't execute them directly, instead, it outputs a structured request indicating which tool to call and with what parameters. It's then up to the application or user to execute the tool and return the result back to the model, which incorporates it into a final, coherent response.

We provide a **standardized tool calling interface** across supported models and providers, making it easier to integrate tool use consistently across different backends.

For a more advanced example of tool use, see [these OpenAI docs](https://platform.openai.com/docs/guides/function-calling?api-mode=chat).

{% tabs %}
{% tab title="Python" %}

```python
from openai import OpenAI
from pydantic import BaseModel

client = OpenAI(
  base_url="https://api.cortecs.ai/v1",
  api_key="<API_KEY>",
)

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Get the current weather in a given city",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "City and state, e.g. San Francisco, CA"
                    }
                },
                "required": ["location"]
            }
        }
    }
]

completion = client.chat.completions.create(
    model="<MODEL_NAME>",
    messages=[
        {"role": "user", "content": "What’s the weather like in Paris?"}
    ],
    tools=tools,
    tool_choice="auto"
)

tool_call = completion.choices[0].message.tool_calls[0]
print("Tool name:", tool_call.function.name)
print("Arguments:", tool_call.function.arguments)
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.cortecs.ai/v1",
  apiKey: "<API_KEY>",
});

const tools = [
  {
    type: "function",
    function: {
      name: "get_weather",
      description: "Get the current weather in a given city",
      parameters: {
        type: "object",
        properties: {
          location: {
            type: "string",
            description: "City and state, e.g. San Francisco, CA",
          },
        },
        required: ["location"],
      },
    },
  },
];

const completion = await client.chat.completions.create({
  model: "<MODEL_NAME>",
  messages: [
    { role: "user", content: "What’s the weather like in Paris?" }
  ],
  tools: tools,
  tool_choice: "auto",
});

const toolCall = completion.choices[0].message.tool_calls[0];
console.log("Tool name:", toolCall.function.name);
console.log("Arguments:", toolCall.function.arguments);
```

{% endtab %}

{% tab title="Curl" %}

```bash
curl https://api.cortecs.ai/v1/chat/completions \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "<MODEL_NAME>",
    "messages": [
      {
        "role": "user",
        "content": "What’s the weather like in Paris?"
      }
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "get_weather",
          "description": "Get the current weather in a given city",
          "parameters": {
            "type": "object",
            "properties": {
              "location": {
                "type": "string",
                "description": "City and state, e.g. San Francisco, CA"
              }
            },
            "required": ["location"]
          }
        }
      }
    ],
    "tool_choice": "auto"
  }'

```

{% endtab %}
{% endtabs %}


# Audio Inputs

Audio Processing enables applications to **understand, generate, and reason over audio content** using multimodal AI models. The audio processing works through the **Completion endpoint** and supports models that handle **multiple modalities**, including audio.

To get a full list of supported models, visit [**cortecs.ai**](https://cortecs.ai/serverlessModels) and filter by the **Audio** tag.

{% hint style="info" %}
Audio format support depends on the provider. Check the model documentation for details.
{% endhint %}

{% tabs %}
{% tab title="Python" %}

```python
from openai import OpenAI
import base64

client = OpenAI(
  base_url="https://api.cortecs.ai/v1",
  api_key="<API_KEY>",
)

# Load and encode audio file
with open("path/to/audio_test.mp3", "rb") as f:
    audio_base64 = base64.b64encode(f.read()).decode('utf-8')

chat_response = client.chat.completions.create(
    model="gemini-2.5-pro",
    messages=[{
        "role": "user",
        "content": [
            {
                "type": "text",
                "text": "What is this file about?"
            },
            {
                "type": "input_audio",
                "input_audio": {
                    "data": audio_base64,
                    "format": "mp3"
                }
            },
        ]
    }]
)

print(chat_response)
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
import OpenAI from "openai";
import fs from "fs";

const client = new OpenAI({
  baseURL: "https://api.cortecs.ai/v1",
  apiKey: process.env.CORTECS_API_KEY,
});

// Load and encode audio file
const audioBuffer = fs.readFileSync("path/to/audio_test.mp3");
const audioBase64 = audioBuffer.toString("base64");

const chatResponse = await client.chat.completions.create({
  model: "gemini-2.5-pro",
  messages: [
    {
      role: "user",
      content: [
        {
          type: "text",
          text: "What is this file about?"
        },
        {
          type: "input_audio",
          input_audio: {
            data: audioBase64,
            format: "mp3"
          }
        }
      ]
    }
  ]
});

console.log(chatResponse);
```

{% endtab %}

{% tab title="Curl" %}

```bash
curl https://api.cortecs.ai/v1/chat/completions \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-2.5-pro",
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "text",
            "text": "What is this file about?"
          },
          {
            "type": "input_audio",
            "input_audio": {
              "data": "<BASE64_AUDIO_DATA>",
              "format": "mp3"
            }
          }
        ]
      }
    ]
  }'
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
**Note:** For a dedicated speech-to-text endpoint, see the [**Audio Transcription**](https://docs.cortecs.ai/features/images) page.
{% endhint %}


# Document Inputs

**Document inputs** let multimodal models analyze files together with text prompts. Common use cases include summarization, information extraction, question answering, and document comparison.

To explore available models, visit [cortecs.ai](https://cortecs.ai/serverlessModels?tags=Document) and filter by the **Document** tag.

{% hint style="info" %}
Supported document formats, file sizes, and page limits depend on the model and provider. The examples below send a PDF as Base64-encoded data.
{% endhint %}

## OpenAI Chat Completions API

{% tabs %}
{% tab title="Python" %}

```python
import base64
from pathlib import Path

from openai import OpenAI

client = OpenAI(
    base_url="https://api.cortecs.ai/v1",
    api_key="<API_KEY>",
)

pdf_base64 = base64.b64encode(
    Path("path/to/document.pdf").read_bytes()
).decode("utf-8")

completion = client.chat.completions.create(
    model="<MODEL_NAME>",
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "file",
                    "file": {
                        "filename": "document.pdf",
                        "file_data": f"data:application/pdf;base64,{pdf_base64}",
                    },
                },
                {
                    "type": "text",
                    "text": "Summarize the key points in this document.",
                },
            ],
        }
    ],
)

print(completion.choices[0].message.content)
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
import fs from "fs";
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.cortecs.ai/v1",
  apiKey: "<API_KEY>"
});

const pdfBase64 = fs
  .readFileSync("path/to/document.pdf")
  .toString("base64");

const completion = await client.chat.completions.create({
  model: "<MODEL_NAME>",
  messages: [
    {
      role: "user",
      content: [
        {
          type: "file",
          file: {
            filename: "document.pdf",
            file_data: `data:application/pdf;base64,${pdfBase64}`
          }
        },
        {
          type: "text",
          text: "Summarize the key points in this document."
        }
      ]
    }
  ]
});

console.log(completion.choices[0].message.content);
```

{% endtab %}

{% tab title="Curl" %}

```bash
pdf_base64=$(base64 < path/to/document.pdf | tr -d '\n')

curl 'https://api.cortecs.ai/v1/chat/completions' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <API_KEY>' \
  -d '{
    "model": "<MODEL_NAME>",
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "file",
            "file": {
              "filename": "document.pdf",
              "file_data": "data:application/pdf;base64,'"${pdf_base64}"'"
            }
          },
          {
            "type": "text",
            "text": "Summarize the key points in this document."
          }
        ]
      }
    ]
  }'
```

{% endtab %}
{% endtabs %}

## OpenAI Responses API

{% tabs %}
{% tab title="Python" %}

```python
import base64
from pathlib import Path

from openai import OpenAI

client = OpenAI(
    base_url="https://api.cortecs.ai/v1",
    api_key="<API_KEY>",
)

pdf_base64 = base64.b64encode(
    Path("path/to/document.pdf").read_bytes()
).decode("utf-8")

response = client.responses.create(
    model="<MODEL_NAME>",
    input=[
        {
            "role": "user",
            "content": [
                {
                    "type": "input_file",
                    "filename": "document.pdf",
                    "file_data": f"data:application/pdf;base64,{pdf_base64}",
                },
                {
                    "type": "input_text",
                    "text": "Summarize the key points in this document.",
                },
            ],
        }
    ],
)

print(response.output_text)
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
import fs from "fs";
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.cortecs.ai/v1",
  apiKey: "<API_KEY>"
});

const pdfBase64 = fs
  .readFileSync("path/to/document.pdf")
  .toString("base64");

const response = await client.responses.create({
  model: "<MODEL_NAME>",
  input: [
    {
      role: "user",
      content: [
        {
          type: "input_file",
          filename: "document.pdf",
          file_data: `data:application/pdf;base64,${pdfBase64}`
        },
        {
          type: "input_text",
          text: "Summarize the key points in this document."
        }
      ]
    }
  ]
});

console.log(response.output_text);
```

{% endtab %}

{% tab title="Curl" %}

```bash
pdf_base64=$(base64 < path/to/document.pdf | tr -d '\n')

curl 'https://api.cortecs.ai/v1/responses' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <API_KEY>' \
  -d '{
    "model": "<MODEL_NAME>",
    "input": [
      {
        "role": "user",
        "content": [
          {
            "type": "input_file",
            "filename": "document.pdf",
            "file_data": "data:application/pdf;base64,'"${pdf_base64}"'"
          },
          {
            "type": "input_text",
            "text": "Summarize the key points in this document."
          }
        ]
      }
    ]
  }'
```

{% endtab %}
{% endtabs %}

## Anthropic Messages API

{% tabs %}
{% tab title="Python" %}

```python
import base64
from pathlib import Path

from anthropic import Anthropic

client = Anthropic(
    base_url="https://api.cortecs.ai",
    api_key="<API_KEY>",
)

pdf_base64 = base64.b64encode(
    Path("path/to/document.pdf").read_bytes()
).decode("utf-8")

message = client.messages.create(
    model="<MODEL_NAME>",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "document",
                    "source": {
                        "type": "base64",
                        "media_type": "application/pdf",
                        "data": pdf_base64,
                    },
                },
                {
                    "type": "text",
                    "text": "Summarize the key points in this document.",
                },
            ],
        }
    ],
)

print("\n".join(block.text for block in message.content if block.type == "text"))
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
import fs from "fs";
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({
  baseURL: "https://api.cortecs.ai",
  apiKey: "<API_KEY>"
});

const pdfBase64 = fs
  .readFileSync("path/to/document.pdf")
  .toString("base64");

const message = await client.messages.create({
  model: "<MODEL_NAME>",
  max_tokens: 1024,
  messages: [
    {
      role: "user",
      content: [
        {
          type: "document",
          source: {
            type: "base64",
            media_type: "application/pdf",
            data: pdfBase64
          }
        },
        {
          type: "text",
          text: "Summarize the key points in this document."
        }
      ]
    }
  ]
});

console.log(
  message.content
    .filter((block) => block.type === "text")
    .map((block) => block.text)
    .join("\n")
);
```

{% endtab %}

{% tab title="Curl" %}

```bash
pdf_base64=$(base64 < path/to/document.pdf | tr -d '\n')

curl 'https://api.cortecs.ai/v1/messages' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <API_KEY>' \
  -H 'anthropic-version: 2023-06-01' \
  -d '{
    "model": "<MODEL_NAME>",
    "max_tokens": 1024,
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "document",
            "source": {
              "type": "base64",
              "media_type": "application/pdf",
              "data": "'"${pdf_base64}"'"
            }
          },
          {
            "type": "text",
            "text": "Summarize the key points in this document."
          }
        ]
      }
    ]
  }'
```

{% endtab %}
{% endtabs %}


# Image Inputs

Many models support processing **image inputs**. This lets you combine text and images for richer, multimodal interactions. To get a full list of models, visit [cortecs.ai](https://cortecs.ai/serverlessModels) and filter by the **Image** tag.

**Code Samples:**

* **Using Image URLs:**

You can send images directly by referencing a public image URL.

{% tabs %}
{% tab title="Python" %}

```python
from openai import OpenAI

client = OpenAI(
  base_url="https://api.cortecs.ai/v1",
  api_key="<API_KEY>",
)

completion = client.chat.completions.create(
  model="<MODEL_NAME>",
  messages=[
      {
        "role": "user",
        "content": [
          {
            "type": "text",
            "text": "What is in this image?"
          },
          {
            "type": "image_url",
            "image_url": {
              "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
            }
          }
        ]
      }
    ],
)

print(completion.choices[0].message.content)
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
import OpenAI from "openai";

const openai = new OpenAI({
    baseURL: 'https://api.cortecs.ai/v1',
    apiKey: '<API_KEY>'
});

const completion = await openai.chat.completions.create({
  model: "<MODEL_NAME>",
  messages: [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "What is in this image?"
        },
        {
          "type": "image_url",
          "image_url": {
            "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
          }
        }
      ]
    }
  ]
});

console.log(completion.choices[0].message.content);
```

{% endtab %}

{% tab title="Curl" %}

```bash
curl 'https://api.cortecs.ai/v1/chat/completions' \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer <API_KEY>' \
    -d '{
      "model": "<MODEL_NAME>",
      "messages": [
        {
          "role": "user",
          "content": [
            {
              "type": "text",
              "text": "What is in this image?"
            },
            {
              "type": "image_url",
              "image_url": {
                "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
              }
            }
          ]
        }
       ]
     }'
```

{% endtab %}
{% endtabs %}

* **Using Base64 Encoded Images:**

For local or private images that are not publicly accessible, you can embed the image using Base64 encoding.

{% tabs %}
{% tab title="Python" %}

```python
from openai import OpenAI
import base64

with open("path/to/image.png", "rb") as image_file:
    base64_image = base64.b64encode(image_file.read()).decode("utf-8")

client = OpenAI(
    base_url="https://api.cortecs.ai/v1",
    api_key="<API_KEY>",
)


completion = client.chat.completions.create(
    model="<MODEL_NAME>",
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": "What is in this image?"
                },
                {
                    "type": "image_url",
                    "image_url": {
                        "url": f"data:image/png;base64,{base64_image}"
                    }
                }
            ]
        }
    ],
)

print(completion.choices[0].message.content)

```

{% endtab %}

{% tab title="Node.js" %}

```javascript
import fs from "fs";
import OpenAI from "openai";


const imageBuffer = fs.readFileSync("path/to/image.png");
const base64Image = imageBuffer.toString("base64");

const openai = new OpenAI({
  baseURL: "https://api.cortecs.ai/v1",
  apiKey: "<API_KEY>"
});

const completion = await openai.chat.completions.create({
  model: "<MODEL_NAME>",
  messages: [
    {
      role: "user",
      content: [
        {
          type: "text",
          text: "What is in this image?"
        },
        {
          type: "image_url",
          image_url: {
            url: `data:image/png;base64,${base64Image}`
          }
        }
      ]
    }
  ]
});

console.log(completion.choices[0].message.content);

```

{% endtab %}

{% tab title="Curl" %}

```bash
base64_image=$(base64 -w 0 path/to/image.png)

curl 'https://api.cortecs.ai/v1/chat/completions' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <API_KEY>' \
  -d '{
    "model": "<MODEL_NAME>",
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "text",
            "text": "What is in this image?"
          },
          {
            "type": "image_url",
            "image_url": {
              "url": "data:image/png;base64,'"${base64_image}"'"
            }
          }
        ]
      }
    ]
  }'

```

{% endtab %}
{% endtabs %}


# Image Generation

**Image generation** creates images from natural-language prompts, enabling applications such as illustrations, product concepts, marketing assets, and visual prototypes.

To explore available models, visit [cortecs.ai](https://cortecs.ai/serverlessModels?tags=Image-Gen) and filter by the **Image-Gen** tag.

### Example usage

{% tabs %}
{% tab title="Python" %}

```python
import base64
from pathlib import Path

from openai import OpenAI

client = OpenAI(
    base_url="https://api.cortecs.ai/v1",
    api_key="<API_KEY>",
)

response = client.images.generate(
    model="gemini-2.5-flash-image",
    prompt="Generate an image of a blue circle on a white background.",
)

image_base64 = next(
    (image.b64_json for image in response.data if image.b64_json),
    None,
)

if image_base64 is None:
    raise RuntimeError("The response did not contain a Base64-encoded image.")

output_path = Path("generated-image.png")
output_path.write_bytes(base64.b64decode(image_base64))
print(f"Saved image to {output_path.resolve()}")
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
import fs from "fs";
import OpenAI from "openai";

const openai = new OpenAI({
  baseURL: "https://api.cortecs.ai/v1",
  apiKey: "<API_KEY>"
});

const response = await openai.images.generate({
  model: "gemini-2.5-flash-image",
  prompt: "Generate an image of a blue circle on a white background."
});

const imageBase64 = response.data.find((image) => image.b64_json)?.b64_json;

if (!imageBase64) {
  throw new Error("The response did not contain a Base64-encoded image.");
}

await fs.promises.writeFile(
  "generated-image.png",
  Buffer.from(imageBase64, "base64")
);

console.log("Saved image to generated-image.png");
```

{% endtab %}

{% tab title="Curl" %}

```bash
curl 'https://api.cortecs.ai/v1/images/generations' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <API_KEY>' \
  -d '{
    "model": "gemini-2.5-flash-image",
    "prompt": "Generate an image of a blue circle on a white background."
  }' \
  | jq -r '.data[] | select(.b64_json != null) | .b64_json' \
  | base64 --decode > generated-image.png
```

{% endtab %}
{% endtabs %}


# Embeddings

**Embeddings** are numerical vectors that represent text’s meaning, enabling machines to compare and analyze language. They power tasks like **search**, **classification**, and **recommendations** by capturing semantic relationships in a compact form.

To get a full list of embedding models visit [cortecs.ai](https://cortecs.ai/serverlessModels) and filter by the **Embedding** tag.

{% tabs %}
{% tab title="Python" %}

```python
from openai import OpenAI

client = OpenAI(
  base_url="https://api.cortecs.ai/v1",
  api_key="<API_KEY>",
)

response = client.embeddings.create(
    input="Your text string goes here",
    model="<MODEL_NAME>"
)

print(response.data[0].embedding)
```

{% endtab %}

{% tab title="Node.js" %}

<pre class="language-javascript"><code class="lang-javascript"><strong>import OpenAI from "openai";
</strong>
const openai = new OpenAI({
    baseURL: 'https://api.cortecs.ai/v1',
    apiKey: '&#x3C;API_KEY>'
});

const embedding = await openai.embeddings.create({
  model: "&#x3C;MODEL_NAME>",
  input: "Your text string goes here"
});

console.log(embedding);
</code></pre>

{% endtab %}

{% tab title="Curl" %}

```bash
curl https://api.cortecs.ai/v1/embeddings \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <API_KEY>" \
  -d '{
    "input": "Your text string goes here",
    "model": "<MODEL_NAME>"
  }'
```

{% endtab %}
{% endtabs %}


# Reasoning

## Reasoning

Reasoning allows language models to perform deeper, structured thinking before producing a final answer. How this reasoning is exposed or whether it appears at all depends entirely on the model provider.

Some models reveal part of their thinking process, while others keep it hidden but still use it internally.

### **What Is Reasoning?**

Reasoning refers to the model’s deeper analytical process: evaluating options, forming intermediate steps, and then producing a final answer.

\
**Note:** Depending on the model provider, this reasoning may appear in various formats:

* mixed into the normal `content`
* in a dedicated `reasoning_content` field
* inside structured `thinking_blocks` (only returned for Anthropic models)

Other models keep their chain-of-thought hidden but still support configurable reasoning behavior.

### **Controlling Reasoning**

To provide a consistent experience across providers that support it, Cortecs accepts:

```
"reasoning_effort": "low" | "medium" | "high"
```

This parameter represents **how much reasoning effort** you want the model to use.

* If the provider supports configurable reasoning, Cortecs translates the value appropriately.
* If the provider does *not* support adjustable reasoning, the parameter is simply ignored.
* If the provider uses reasoning by default, the parameter may still help increase or reduce thinking depth.

**When to choose which level?**

* **Use low** if you want fast responses, low cost, or the task is simple.
* **Use medium** for general use: coding, explanations, multi-step tasks.
* **Use high** for reasoning-intensive tasks: debugging, strategy, multi-constraint planning, mathematical reasoning, or anything requiring precision.

### **Provider Behavior**

Different model families use different mechanisms for reasoning. Below is how Cortecs handles `reasoning_effort` for each provider.

#### **Anthropic**

{% hint style="info" %}
**Model support:** Support for adaptive and extended thinking depends on the Anthropic model. Some newer models support adaptive thinking only and reject `thinking.type: "enabled"`. See Anthropic’s [supported-model configuration table](https://platform.claude.com/docs/en/build-with-claude/thinking-troubleshooting#supported-models) before choosing a mode.
{% endhint %}

**Adaptive Thinking**

Anthropic models that support adaptive thinking (for example, Claude Opus 5) can dynamically decide how much reasoning to use. If adaptive thinking is not enabled by default for a model, enable it by passing a `thinking` parameter:

```python
extra_body={
    "thinking": {"type": "adaptive"}
}
```

You can control the effort level with Anthropic's `output_config.effort` parameter:

```python
extra_body={
    "thinking": {"type": "adaptive"},
    "output_config": {"effort": "high"}
}
```

Alternatively, use the standard `reasoning_effort` parameter. Cortecs maps it to `output_config.effort` for supported Anthropic models.

For models that allow thinking to be turned off, disable it with:

```python
extra_body={
    "thinking": {"type": "disabled"}
}
```

To configure whether reasoning content is included in the response, set `thinking.display` to `"summarized"` or `"omitted"`:

```python
extra_body={
    "thinking": {
        "type": "adaptive",
        "display": "summarized"
    }
}
```

Use `"summarized"` to return summarized reasoning content or `"omitted"` to hide it. For newer adaptive-thinking models such as Claude Opus 5, the default is `"omitted"`.

**Extended Thinking**

Anthropic models that support extended thinking use `budget_tokens` to set a fixed reasoning budget. Enable it by setting `thinking.type` to `"enabled"`:

```python
extra_body={
    "thinking": {
        "type": "enabled",
        "budget_tokens": 1024
    }
}
```

For these models, Cortecs can convert the user’s `reasoning_effort` input into the appropriate reasoning budget:

| Effort | Budget |
| ------ | ------ |
| low    | 1024   |
| medium | 2048   |
| high   | 4096   |

#### **Azure OpenAI**

Azure OpenAI follows the same general behavior as OpenAI:

* Azure OpenAI does **not expose raw reasoning tokens**, so the internal chain of thought is never shown.
* For newer reasoning-capable models (such as GPT-5), you can still use `reasoning_effort` to control the depth of reasoning; older ones ignore it.

#### **Google Gemini (2.5 and later)**

* Reasoning is **enabled by default**.
* Provided efforts are converted into a reasoning budget similar to [Anthropic](https://docs.cortecs.ai/features/reasoning-beta#anthropic).

**Custom Budget (Gemini)**

Users may specify a custom **numeric budget** similar to [Anthropic](https://docs.cortecs.ai/features/reasoning-beta#anthropic).

#### **Mistral Models**

* Some models support `reasoning_effort` (e.g., Magistral, mistral-small), while others ignore it.
* When supported, it enables internal reasoning and may return `reasoning_content`.

#### **AKI Models**

* `reasoning_effort` is not supported by all models. When supported, accepted values are `none`, `low`, `medium`, and `high` Otherwise, the parameter is ignored.

#### **Tensorix Models**

* Reasoning capabilities differ per model family.
* Cortecs accepts the standard `reasoning_effort` parameter and automatically maps it to Tensorix’s format.
* Some model families (e.g., Kimi) always use **reasoning** and do not support configurable reasoning effort. Others (e.g., DeepSeek) have reasoning disabled by default and require `reasoning_effort` to be provided to enable it.

**Reasoning** behavior varies across models, and not all reasoning steps may be visible in the response. Using `reasoning_effort` lets you request deeper or lighter reasoning when supported, while Cortecs automatically handles internal budgets where applicable. Keep in mind that some models expose reasoning explicitly, others hide it, and some include it by default.

{% hint style="info" %}
Reasoning token counts are currently included in the completion token count.
{% endhint %}


# Audio Transcription

**Transcription** converts spoken audio into written text, enabling applications such as speech-to-text, meeting notes, subtitles, and voice analytics. It supports multiple audio formats and languages, making it easy to extract accurate text from audio content.

To get a full list of embedding models visit [cortecs.ai](https://cortecs.ai/serverlessModels) and filter by the **Transcription** tag.

{% tabs %}
{% tab title="Python" %}

```python
from openai import OpenAI

client = OpenAI(
    base_url="https://api.cortecs.ai/v1/audio/transcriptions",
    api_key="<API_KEY>",
)

with open("audio_file.wav", "rb") as audio_file:
    response = client.audio.transcriptions.create(
        file=audio_file,
        model="<MODEL_NAME>"
    )

print(response)
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
import fs from 'fs';

const filepath = 'audio_file.wav';

const formData = new FormData();
formData.append('file', new Blob([fs.readFileSync(filepath)]), 'audio_file.wav');
formData.append('model', '<MODEL_NAME>');

const response = await fetch('https://api.cortecs.ai/v1/audio/transcriptions', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer <API_KEY>',
  },
  body: formData,
});

const data = await response.json();
console.log(data);
```

{% endtab %}

{% tab title="Curl" %}

```bash
curl https://api.cortecs.ai/v1/audio/transcriptions \
  -H "Authorization: Bearer <API_KEY>" \
  -F "file=@audio_file.wav" \
  -F "model=<MODEL_NAME>"
```

{% endtab %}
{% endtabs %}

> **Note:** File format support depends on the provider. Check the model documentation for details.


# Text to Speech \[BETA]

{% hint style="warning" %}
This endpoint is currently in beta. For any issues or feedback, please contact us via [Discord](https://discord.com/invite/bPFEFcWBhp) or <support@cortecs.ai>.
{% endhint %}

**Text-to-Speech (TTS)** converts written text into natural-sounding audio, enabling applications such as voice assistants, audiobook generation, accessibility tools, and real-time speech synthesis. It supports multiple voices and providers, allowing flexible audio generation tailored to different use cases.

To explore available models, visit [cortecs.ai](https://cortecs.ai/serverlessModels?tags=Speech) and filter by the **Speech** tag.

### Example usage

{% tabs %}
{% tab title="Python" %}

```python
from openai import OpenAI 

client = OpenAI( 
    base_url="https://api.cortecs.ai/v1", 
    api_key="<API_KEY>", 
) 

response = client.audio.speech.create( 
    model="chatterbox-turbo", 
    input="Hello, this is a text-to-speech test.", 
    voice="<provider_voice>" 
) 

response.stream_to_file("speech.mp3")
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
import OpenAI from "openai";
import fs from "fs";

const openai = new OpenAI({
    baseURL: 'https://api.cortecs.ai/v1',
    apiKey: '<API_KEY>'
});

const response = await openai.audio.speech.create({
  model: "chatterbox-turbo",
  input: "Hello, this is a text-to-speech test.",
  voice: "<provider_voice>"
});

const buffer = Buffer.from(await response.arrayBuffer());
await fs.promises.writeFile("speech.mp3", buffer);
```

{% endtab %}

{% tab title="Curl" %}

```bash
curl 'https://api.cortecs.ai/v1/audio/speech' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <API_KEY>' \
  -d '{
    "model": "chatterbox-turbo",
    "input": "Hello, this is a text-to-speech test.",
    "voice": "<provider_voice>"
  }' \
  --output speech.mp3
```

{% endtab %}
{% endtabs %}

### **Voice Support**

Each provider supports different voice styles. Available options depend on the selected provider.

| Provider | Example Voice           |
| -------- | ----------------------- |
| Mistral  | `en_paul_neutral`       |
| Tensorix | `Emily.wav`             |
| OVH      | `"English-US.Female-1"` |

These are only example voices. Each provider may offer additional voice options depending on the model and configuration. Always check the provider documentation for the full list of available voices.

{% hint style="info" %}
Text-to-Speech models are priced **per character** of input text.
{% endhint %}


# Routing


# Routing Concept

Behind the scenes of LLM routing

## Overview

The **LLM Router** is designed to deliver **fast, reliable, and cost-efficient inference** without requiring you to manage infrastructure or providers. Based on your request and preferences, **cortecs** automatically selects the best available provider for you.

## How it works?

Routing happens in two main steps:

1. **Filtering:**\
   We instantly exclude providers that do not meet your request’s minimum requirements:
   * **Compliance Requirements:** Providers that don’t meet your compliance requirements are automatically excluded.
   * **Availability**: Unavailable or unresponsive providers are excluded.
   * **Context Length & Token Limit**: Providers that cannot handle the requested context length or number of output tokens are removed from consideration.
2. **Ranking:**\
   We use **predictive machine learning models** to estimate each provider's throughput and performance based on your request. Eligible providers are then ranked using your selected routing preference:

   | Preference             | Behavior                              |
   | ---------------------- | ------------------------------------- |
   | **Speed**              | Selects the fastest provider          |
   | **Cost**               | Select the most cost-efficient option |
   | **Balanced (default)** | Optimize for a mix of speed and cost  |

You can set your routing preference in two ways:

* In the **API request body**: `"preference": "speed" | "cost" | "balanced"`
* In the **model web interface**, use the **Select Preference** button.

If you don’t specify a preference, the system defaults to **balanced**.

> 🔄 **Automatic Fallback:** If the top-ranked provider fails during processing, the router instantly retries with the next best option to **maximize** **uptime** and **minimizes failed requests**.

## Usage Cost

Response data typically includes a usage object that tracks `prompt_tokens`, `completion_tokens`, and `total_tokens` for every request. Cortecs enhances this metadata by adding cost information directly. This allows you to monitor the exact monetary spend of an inference call.

The `usage` field contains the following fields:

* `cost`: The overall cost of the call
* `cost_details`:
  * `prompt_cost`: Cost of the prompt tokens (input)
  * `completion_cost`: Cost of the completion tokens (output)
  * `prompt_audio_cost`: Cost of the audio

{% hint style="info" %}
**Note:** The costs returned represent credits where 1€ = 1.000.000 credits.
{% endhint %}

## Parameter Handling

**Cortecs** allows you to define preferred parameters across multiple providers. If a provider encounters an error while processing your parameters, the response is returned directly from that provider. Additionally, you can also pass router-specific parameters to control routing behavior.

**Router Specific Parameters**

The following parameters control the behaviour of the router:

* `preference`: Choose between `speed`, `cost` and `balanced`. Default is `balanced`.
* `allowed_providers`: A list of allowed providers. The router will only use the specified providers and will not fall back to others. By default, all available providers are allowed.
* `eu_native`: A boolean indicating whether to restrict routing to EU-based and regulated providers. Default is `false`. Even when set to `false`, all routing remains GDPR compliant.
* `allow_quantization`: A boolean indicating whether to allow quantized endpoints. Default is `true`. Quantization is a model compression technique that typically preserves full accuracy, so enabling this option usually does not impact model performance.
* `timeout`: An integer representing the request timeout period in seconds. It defaults to `600`, providing a 10-minute window before the request is terminated.

> When using these parameters with an **OpenAI-compatible wrapper**, include them in the `extra_body` dictionary. See example [here](https://docs.cortecs.ai/routing/pages/KrJWsiiPgcnJPntXQvuY#id-4.-send-your-first-request).

#### **Other Parameters**

Including optional parameters in your request may reduce the likelihood of successful execution, as not all providers support every parameter. When unsupported parameters are included, some providers may reject the request or fail to process it correctly.

> 💡 **Tip:** To improve reliability and maximize compatibility across providers, include **only the parameters that are essential** for your use case.


# Model Fallback

Model Fallback ensures high availability by automatically retrying requests on alternative models when the primary model is temporarily unavailable due to **timeouts, provider outages, rate limits, etc.**

{% hint style="info" %}
Fallback is not triggered for **provider validation errors** (e.g., invalid, unsupported, or malformed request parameters). These errors are returned immediately without retrying other models.
{% endhint %}

## How It Works

Each model can have a **fallback model** configured.

When a request fails on the primary model:

1. The router tries the fallback model automatically
2. If that model also fails, the router continues down the **fallback chain**
3. The process stops as soon as a model succeeds

Fallback models can themselves have fallbacks, forming a chained retry sequence.

#### Example Fallback Chain

```json
devstral-2512 → devstral-small-2512 → devstral-small-2507
    (fails)          (fails)            (succeeds ✅)              
```

If all models in the fallback chain fail, you receive the **error details of the first attempted model.**

{% hint style="success" %}
**You only pay for the successful request and for the model that ultimately served the response.**
{% endhint %}

#### Via Web Console

1. Go to your [**Project Settings**](https://cortecs.ai/userArea/console?tab=inference) **→ Inference Section**.
2. Toggle **Model Fallback ON** ✅ to automatically retry failed requests using fallback models.

<figure><img src="/files/fKUpXjiNTU6EN4jqvJGJ" alt=""><figcaption></figcaption></figure>

3. Toggle **OFF** ❌ to disable fallback behavior. Requests will fail immediately if the primary model is unavailable.

<figure><img src="/files/fJnuy4q0BpznC5wXyMpl" alt=""><figcaption></figcaption></figure>

#### Via API

You can control this behavior directly in your requests using the `enable_model_fallback` parameter:

```json
{
  "model": "devstral-2512",
  "messages": [...],
  "enable_model_fallback": true
}
```

* true ✅ (default) → Fallback models are allowed
* false ❌ → Only the originally requested model is used

### Fallback Model Selection Logic

Fallback models are selected within the **same model family and capability tier** to maintain compatibility and predictable behavior.

* **Version Downgrade:** Newer versions fall back to older versions

```json
gpt-5.1 → gpt-5 → gpt-4.1 → gpt-4o → gpt-4o-mini
```

* **Size Downgrade:** Larger models fall back to smaller variants

<pre class="language-json"><code class="lang-json"><strong>gpt-oss-120b → gpt-oss-20b
</strong></code></pre>

* **Embedding Models:** Embedding models fall back only within the same embedding family to preserve vector space compatibility.

Here's the updated documentation page with the **Custom Fallback Chains** section added. Since the visualizer isn't available, here's the fully marked-up content you can paste into your docs system:

### Custom Fallback Chains

By default, fallback models are selected automatically as descirbed above. You can override this behavior by specifying your own ordered list of fallback models using the `fallbacks` request parameter.

{% hint style="info" %}
When `fallbacks` is provided, it **replaces** the default fallback mechanism entirely. The router will only attempt the models listed in the array, in order.
{% endhint %}

#### Request Parameter

| Parameter   | Type       | Description                                                                                                                                                  |
| ----------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `fallbacks` | `string[]` | An ordered list of model IDs to try if the primary model fails. Overrides the default fallback chain. Models are attempted left to right until one succeeds. |

#### Example

```json
{
  "model": "claude-opus4-8",
  "messages": [...],
  "fallbacks": ["claude-opus4-7", "claude-opus4-6"]
}
```

In this example, the router attempts models in this order:

```
claude-opus4-8 → claude-opus4-7 → claude-opus4-6
 (primary)        (fallback 1)     (fallback 2)
```

#### Behavior

* **Ordered retry:** Models in `fallbacks` are tried left to right; the router stops as soon as one succeeds.
* **Overrides defaults:** Providing `fallbacks` disables automatic family-based fallback selection entirely for that request.
* **Cross-family support:** Unlike default fallbacks, custom chains can span different model families.
* **Cost:** You are only billed for the model that successfully served the response.


# Prompt Caching

Prompt Caching allows you to reduce costs and latency by reusing previously processed prompt tokens. When supported by the provider, repeated parts of your input are served from cache instead of being reprocessed.

Caching is handled transparently at the provider level, the router automatically detects cache usage in API responses and applies the correct billing.

💡 **Note:** Not all providers support prompt caching. Behavior and pricing depend on the underlying provider.

### ⚙️ How It Works

When you send a request with a large or repeated prompt:

1. The provider may cache part of the input (typically the prefix)
2. On subsequent requests with the same prefix, cached tokens are reused
3. Cached tokens are billed at a reduced rate (or sometimes free)

The router detects caching via the `prompt_tokens_details` field and splits input tokens into three categories:

| Token Type            | Description                          | Billing                 |
| --------------------- | ------------------------------------ | ----------------------- |
| Text tokens           | Fresh input tokens (not cached)      | Standard input rate     |
| Cached tokens         | Tokens served from cache (cache hit) | Reduced cache-read rate |
| Cache creation tokens | Tokens written to cache              | Cache-write rate        |

#### Cost Calculation

```
input_cost = text_tokens × input_rate
           + cached_tokens × cache_read_rate
           + cache_creation_tokens × cache_write_rate
```

### 🔍 Cache usage fields

Each API response includes a `usage` object. When caching is active, you’ll see:

```
{
  "usage": {
    "completion_tokens": 3000,
    "prompt_tokens": 15000,
    "total_tokens": 18000,
    "prompt_tokens_details": {
      "cached_tokens": 10000,
      "cache_creation_tokens": 0
    },
    "cost_details": {
      "prompt_cost": 100,
      "cache_read_cost": 150,
      "cache_write_cost": 0,
      "completion_cost": 80
    }
  }
}
```

| Field                   | Description                             |
| ----------------------- | --------------------------------------- |
| `prompt_tokens`         | Total input tokens (includes all types) |
| `cached_tokens`         | Tokens served from cache (cache hit)    |
| `cache_creation_tokens` | Tokens written to cache                 |

When `cached_tokens > 0`, caching is active and cost savings apply.

### 🏢 Supported Providers

#### Amazon Bedrock (Claude models)

You can explicitly control caching using `cache_control`:

```python
model="claude-4-6-sonnet",
messages= [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "You are an expert analyst. Use the document below to answer my question."
        },
        {
          "type": "text",
          "text": "LONG DOCUMENT: ... (thousands of tokens)",
          "cache_control": { "type": "ephemeral" }
        },
        {
          "type": "text",
          "text": "Question: What are the 3 main insights from this document?"
        }
      ]
    }
  ]
```

* Minimum tokens: \~1024 (varies by model)
* Prompts below the minimum are not cached
* **TTL:** \~5–60minutes

#### Google Vertex (Gemini models)

Supports **automatic (implicit) caching:** no configuration required.

* Works with Gemini 2.5 Flash and Pro
* Minimum tokens:
  * Flash: \~1024
  * Pro: \~2048
* **TTL:** \~3–5 minutes

#### Azure (OpenAI models)

* Automatic caching (cannot be disabled)
* Applies to GPT-4o and newer models
* Requirements:
  * Minimum \~1024 tokens
  * First \~1024 tokens must be identical for cache hits
* **TTL:** \~5–60minutes

#### Mistral

* Automatic caching supported
* Cache read pricing is typically \~10% of the standard input cost

#### Inceptron

* Automatic caching supported
* Cache write may be free

#### Tensorix

* Automatic caching supported
* Cache reuse is **best-effort, not guaranteed** (cache hits depend on warm replica state and request routing across replicas)
* No explicit cache control or TTL exposed to users

#### Aki

* Automatic caching for supported models
* **TTL:** \~5 minutes

#### Other Providers

Prompt caching is **not currently supported**.

### 💡 Best practices for cache usage

* **Keep prompts stable:** Ensure the beginning of your prompt remains identical across requests
* **Use large shared context:** Place reusable content (documents, instructions) at the start
* **Avoid dynamic prefixes:** Changes at the beginning of the prompt prevent cache reuse
* **Leverage system messages:** Store static instructions or context there


# Auto Update \[BETA]

{% hint style="warning" %}
This endpoint is currently in beta. For any issues or feedback, please contact us via [Discord](https://discord.com/invite/bPFEFcWBhp) or <support@cortecs.ai>.
{% endhint %}

We organize our models into **model series**. Each series groups related model versions together under a shared name. When we release a new version within a series, we add it to that series on our platform.

By using the `:latest` tag on a series name, your application always points to the most recent model in that series no manual updates required.

### How It Works

{% hint style="warning" %}
**Work in progress.** Currently, available series are only exposed via the `model_series` field in the `/v1/models` endpoint. We will be integrating this data into the UI in an upcoming release.
{% endhint %}

Every model series has a `:latest` alias that always resolves to the newest available model in that series. When you use `:latest` in your requests, we automatically route you to the current latest model. As soon as we publish a new model to a series, any request using `:latest` will use that new model.

Instead of specifying a fixed model version, append `:latest` to the series name:

```json
{
  "model": "claude-sonnet-4:latest",
  "messages": [...]
}
```

That's all you need to do. From this point on, your application will automatically use the newest model in the `claude-sonnet-4` series whenever we release one.

#### Pinning to a Specific Version

If you need predictable, stable behavior you still can pin to a specific model version:

```json
{
  "model": "claude-sonnet-4-5",
  "messages": [...]
}
```

This version will remain unchanged until you explicitly update it.

### Things to Keep in Mind

**Behavior may change between versions.** New models in a series are generally improved, but responses may differ from a prior version. If your application depends on highly consistent output, consider pinning to a specific version and testing new models before adopting them.

**Updates happen immediately.** There is no gradual rollout when using `:latest` — once a new model is published to a series, all requests using `:latest` will use it.


# API


# API Compatibility

Choose the right Cortecs-compatible API

Cortecs exposes multiple compatible APIs at the same base URL:

```
https://api.cortecs.ai/v1
```

Send your Cortecs API key as a Bearer token. Use the exact model ID returned by the [Models API](/api-overview/models).

## Choose an API

| Workflow                                    | API                | Endpoint            | When to use it                                                                 |
| ------------------------------------------- | ------------------ | ------------------- | ------------------------------------------------------------------------------ |
| Agents, reasoning, and tool calling         | Responses \[BETA]  | `/responses`        | Preferred for new agent workflows when the client supports the Responses API   |
| General chat and broad client compatibility | Chat Completions   | `/chat/completions` | Fallback for clients that only implement the OpenAI Chat Completions format    |
| Anthropic-compatible clients                | Anthropic Messages | `/messages`         | Use for clients such as Claude Code that speak the Anthropic Messages protocol |
| Model and capability discovery              | Models             | `/models`           | Resolve current model IDs, modalities, context sizes and supported features    |

The three generation APIs do not use identical request or response shapes. For example, Responses accepts `input` and returns typed output items; the OpenAI SDK also provides `output_text`. Chat Completions accepts `messages` and returns `choices`.

{% hint style="warning" %}
OpenAI-compatible does not mean that every OpenAI-specific feature is available. Only use fields documented in the Cortecs API reference. In particular, the Cortecs Responses API does not currently document OpenAI-managed storage or conversation resources.
{% endhint %}

## Compatibility checklist

If a Responses integration does not work:

1. Confirm that the client sends requests to `/v1/responses`, not `/v1/chat/completions`.
2. Confirm that the selected model supports every requested capability in the Models API.
3. Remove OpenAI-specific fields that are not documented by Cortecs.
4. If the client only supports Chat Completions, switch to `/v1/chat/completions` and translate `input` to `messages`.
5. Use `/v1/messages` only when the client implements the Anthropic Messages format.

See the [Models API](/api-overview/models) for model discovery, [Advanced Usage](/routing/advanced-usage) for routing controls, [Model Fallback](/routing/model-fallback) for retry behavior, and [Security & Compliance](/security-and-compliance) for data-handling controls.


# Chat Completions

## Create a chat completion

> This endpoint creates a chat completion using the specified model.

```json
{"openapi":"3.0.0","info":{"title":"Cortecs Chat Completions API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"CompletionRequest":{"type":"object","description":"A request object for generating chat completions and controlling router behavior. This object contains suggested parameters to generate a response from the specified model. Many of the parameters are optional, and it is recommended to set them only if needed; however, you may include other parameters as required. Note that not all providers support the same set of parameters. Adding unsupported or unnecessary parameters can cause requests to fail or limit the providers able to process them.\n","properties":{"preference":{"type":"string","description":"The provider preference for handling the request.","enum":["speed","cost","balanced"]},"allowed_providers":{"type":"array","items":{"type":"string"},"description":"The providers that are allowed to be used for the completion.","nullable":true},"eu_native":{"type":"boolean","description":"Whether to consider only providers based and regulated withing the EU. Even when false, all our endpoints are GDPR compliant.","nullable":true},"allow_quantization":{"type":"boolean","description":"Whether to allow quantized endpoints.","nullable":true},"allow_zero_data_retention":{"type":"boolean","description":"Whether to use only ZDR providers.","nullable":true},"enable_model_fallback":{"type":"boolean","description":"Whether to allow model fallback when a model is currently unavailable.","nullable":true},"fallbacks":{"type":"array","items":{"type":"string"},"description":"The providers that are allowed to be used for the completion.","nullable":true},"model":{"type":"string","description":"The model to use for the completion."},"messages":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string","description":"The role of the message sender."},"content":{"type":"string","description":"The content of the message.","nullable":true}}}},"temperature":{"type":"number","description":"Controls randomness in the output. Higher values make the output more random.","default":0.7,"nullable":true},"max_tokens":{"type":"integer","description":"The maximum number of tokens to generate in the completion. It can also be referred to as `max_completion_tokens`. The limit depends on the model’s context size — it can’t exceed the context size minus your prompt length.","nullable":true},"top_p":{"type":"number","description":"Controls diversity via nucleus sampling - only tokens whose cumulative probability mass exceeds top_p are considered for sampling. For example, 0.1 means only tokens comprising the top 10% probability mass are considered. An alternative to temperature sampling - we recommend altering either top_p or temperature, but not both.","nullable":true},"frequency_penalty":{"type":"number","description":"Reduces the probability of generating a token based on its frequency in the text so far. The more times a token has appeared in the text so far, the lower the probability of it appearing in the completion.","default":0,"nullable":true},"presence_penalty":{"type":"number","description":"Reduces the probability of generating a token based on whether it has already appeared in the text so far. If a token has already appeared in the text so far, the probability of it appearing in the completion is reduced.","default":0,"nullable":true},"response_format":{"type":"object","description":"Specifies the format of the response.","nullable":true},"stop":{"type":"array","description":"Sequences where the API will stop generating further tokens.","items":{"type":"string"},"nullable":true},"stream":{"type":"boolean","description":"Whether to stream the response. The last chunk will contain the usage information.","default":false,"nullable":true},"logprobs":{"oneOf":[{"type":"integer"},{"type":"boolean"}],"description":"Whether to return log probabilities of the output tokens.","nullable":true},"seed":{"type":"integer","description":"Random seed for reproducible results.","nullable":true},"tools":{"type":"array","description":"List of tools available to the model.","items":{"type":"object"},"nullable":true},"tool_choice":{"type":"string","description":"Controls which tool the model should use. Only set if tools is not empty.","nullable":true},"n":{"type":"integer","description":"Number of completions to generate.","nullable":true},"prediction":{"type":"object","description":"Specify expected results, optimizing response times by leveraging known or predictable content. This approach is especially effective for updating text documents or code files with minimal changes, reducing latency while maintaining high-quality results.","nullable":true},"parallel_tool_calls":{"type":"boolean","description":"Whether to allow parallel tool calls."},"safe_prompt":{"type":"boolean","description":"Whether to inject a safety prompt before all conversations."}}},"CompletionResponse":{"type":"object","properties":{"object":{"type":"string","description":"The type of object returned"},"id":{"type":"string","description":"The unique identifier for the completion"},"created":{"type":"integer","description":"The timestamp when the completion was created"},"provider":{"type":"string","description":"The provider that generated the completion"},"model":{"type":"string","description":"The model that generated the completion"},"choices":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","description":"The index of the choice"},"message":{"type":"object","properties":{"role":{"type":"string","description":"The role of the message sender"},"content":{"type":"string","description":"The content of the message","nullable":true},"tool_calls":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The ID of the tool call"},"type":{"type":"string","description":"The type of the tool call"},"function":{"type":"object","description":"The function details for the tool call"}}},"nullable":true},"reasoning_content":{"type":"string","description":"Additional reasoning content","nullable":true}}},"finish_reason":{"type":"string","description":"The reason why the completion finished (stop, length, tool_calls, etc.)"},"logprobs":{"type":"object","description":"Log probabilities of the output tokens","nullable":true}}}},"usage":{"type":"object","description":"Token usage information. In streaming responses, this will be included only in the last chunk.","properties":{"prompt_tokens":{"type":"integer","description":"Number of tokens in the prompt"},"completion_tokens":{"type":"integer","description":"Number of tokens in the completion"},"total_tokens":{"type":"integer","description":"Total number of tokens used"}}},"prompt_logprobs":{"type":"object","description":"Log probabilities of the prompt tokens","nullable":true}}}}},"paths":{"/chat/completions":{"post":{"summary":"Create a chat completion","description":"This endpoint creates a chat completion using the specified model.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompletionRequest"}}}},"responses":{"200":{"description":"A chat completion.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompletionResponse"}}}},"500":{"description":"Internal server error."}}}}}}
```


# Embeddings

## Create an embedding

> This endpoint creates an embedding using the specified model.

```json
{"openapi":"3.0.0","info":{"title":"Cortecs Embeddings API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"EmbeddingRequest":{"type":"object","description":"A request object for generating embeddings. This object contains suggested parameters to generate an embedding from the specified model; however, you may include other parameters as required. Note that not all providers support the same set of parameters. Adding unsupported or unnecessary parameters can cause requests to fail or limit the providers able to process them.\n","properties":{"preference":{"type":"string","description":"The provider preference for handling the request.","enum":["speed","cost","balanced"]},"allowed_providers":{"type":"array","items":{"type":"string"},"description":"The providers that are allowed to be used for the completion.","nullable":true},"eu_native":{"type":"boolean","description":"Whether to consider only providers based and regulated withing the EU. Even when false, all our endpoints are GDPR compliant.","nullable":true},"allow_quantization":{"type":"boolean","description":"Whether to allow quantized endpoints.","nullable":true},"allow_zero_data_retention":{"type":"boolean","description":"Whether to use only ZDR providers.","nullable":true},"enable_model_fallback":{"type":"boolean","description":"Whether to allow model fallback when a model is currently unavailable.","nullable":true},"fallbacks":{"type":"array","items":{"type":"string"},"description":"The providers that are allowed to be used for the completion.","nullable":true},"model":{"type":"string","description":"The model to use for the embedding."},"input":{"oneOf":[{"type":"string","description":"A single input to embed."},{"type":"array","items":{"type":"string"},"description":"A list of inputs to embed."}]},"encoding_format":{"type":"string","description":"The encoding to use for the output.","enum":["float","base64"],"default":"float"}}},"EmbeddingResponse":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the completion"},"object":{"type":"string","description":"The type of object returned"},"created":{"type":"integer","description":"The timestamp when the completion was created"},"provider":{"type":"string","description":"The provider that generated the completion"},"model":{"type":"string","description":"The model that generated the embedding"},"data":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","description":"The index of the choice"},"object":{"type":"string","description":"The type of object returned"},"embedding":{"type":"array","items":{"type":"number"},"description":"The embedding"}}}},"usage":{"type":"object","description":"Token usage information.","properties":{"prompt_tokens":{"type":"integer","description":"Number of input tokens"},"completion_tokens":{"type":"integer","description":"Since embeddings are not tokens, this is always 0"},"total_tokens":{"type":"integer","description":"Total number of tokens used"}}}}}}},"paths":{"/embeddings":{"post":{"summary":"Create an embedding","description":"This endpoint creates an embedding using the specified model.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingRequest"}}}},"responses":{"200":{"description":"An embedding.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingResponse"}}}},"500":{"description":"Internal server error."}}}}}}
```


# Audio Transcription

## Create an audio transcription

> This endpoint transcribes audio into the input language using the specified model.

```json
{"openapi":"3.0.0","info":{"title":"Cortecs Audio Transcription API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"AudioTranscriptionRequest":{"type":"object","description":"A request object for generating audio transcriptions and controlling router behavior. This object contains suggested parameters to generate a response from the specified model. Many of the parameters are optional, and it is recommended to set them only if needed; however, you may include other parameters as required. Note that not all providers support the same set of parameters. Adding unsupported or unnecessary parameters can cause requests to fail or limit the providers able to process them.\n","properties":{"preference":{"type":"string","description":"The provider preference for handling the request.","enum":["speed","cost","balanced"]},"allowed_providers":{"type":"array","items":{"type":"string"},"description":"The providers that are allowed to be used for the completion.","nullable":true},"eu_native":{"type":"boolean","description":"Whether to consider only providers based and regulated withing the EU. Even when false, all our endpoints are GDPR compliant.","nullable":true},"allow_quantization":{"type":"boolean","description":"Whether to allow quantized endpoints.","nullable":true},"allow_zero_data_retention":{"type":"boolean","description":"Whether to use only ZDR providers.","nullable":true},"enable_model_fallback":{"type":"boolean","description":"Whether to allow model fallback when a model is currently unavailable.","nullable":true},"fallbacks":{"type":"array","items":{"type":"string"},"description":"The providers that are allowed to be used for the completion.","nullable":true},"file":{"type":"string","format":"binary","description":"The audio file object to transcribe."},"model":{"type":"string","description":"The model to use for the transcription."},"language":{"type":"string","description":"The language of the audio input, following ISO-639-1 format such as `en` for English, `fr` for French, `de` for German.\n","nullable":true},"prompt":{"type":"string","description":"An optional text to guide the model's style.\n","nullable":true},"response_format":{"type":"string","description":"The format of the transcript output.\n","nullable":true},"temperature":{"type":"number","description":"Controls randomness in the output. Higher values make the output more random.\n","nullable":true}},"required":["file","model"]},"AudioTranscriptionResponse":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the transcription"},"object":{"type":"string","description":"The type of object returned"},"created":{"type":"integer","description":"The timestamp when the transcription was created"},"provider":{"type":"string","description":"The provider that generated the transcription"},"model":{"type":"string","description":"The model that generated the transcription"},"text":{"type":"string","description":"The transcribed text."},"language":{"type":"string","description":"The language of the audio input.","nullable":true},"segments":{"type":"array","items":{"type":"object"},"description":"Segments of the transcribed text (may be unavailable for some providers).","nullable":true},"usage":{"type":"object","description":"Usage information showing audio duration.","properties":{"audio_duration_seconds":{"type":"number","description":"The duration of the audio in seconds."}}}}}}},"paths":{"/audio/transcriptions":{"post":{"summary":"Create an audio transcription","description":"This endpoint transcribes audio into the input language using the specified model.","operationId":"createAudioTranscription","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/AudioTranscriptionRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioTranscriptionResponse"}}}},"500":{"description":"Internal server error."}}}}}}
```


# Image Generation \[BETA]

{% hint style="info" %}
To get a full list of models, visit [cortecs.ai](https://cortecs.ai/) and filter by the **Image-Gen** tag.
{% endhint %}

## Generate images

> Generates one or more images from a text prompt using the specified image-generation model.

```json
{"openapi":"3.0.0","info":{"title":"Cortecs Image Generation API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"ImageGenerationRequest":{"type":"object","required":["model","prompt"],"properties":{"model":{"type":"string","description":"The image-generation model to use."},"prompt":{"type":"string","description":"A text description of the image to generate."},"n":{"type":"integer","minimum":1,"description":"Number of images to generate. Provider support may vary.","default":1},"size":{"type":"string","description":"Requested output dimensions in widthxheight form. Provider support may vary."},"response_format":{"type":"string","enum":["url","b64_json"],"description":"The format of each generated image. Provider support may vary."},"preference":{"type":"string","enum":["speed","cost","balanced"],"description":"The provider preference for handling the request."},"allowed_providers":{"type":"array","items":{"type":"string"},"description":"Providers that may process the request."},"eu_native":{"type":"boolean","description":"Whether to consider only providers based and regulated within the EU."},"allow_quantization":{"type":"boolean","description":"Whether to allow quantized endpoints."},"allow_zero_data_retention":{"type":"boolean","description":"Whether to use only zero-data-retention providers."},"enable_model_fallback":{"type":"boolean","description":"Whether to allow model fallback when the primary model is unavailable."},"fallbacks":{"type":"array","items":{"type":"string"},"description":"Alternative models to use when model fallback is enabled."}}},"ImageGenerationResponse":{"type":"object","required":["created","data"],"properties":{"created":{"type":"integer","description":"Unix timestamp when the images were created."},"data":{"type":"array","items":{"type":"object","properties":{"b64_json":{"type":"string","nullable":true,"description":"Base64-encoded image data when requested or returned by the provider."},"url":{"type":"string","nullable":true,"description":"Image URL when returned by the provider. Provider support may vary."},"revised_prompt":{"type":"string","nullable":true,"description":"Provider-revised prompt when available."}}}},"size":{"type":"string","nullable":true,"description":"Output dimensions when reported by the provider."},"usage":{"type":"object","properties":{"input_tokens":{"type":"integer","description":"Prompt input tokens when reported by the provider."},"output_tokens":{"type":"integer","description":"Output tokens when reported by the provider."},"total_tokens":{"type":"integer","description":"Total tokens when reported by the provider."},"cost":{"type":"number","description":"Total image-request cost in Cortecs microcredits."},"cost_details":{"type":"object","properties":{"image_generation_cost":{"type":"number","description":"Generated-image cost in Cortecs microcredits."},"prompt_cost":{"type":"number","description":"Prompt-input cost in Cortecs microcredits."}}}}}}}}},"paths":{"/images/generations":{"post":{"summary":"Generate images","description":"Generates one or more images from a text prompt using the specified image-generation model.","operationId":"createImageGeneration","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageGenerationRequest"}}}},"responses":{"200":{"description":"Generated images.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageGenerationResponse"}}}},"500":{"description":"Internal server error."}}}}}}
```


# Models

## Retrieve all available models

> This endpoint retrieves information about all available models. An optional API key can be provided via the \`Authorization\` header; when present, results are scoped to the models and providers available based on the inference settings. Provider filtering parameters mirror those accepted by the chat completions endpoint.

```json
{"openapi":"3.0.0","info":{"title":"Cortecs Model API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]},{}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Optional API key. When provided, the response is filtered to only include models and providers available based on the inference settings."}},"schemas":{"Models":{"type":"object","required":["object","data"],"properties":{"object":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Model"}}}},"Model":{"type":"object","required":["id","object","created","owned_by","pricing","providers"],"properties":{"id":{"type":"string"},"object":{"type":"string"},"created":{"type":"integer"},"owned_by":{"type":"string"},"description":{"type":"string","nullable":true},"pricing":{"$ref":"#/components/schemas/Pricing"},"providers":{"type":"array","items":{"type":"string"}},"context_size":{"type":"integer","description":"The maximum context size for this model.","nullable":true},"tags":{"type":"array","items":{"type":"string"},"nullable":true},"input_modalities":{"type":"array","description":"Supported input modalities (e.g. text, image, audio) derived from the model tags.","items":{"type":"string"}},"output_modalities":{"type":"array","description":"Supported output modalities (e.g. text, audio, embeddings) derived from the model tags.","items":{"type":"string"}},"supported_features":{"type":"array","description":"Features supported by this model across all available providers. Current values include `json_mode`, `reasoning`, and `tools`.","items":{"type":"string","enum":["json_mode","reasoning","tools"]}},"model_series":{"type":"array","items":{"type":"string"},"nullable":true},"providers_details":{"type":"object","description":"Per-provider breakdown keyed by provider name. Only present when `extended=true`, and always included by the single-model endpoint.","additionalProperties":{"$ref":"#/components/schemas/ProviderDetails"}}}},"Pricing":{"type":"object","description":"Pricing details. On the model level the cost numbers represent the minimums based on the cheapest provider available for this model.","required":["input_token","output_token","currency"],"properties":{"input_token":{"type":"number","description":"Input token cost per 1M tokens"},"output_token":{"type":"number","description":"Output token cost per 1M tokens"},"audio_cost":{"type":"number","description":"Audio cost per second (if supported)"},"speech_cost":{"type":"number","description":"Speech cost per 1M characters (if supported)"},"cache_read_cost":{"type":"number","description":"Cache read cost per 1M tokens (if supported)"},"cache_write_cost":{"type":"number","description":"Cache write cost per 1M tokens (if supported)"},"currency":{"type":"string","description":"The currency of the prices (e.g. EUR, USD)"}}},"ProviderDetails":{"type":"object","description":"Per-provider details, keyed by provider name. Only present when `extended=true` (and always for the single-model endpoint).","properties":{"pricing":{"$ref":"#/components/schemas/Pricing"},"quantization":{"type":"string","description":"The quantization applied by this provider, if any.","nullable":true},"context_size":{"type":"integer","description":"The context size offered by this provider.","nullable":true},"supported_features":{"type":"array","description":"Features supported by this provider. Current values include `json_mode`, `reasoning`, and `tools`.","items":{"type":"string","enum":["json_mode","reasoning","tools"]}}}}}},"paths":{"/models":{"get":{"summary":"Retrieve all available models","description":"This endpoint retrieves information about all available models. An optional API key can be provided via the `Authorization` header; when present, results are scoped to the models and providers available based on the inference settings. Provider filtering parameters mirror those accepted by the chat completions endpoint.","parameters":[{"name":"tag","in":"query","description":"One or more tags to filter by (defaults to ['Instruct'])","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"currency","in":"query","description":"ISO currency code for pricing conversion (defaults to 'EUR')","required":false,"schema":{"type":"string","default":"EUR"}},{"name":"allowed_providers","in":"query","description":"Restrict results to models that are available on at least one of the specified providers. Accepts multiple values.","required":false,"schema":{"type":"array","items":{"type":"string"}},"style":"form","explode":true},{"name":"eu_native","in":"query","description":"When `true`, only models hosted by providers that are based and regulated within the EU are returned. Even when `false`, all endpoints remain GDPR compliant.","required":false,"schema":{"type":"boolean"}},{"name":"allow_quantization","in":"query","description":"When `false`, quantized model variants are excluded from the results. Defaults to `true`.","required":false,"schema":{"type":"boolean"}},{"name":"allow_zero_data_retention","in":"query","description":"When `true`, only models available on providers that offer zero data retention (ZDR) are returned.","required":false,"schema":{"type":"boolean"}},{"name":"extended","in":"query","description":"When `true`, each model additionally includes a `providers_details` object with a per-provider breakdown of pricing, quantization, context size and supported features. Defaults to `false`.","required":false,"schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"A list of available models","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Models"}}}},"401":{"description":"Invalid or expired API key"},"500":{"description":"Internal server error"}}}}}}
```

## Retrieve a single model

> Retrieve detailed information about a specific model. The response always includes the \`providers\_details\` per-provider breakdown. An optional API key can be provided via the \`Authorization\` header; when present, results are scoped to the models and providers available based on the inference settings. The same provider filtering parameters as \`/models\` are accepted and are applied to the model's provider list. If no matching model (with at least one allowed provider) is found, \`null\` is returned.

```json
{"openapi":"3.0.0","info":{"title":"Cortecs Model API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]},{}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Optional API key. When provided, the response is filtered to only include models and providers available based on the inference settings."}},"schemas":{"Model":{"type":"object","required":["id","object","created","owned_by","pricing","providers"],"properties":{"id":{"type":"string"},"object":{"type":"string"},"created":{"type":"integer"},"owned_by":{"type":"string"},"description":{"type":"string","nullable":true},"pricing":{"$ref":"#/components/schemas/Pricing"},"providers":{"type":"array","items":{"type":"string"}},"context_size":{"type":"integer","description":"The maximum context size for this model.","nullable":true},"tags":{"type":"array","items":{"type":"string"},"nullable":true},"input_modalities":{"type":"array","description":"Supported input modalities (e.g. text, image, audio) derived from the model tags.","items":{"type":"string"}},"output_modalities":{"type":"array","description":"Supported output modalities (e.g. text, audio, embeddings) derived from the model tags.","items":{"type":"string"}},"supported_features":{"type":"array","description":"Features supported by this model across all available providers. Current values include `json_mode`, `reasoning`, and `tools`.","items":{"type":"string","enum":["json_mode","reasoning","tools"]}},"model_series":{"type":"array","items":{"type":"string"},"nullable":true},"providers_details":{"type":"object","description":"Per-provider breakdown keyed by provider name. Only present when `extended=true`, and always included by the single-model endpoint.","additionalProperties":{"$ref":"#/components/schemas/ProviderDetails"}}}},"Pricing":{"type":"object","description":"Pricing details. On the model level the cost numbers represent the minimums based on the cheapest provider available for this model.","required":["input_token","output_token","currency"],"properties":{"input_token":{"type":"number","description":"Input token cost per 1M tokens"},"output_token":{"type":"number","description":"Output token cost per 1M tokens"},"audio_cost":{"type":"number","description":"Audio cost per second (if supported)"},"speech_cost":{"type":"number","description":"Speech cost per 1M characters (if supported)"},"cache_read_cost":{"type":"number","description":"Cache read cost per 1M tokens (if supported)"},"cache_write_cost":{"type":"number","description":"Cache write cost per 1M tokens (if supported)"},"currency":{"type":"string","description":"The currency of the prices (e.g. EUR, USD)"}}},"ProviderDetails":{"type":"object","description":"Per-provider details, keyed by provider name. Only present when `extended=true` (and always for the single-model endpoint).","properties":{"pricing":{"$ref":"#/components/schemas/Pricing"},"quantization":{"type":"string","description":"The quantization applied by this provider, if any.","nullable":true},"context_size":{"type":"integer","description":"The context size offered by this provider.","nullable":true},"supported_features":{"type":"array","description":"Features supported by this provider. Current values include `json_mode`, `reasoning`, and `tools`.","items":{"type":"string","enum":["json_mode","reasoning","tools"]}}}}}},"paths":{"/models/{model_id}":{"get":{"summary":"Retrieve a single model","description":"Retrieve detailed information about a specific model. The response always includes the `providers_details` per-provider breakdown. An optional API key can be provided via the `Authorization` header; when present, results are scoped to the models and providers available based on the inference settings. The same provider filtering parameters as `/models` are accepted and are applied to the model's provider list. If no matching model (with at least one allowed provider) is found, `null` is returned.","parameters":[{"name":"model_id","in":"path","description":"The model identifier (e.g. `mistral-small-2503`).","required":true,"schema":{"type":"string"}},{"name":"tag","in":"query","description":"One or more tags to filter by (defaults to ['Instruct'])","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"currency","in":"query","description":"ISO currency code for pricing conversion (defaults to 'EUR')","required":false,"schema":{"type":"string","default":"EUR"}},{"name":"allowed_providers","in":"query","description":"Restrict the model's provider list to at least one of the specified providers. Accepts multiple values.","required":false,"schema":{"type":"array","items":{"type":"string"}},"style":"form","explode":true},{"name":"eu_native","in":"query","description":"When `true`, only providers that are based and regulated within the EU are considered. Even when `false`, all endpoints remain GDPR compliant.","required":false,"schema":{"type":"boolean"}},{"name":"allow_quantization","in":"query","description":"When `false`, quantized provider variants are excluded. Defaults to `true`.","required":false,"schema":{"type":"boolean"}},{"name":"allow_zero_data_retention","in":"query","description":"When `true`, only providers that offer zero data retention (ZDR) are considered.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"The requested model, or `null` if it was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Model"}}}},"401":{"description":"Invalid or expired API key"},"500":{"description":"Internal server error"}}}}}}
```


# Anthropic Messages

## POST /messages

> Create a messages response. This endpoint is compatible with the Anthropic API.

```json
{"openapi":"3.1.0","info":{"title":"Cortecs Anthropic Messages API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"MessageRequest":{"type":"object","description":"Request message for /v1/messages","properties":{"preference":{"type":"string","description":"The provider preference for handling the request.","enum":["speed","cost","balanced"]},"allowed_providers":{"type":"array","items":{"type":"string"},"description":"The providers that are allowed to be used for the completion.","nullable":true},"eu_native":{"type":"boolean","description":"Whether to consider only providers based and regulated withing the EU. Even when false, all our endpoints are GDPR compliant.","nullable":true},"allow_quantization":{"type":"boolean","description":"Whether to allow quantized endpoints.","nullable":true},"allow_zero_data_retention":{"type":"boolean","description":"Whether to use only ZDR providers.","nullable":true},"enable_model_fallback":{"type":"boolean","description":"Whether to allow model fallback when a model is currently unavailable.","nullable":true},"fallbacks":{"type":"array","items":{"type":"string"},"description":"The providers that are allowed to be used for the completion.","nullable":true},"max_tokens":{"type":"integer","format":"int32","description":"The maximum number of tokens to generate before stopping. The model may stop before the max_tokens when it reaches the stop sequence."},"messages":{"type":"array","items":{"$ref":"#/components/schemas/MessageBody"},"description":"Input messages."},"metadata":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MessageMetadata","description":"An object describing metadata about the request."}]},"model":{"type":"string","description":"Model name for the model to use."},"stop_sequences":{"type":["array","null"],"items":{"type":"string"},"description":"(Not supported by reasoning models) Up to 4 sequences where the API will stop generating further tokens."},"stream":{"type":["boolean","null"],"description":"If set, partial message deltas will be sent. Tokens will be sent as data-only server-sent events as they become available, with the stream terminated by a data: [DONE] message."},"system":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SystemMessageContent","description":"System prompt message for the model, defining how the model should behave to user messages."}]},"temperature":{"type":["number","null"],"format":"float","description":"What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. It may not work well with reasoning models.","default":1,"maximum":2,"minimum":0},"tool_choice":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MessageToolChoice","description":"Controls which (if any) tool is called by the model. \"none\" means the model will not call any tool and instead generates a message. \"auto\" means the model can pick between generating a message or calling one or more tools. \"any\" means the model must call one or more tools. Specifying a particular tool via {\"type\": \"tool\", \"function\": {\"name\": \"get_weather\"}} forces the model to call that tool. \"none\" is the default when no tools are provided. \"auto\" is the default if tools are provided."}]},"tools":{"type":["array","null"],"items":{"$ref":"#/components/schemas/MessageTools"},"description":"A list of tools the model may call in JSON-schema. Currently, only functions are supported as a tool. Use this to provide a list of functions the model may generate JSON inputs for. A max of 128 functions are supported."},"top_k":{"type":["integer","null"],"format":"int32","description":"(Unsupported) When generating next tokens, randomly selecting the next token from the k most likely options."},"top_p":{"type":["number","null"],"format":"float","description":"An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. It is generally recommended to alter this or temperature but not both.","default":1,"maximum":1,"exclusiveMinimum":0}}},"MessageBody":{"type":"object","description":"Anthropic compatible message body","required":["role","content"],"properties":{"content":{"$ref":"#/components/schemas/MessageContent","description":"The content message."},"role":{"type":"string","description":"The role that the message belongs to, \"system\" for system prompt, \"user\" for user prompt, and \"assistant\" for response from the model."}}},"MessageContent":{"oneOf":[{"type":"string","description":"Text prompt."},{"type":"array","items":{"$ref":"#/components/schemas/MessageContentPart"},"description":"An array of message content parts."}]},"MessageContentPart":{"oneOf":[{"type":"object","description":"Text prompt message content part.","required":["text","type"],"properties":{"cache_control":{"description":"(Unsupported) Cache control."},"text":{"type":"string","description":"Text prompt."},"type":{"type":"string","enum":["text"]}}},{"type":"object","description":"Image prompt message content part.","required":["source","type"],"properties":{"cache_control":{"description":"(Unsupported) Cache control."},"source":{"$ref":"#/components/schemas/MessageImageContent","description":"Image source."},"type":{"type":"string","enum":["image"]}}},{"type":"object","description":"Tool call message content part. Received from model.","required":["id","name","input","type"],"properties":{"cache_control":{"description":"(Unsupported) Cache control."},"id":{"type":"string","description":"ID of the tool call."},"input":{"description":"Input for tool call."},"name":{"type":"string","description":"Name of the tool call."},"type":{"type":"string","enum":["tool_use"]}}},{"type":"object","description":"Tool call result.","required":["tool_use_id","content","type"],"properties":{"cache_control":{"description":"(Unsupported) Cache control."},"content":{"$ref":"#/components/schemas/ToolResultContent","description":"Result content of the tool call. Can be a string or an array of content blocks."},"is_error":{"type":["boolean","null"],"description":"Whether the tool call returns an error."},"tool_use_id":{"type":"string","description":"ID of the tool call given by the model."},"type":{"type":"string","enum":["tool_result"]}}},{"type":"object","description":"(Redacted) Thinking of the model.","required":["data","type"],"properties":{"data":{"type":"string","description":"Encrypted data of the redacted thinking."},"type":{"type":"string","enum":["redacted_thinking"]}}},{"type":"object","description":"Thinking of the model.","required":["thinking","type"],"properties":{"signature":{"type":["string","null"],"description":"Signature of the thinking block (required by Anthropic SDK for round-tripping)."},"thinking":{"type":"string","description":"Thinking."},"type":{"type":"string","enum":["thinking"]}}}]},"MessageImageContent":{"oneOf":[{"type":"object","required":["media_type","data","type"],"properties":{"data":{"type":"string","description":"Base64 encoded image string."},"media_type":{"type":"string","description":"Media type of the image source. Available options: image/jpeg, image/png, image/webp."},"type":{"type":"string","enum":["base64"]}}},{"type":"object","required":["url","type"],"properties":{"type":{"type":"string","enum":["url"]},"url":{"type":"string","description":"URL of the image."}}}]},"ToolResultContent":{"oneOf":[{"type":"string","description":"Plain text content."},{"type":"array","items":{"$ref":"#/components/schemas/ToolResultContentBlock"},"description":"An array of tool result content blocks."}]},"ToolResultContentBlock":{"type":"object","description":"A content block within a tool result.","properties":{"type":{"type":"string","description":"The type of content block."},"text":{"type":"string","description":"Text content of the block."}}},"MessageMetadata":{"type":"object","properties":{"user_id":{"type":["string","null"],"description":"A unique identifier representing your end-user, which can help to monitor and detect abuse."}}},"SystemMessageContent":{"oneOf":[{"type":"string","description":"Text content of system prompt."},{"type":"array","items":{"$ref":"#/components/schemas/SystemMessagePart"},"description":"An array of system prompt parts."}]},"SystemMessagePart":{"type":"object","required":["type","text"],"properties":{"cache_control":{"description":"(Unsupported) Cache control."},"text":{"type":"string","description":"System prompt text."},"type":{"type":"string","description":"Type of the object. This is always \"text\"."}}},"MessageToolChoice":{"oneOf":[{"type":"object","description":"Allows the model to automatically decide whether to call the tool.","required":["type"],"properties":{"type":{"type":"string","enum":["auto"]}}},{"type":"object","description":"Forces the model to use at least one tool, without specifying the tool.","required":["type"],"properties":{"type":{"type":"string","enum":["any"]}}},{"type":"object","description":"Forces the model to use the named tool.","required":["name","type"],"properties":{"name":{"type":"string","description":"Name of the tool to use."},"type":{"type":"string","enum":["tool"]}}}],"description":"Tool choice option."},"MessageTools":{"type":"object","required":["name","description","input_schema"],"properties":{"cache_control":{"description":"(Unsupported) Cache control."},"description":{"type":"string","description":"Description of the tool."},"input_schema":{"$ref":"#/components/schemas/MessageToolInputSchema","description":"Input schema allowed by the tool."},"name":{"type":"string","description":"Name of the tool."}}},"MessageToolInputSchema":{"type":"object","required":["type","properties"],"properties":{"properties":{"description":"JSON-object of the tool input schema."},"required":{"type":["array","null"],"items":{"type":"string"},"description":"Required properties of the tool input schema, if any."},"type":{"type":"string","description":"Type of the schema. This is always \"object\"."}}},"MessageResponse":{"type":"object","description":"Response message for /v1/messages","required":["id","type","role","content","model","usage"],"properties":{"content":{"type":"array","items":{"$ref":"#/components/schemas/MessageResponseContent"},"description":"Response message content."},"id":{"type":"string","description":"Unique object identifier."},"model":{"type":"string","description":"Model name that handled the request."},"role":{"type":"string","description":"Role of the generated message. Always \"assistant\"."},"stop_reason":{"type":["string","null"],"description":"Reason to stop. \"stop_sequence\" means the inference has reached a model-defined or user-supplied stop sequence in stop. \"max_tokens\" means the inference result has reached models' maximum allowed token length or user defined value in max_tokens. \"end_turn\" or null in streaming mode when the chunk is not the last. \"tool_use\" means the model has called a tool and is waiting for the tool response."},"stop_sequence":{"type":["string","null"],"description":"Custom stop sequence used to stop the generation."},"type":{"type":"string","description":"Object type. This is always \"message\" for message types."},"usage":{"$ref":"#/components/schemas/MessageUsage","description":"Token usage information."}}},"MessageResponseContent":{"oneOf":[{"type":"object","description":"Text response from the model.","required":["text","type"],"properties":{"text":{"type":"string"},"type":{"type":"string","enum":["text"]}}},{"type":"object","description":"Thinking response for the model.","required":["signature","thinking","type"],"properties":{"signature":{"type":"string","description":"Signature of the content."},"thinking":{"type":"string","description":"Thinking content."},"type":{"type":"string","enum":["thinking"]}}},{"type":"object","description":"Redacted thinking response for the model.","required":["data","type"],"properties":{"data":{"type":"string","description":"Signature of the content."},"type":{"type":"string","enum":["redacted_thinking"]}}},{"type":"object","description":"Request by the model to invoke a tool call.","required":["id","name","input","type"],"properties":{"id":{"type":"string","description":"Tool call ID."},"input":{"description":"Input to the tool call following the input_schema."},"name":{"type":"string","description":"Name of the tool call to be used."},"type":{"type":"string","enum":["tool_use"]}}}]},"MessageUsage":{"type":"object","required":["input_tokens","cache_creation_input_tokens","cache_read_input_tokens","output_tokens"],"properties":{"cache_creation_input_tokens":{"type":"integer","format":"int32","description":"(Unsupported) Number of tokens written to the cache when creating a new entry."},"cache_read_input_tokens":{"type":"integer","format":"int32","description":"Number of tokens retrieved from the cache for this request."},"input_tokens":{"type":"integer","format":"int32","description":"Number of input tokens used."},"output_tokens":{"type":"integer","format":"int32","description":"Number of output tokens used."}}}}},"paths":{"/messages":{"post":{"tags":["v1"],"summary":"Create a messages response. This endpoint is compatible with the Anthropic API.","operationId":"handle_generic_messages_request","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Bad request. The request is invalid or an invalid API key is provided."},"422":{"description":"Unprocessable Entity. There are missing fields in the request body."}}}}}}
```


# Responses \[BETA]

## Create a model response

> This endpoint creates a response using the specified model.

```json
{"openapi":"3.0.0","info":{"title":"Cortecs Responses API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"ResponseRequest":{"type":"object","description":"A request object for generating model responses and controlling router behavior. This object contains suggested parameters to generate a response from the specified model. Many parameters are optional, and you may include other parameters as required. Not all providers support the same parameters. Unsupported parameters can cause requests to fail or limit the providers able to process them.\n","properties":{"preference":{"type":"string","description":"The provider preference for handling the request.","enum":["speed","cost","balanced"]},"allowed_providers":{"type":"array","items":{"type":"string"},"description":"The providers that are allowed to be used for the completion.","nullable":true},"eu_native":{"type":"boolean","description":"Whether to consider only providers based and regulated withing the EU. Even when false, all our endpoints are GDPR compliant.","nullable":true},"allow_quantization":{"type":"boolean","description":"Whether to allow quantized endpoints.","nullable":true},"allow_zero_data_retention":{"type":"boolean","description":"Whether to use only ZDR providers.","nullable":true},"enable_model_fallback":{"type":"boolean","description":"Whether to allow model fallback when a model is currently unavailable.","nullable":true},"fallbacks":{"type":"array","items":{"type":"string"},"description":"The providers that are allowed to be used for the completion.","nullable":true},"model":{"type":"string","description":"The model to use for the response."},"input":{"description":"The text, messages, or tool outputs to send to the model.","oneOf":[{"type":"string"},{"type":"array","items":{"type":"object"}}]},"instructions":{"type":"string","description":"Instructions that guide the model's response.","nullable":true},"max_output_tokens":{"type":"integer","description":"The maximum number of tokens to generate.","nullable":true},"temperature":{"type":"number","description":"Controls randomness in the output.","nullable":true},"top_p":{"type":"number","description":"Controls output diversity using nucleus sampling.","nullable":true},"stream":{"type":"boolean","description":"Whether to stream response events.","default":false},"tools":{"type":"array","description":"Tools the model may call.","items":{"type":"object"},"nullable":true},"tool_choice":{"description":"Controls which tool the model may call.","oneOf":[{"type":"string"},{"type":"object"}]},"parallel_tool_calls":{"type":"boolean","description":"Whether the model may call tools in parallel.","nullable":true},"previous_response_id":{"type":"string","description":"The previous response to continue from.","nullable":true},"reasoning":{"type":"object","description":"Reasoning configuration for supported models.","nullable":true},"text":{"type":"object","description":"Text output configuration.","nullable":true},"metadata":{"type":"object","description":"Metadata associated with the response.","additionalProperties":{"type":"string"},"nullable":true}},"required":["model","input"]},"ModelResponse":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier for the response."},"object":{"type":"string","description":"The type of object returned."},"created_at":{"type":"integer","description":"The Unix timestamp when the response was created."},"status":{"type":"string","description":"The current response status."},"provider":{"type":"string","description":"The provider that generated the response."},"model":{"type":"string","description":"The model that generated the response."},"output":{"type":"array","description":"The output items generated by the model.","items":{"type":"object"}},"output_text":{"type":"string","description":"The combined text generated by the model, when available.","nullable":true},"usage":{"type":"object","description":"Token usage information.","properties":{"input_tokens":{"type":"integer","description":"Number of input tokens."},"output_tokens":{"type":"integer","description":"Number of output tokens."},"total_tokens":{"type":"integer","description":"Total number of tokens used."}}}},"required":["id","object","created_at","status","model","output"]}}},"paths":{"/responses":{"post":{"summary":"Create a model response","description":"This endpoint creates a response using the specified model.","operationId":"createResponse","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseRequest"}}}},"responses":{"200":{"description":"A model response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelResponse"}},"text/event-stream":{"schema":{"type":"string","description":"A stream of response events."}}}},"500":{"description":"Internal server error."}}}}}}
```


# Text to Speech \[BETA]

{% hint style="warning" %}
This endpoint is currently in beta. For any issues or feedback, please contact us via [Discord](https://discord.com/invite/bPFEFcWBhp) or <support@cortecs.ai>.
{% endhint %}

## Create speech

> This endpoint generates audio from the input text using the specified TTS model.

```json
{"openapi":"3.1.0","info":{"title":"Cortecs Text-to-Speech API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"SpeechRequest":{"type":"object","description":"A request object for generating speech audio from text. This object contains suggested parameters to generate audio from the specified model. Many of the parameters are optional, and it is recommended to set them only if needed; however, you may include other parameters as required. Note that not all providers support the same set of parameters. Adding unsupported or unnecessary parameters can cause requests to fail or limit the providers able to process them.\n","properties":{"model":{"type":"string","description":"The TTS model to use for speech generation."},"input":{"type":"string","description":"The text to generate audio for."},"voice":{"type":"string","description":"The voice to use for speech generation. Voice options are provider-specific (e.g. Tensorix: \"Emily.wav\", Mistral: \"en_paul_neutral\")."},"response_format":{"type":"string","description":"The audio format of the output. Supported formats are provider-dependent.","nullable":true},"speed":{"type":"number","description":"The speed of the generated audio. The accepted value range differs per provider. Not all providers support this parameter.","nullable":true},"preference":{"type":"string","description":"The provider preference for handling the request.","enum":["speed","cost","balanced"]},"allowed_providers":{"type":"array","items":{"type":"string"},"description":"The providers that are allowed to be used for the request.","nullable":true},"eu_native":{"type":"boolean","description":"Whether to consider only providers based and regulated within the EU. Even when false, all our endpoints are GDPR compliant.","nullable":true},"allow_quantization":{"type":"boolean","description":"Whether to allow quantized endpoints.","nullable":true},"allow_zero_data_retention":{"type":"boolean","description":"Whether to use only ZDR providers.","nullable":true},"enable_model_fallback":{"type":"boolean","description":"Whether to allow model fallback when a model is currently unavailable.","nullable":true},"fallbacks":{"type":"array","items":{"type":"string"},"description":"Alternative models to fall back to if the primary model is unavailable.","nullable":true}},"required":["model","input","voice"]}}},"paths":{"/audio/speech":{"post":{"summary":"Create speech","description":"This endpoint generates audio from the input text using the specified TTS model.","operationId":"createSpeech","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeechRequest"}}}},"responses":{"200":{"description":"The audio file content. The format depends on the requested response_format.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"500":{"description":"Internal server error."}}}}}}
```


# Management API

## Usage / Accounting

> Returns aggregated token and cost metrics bucketed by time and optionally by\
> user, API key, model, or provider.\
> \
> \*\*Time range\*\*\
> \- \`from\` defaults to the start of the current calendar day (UTC).\
> \- \`until\` defaults to the current moment (UTC).\
> \
> \*\*Bucket sizes\*\* (\`bucket\` parameter)\
> \
> \| Value  | Meaning          |\
> \|--------|------------------|\
> \| \`1h\`   | 1 hour           |\
> \| \`6h\`   | 6 hours          |\
> \| \`1d\`   | 1 day (default)  |\
> \| \`1w\`   | 1 week           |\
> \| \`1M\`   | 1 month          |\
> \| \`1Y\`   | 1 year           |\
> \
> \*\*Grouping\*\* (\`group\_by\` parameter)\
> \
> Comma-separated list of fields to group by (in addition to the time bucket).\
> Valid fields: \`user\_id\`, \`key\_name\`, \`model\`, \`provider\`.\
> \
> \| Example value            | GROUP BY columns                            |\
> \|--------------------------|---------------------------------------------|\
> \| \*(omitted)\*              | bucket only (default)                       |\
> \| \`user\_id\`                | bucket + \`user\_id\`                          |\
> \| \`user\_id,key\_name\`       | bucket + \`user\_id\` + \`key\_name\`             |\
> \| \`user\_id,model\`          | bucket + \`user\_id\` + \`model\`                |\
> \| \`model\`                  | bucket + \`model\`                            |\
> \| \`provider\`               | bucket + \`provider\`                         |\
> \| \`user\_id,key\_name,model\` | bucket + \`user\_id\` + \`key\_name\` + \`model\`   |<br>

```json
{"openapi":"3.1.0","info":{"title":"Cortecs Management API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"A management API key must be used as the Bearer token."}},"schemas":{"UsageResponse":{"type":"object","required":["from","until","bucket","group_by","rows"],"properties":{"from":{"type":"string","format":"date-time","description":"Resolved inclusive start of the queried range (UTC)."},"until":{"type":"string","format":"date-time","description":"Resolved exclusive end of the queried range (UTC)."},"bucket":{"type":"string","enum":["1h","6h","1d","1w","1M","1Y"],"description":"The bucket interval used for aggregation."},"group_by":{"type":["string","null"],"description":"The comma-separated group_by fields that were applied.\n`null` when no grouping was requested.\n"},"user_id":{"type":["string","null"],"description":"The `user_id` filter that was applied, if any."},"key_name":{"type":["string","null"],"description":"The `key_name` filter that was applied, if any."},"model":{"type":["string","null"],"description":"The `model` filter that was applied, if any."},"provider":{"type":["string","null"],"description":"The `provider` filter that was applied, if any."},"rows":{"type":"array","items":{"$ref":"#/components/schemas/UsageRow"},"description":"Aggregated rows ordered by `bucket_start ASC`, then `user_id ASC`,\nthen `key_name ASC`, then `model ASC`, then `provider ASC` (where applicable).\n"}}},"UsageRow":{"type":"object","required":["bucket_start","bucket_end","request_count","input_tokens","output_tokens","total_tokens","audio_duration","input_price","output_price","audio_price","cache_read_price","cache_write_price","speech_price","total_price","cache_read_tokens","cache_write_tokens","character_count"],"properties":{"bucket_start":{"type":"string","format":"date-time","description":"Inclusive start of the aggregation bucket (UTC)."},"bucket_end":{"type":"string","format":"date-time","description":"Exclusive end of the aggregation bucket (UTC).\nEqual to `bucket_start + bucket_interval`.\n"},"user_id":{"type":["string","null"],"description":"Present when `group_by` includes `user_id`.\n`null` for requests that had no user context.\n"},"user_email":{"type":["string","null"],"description":"Resolved email address of the user. Present when `group_by` includes\n`user_id` and the user could be found in the team.\n`null` if the user is not a current team member.\n"},"user_name":{"type":["string","null"],"description":"Resolved display name of the user. Present when `group_by` includes\n`user_id` and the user could be found in the team.\n`null` if the user has no name set or is not a current team member.\n"},"key_name":{"type":["string","null"],"description":"Present when `group_by` includes `key_name`.\n`null` for requests with no named API key.\n"},"model":{"type":["string","null"],"description":"Present when `group_by` includes `model`.\n`null` for requests where the model was not recorded.\n"},"provider":{"type":["string","null"],"description":"Present when `group_by` includes `provider`.\n`null` for requests where the provider was not recorded.\n"},"request_count":{"type":"integer","format":"int64","description":"Number of individual inference requests in this bucket."},"input_tokens":{"type":"integer","format":"int64","description":"Total prompt / input tokens consumed, including cache-read and cache-write tokens.\n"},"output_tokens":{"type":"integer","format":"int64","description":"Total completion / output tokens generated."},"total_tokens":{"type":"integer","format":"int64","description":"`input_tokens + output_tokens`"},"audio_duration":{"type":"number","format":"double","description":"Total audio duration in seconds (STT/TTS workloads)."},"input_price":{"type":"number","format":"double","description":"Aggregated cost for input tokens in EUR."},"output_price":{"type":"number","format":"double","description":"Aggregated cost for output tokens in EUR."},"audio_price":{"type":"number","format":"double","description":"Aggregated cost for audio processing in EUR."},"cache_read_price":{"type":"number","format":"double","description":"Aggregated cost for cache-read tokens in EUR."},"cache_write_price":{"type":"number","format":"double","description":"Aggregated cost for cache-write tokens in EUR."},"speech_price":{"type":"number","format":"double","description":"Aggregated cost for speech synthesis (TTS) in EUR."},"image_price":{"type":"number","format":"double","description":"Aggregated cost for images generated in EUR."},"total_price":{"type":"number","format":"double","description":"`input_price + output_price + audio_price + cache_read_price + cache_write_price + speech_price`\n"},"cache_read_tokens":{"type":"integer","format":"int64","description":"Tokens served from prompt cache (subset of `input_tokens`)."},"cache_write_tokens":{"type":"integer","format":"int64","description":"Tokens written to prompt cache (subset of `input_tokens`)."},"character_count":{"type":"integer","format":"int64","description":"Total character count across all requests in this bucket."}}},"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"A human-readable error message."},"detail":{"type":"string","description":"A human-readable error detail message."}}},"ValidationErrorResponse":{"type":"object","required":["detail"],"properties":{"detail":{"type":"array","items":{"type":"object","required":["loc","msg","type"],"properties":{"loc":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"integer"}]},"description":"Location of the offending field."},"msg":{"type":"string","description":"Validation error message."},"type":{"type":"string","description":"Pydantic error type code."}}}}}}}},"paths":{"/manage/usage":{"get":{"operationId":"getUsage","summary":"Usage / Accounting","tags":["Usage"],"description":"Returns aggregated token and cost metrics bucketed by time and optionally by\nuser, API key, model, or provider.\n\n**Time range**\n- `from` defaults to the start of the current calendar day (UTC).\n- `until` defaults to the current moment (UTC).\n\n**Bucket sizes** (`bucket` parameter)\n\n| Value  | Meaning          |\n|--------|------------------|\n| `1h`   | 1 hour           |\n| `6h`   | 6 hours          |\n| `1d`   | 1 day (default)  |\n| `1w`   | 1 week           |\n| `1M`   | 1 month          |\n| `1Y`   | 1 year           |\n\n**Grouping** (`group_by` parameter)\n\nComma-separated list of fields to group by (in addition to the time bucket).\nValid fields: `user_id`, `key_name`, `model`, `provider`.\n\n| Example value            | GROUP BY columns                            |\n|--------------------------|---------------------------------------------|\n| *(omitted)*              | bucket only (default)                       |\n| `user_id`                | bucket + `user_id`                          |\n| `user_id,key_name`       | bucket + `user_id` + `key_name`             |\n| `user_id,model`          | bucket + `user_id` + `model`                |\n| `model`                  | bucket + `model`                            |\n| `provider`               | bucket + `provider`                         |\n| `user_id,key_name,model` | bucket + `user_id` + `key_name` + `model`   |\n","parameters":[{"name":"from","in":"query","required":false,"description":"Inclusive start of the time range (ISO 8601 / RFC 3339).\nDefaults to the start of the current UTC day.\n","schema":{"type":"string","format":"date-time"}},{"name":"until","in":"query","required":false,"description":"Exclusive end of the time range (ISO 8601 / RFC 3339).\nDefaults to the current UTC moment.\n","schema":{"type":"string","format":"date-time"}},{"name":"bucket","in":"query","required":false,"description":"TimescaleDB `time_bucket` interval for aggregation.","schema":{"type":"string","enum":["1h","1d","1w","1M","1Y"]}},{"name":"group_by","in":"query","required":false,"description":"Comma-separated list of fields to group by, in addition to the time bucket.\nValid fields: `user_id`, `key_name`, `model`, `provider`.\nExamples: `user_id`, `user_id,model`, `user_id,key_name,provider`.\n","schema":{"type":"string"}},{"name":"user_id","in":"query","required":false,"description":"Filter results to a single user.","schema":{"type":"string"}},{"name":"key_name","in":"query","required":false,"description":"Filter results to a specific API key name.\nOnly effective when `group_by` includes `key_name` or used as a standalone filter.\n","schema":{"type":"string"}},{"name":"model","in":"query","required":false,"description":"Filter results to a single model name.","schema":{"type":"string"}},{"name":"provider","in":"query","required":false,"description":"Filter results to a single provider.","schema":{"type":"string"}}],"responses":{"200":{"description":"Usage rows matching the requested filters and grouping.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageResponse"}}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid Bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Token does not have permission to access this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation error (missing required parameters or wrong type).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"500":{"description":"Internal server error (DB unreachable, query timeout, etc.).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## List API Keys

> Returns all API keys belonging to the authenticated user. Requires a management API key for authentication.<br>

```json
{"openapi":"3.1.0","info":{"title":"Cortecs Management API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"A management API key must be used as the Bearer token."}},"schemas":{"ApiKey":{"type":"object","properties":{"name":{"type":"string","description":"The unique name of the API key."},"created_at":{"type":"integer","description":"Unix timestamp (seconds) of when the key was created."},"is_management_key":{"type":"boolean","description":"Whether this key has management permissions."}}},"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"A human-readable error message."},"detail":{"type":"string","description":"A human-readable error detail message."}}}}},"paths":{"/manage/api-keys":{"get":{"summary":"List API Keys","tags":["API Keys"],"description":"Returns all API keys belonging to the authenticated user. Requires a management API key for authentication.\n","responses":{"200":{"description":"Successfully returned the list of API keys.","content":{"application/json":{"schema":{"type":"object","properties":{"api_keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}}}}}},"401":{"description":"Unauthorized – Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden – The provided API key is not a management key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Create API Key

> Creates a new API key for the authenticated user. Requires a management API key for authentication.<br>

```json
{"openapi":"3.1.0","info":{"title":"Cortecs Management API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"A management API key must be used as the Bearer token."}},"schemas":{"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"A human-readable error message."},"detail":{"type":"string","description":"A human-readable error detail message."}}}}},"paths":{"/manage/api-keys":{"post":{"summary":"Create API Key","tags":["API Keys"],"description":"Creates a new API key for the authenticated user. Requires a management API key for authentication.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"A unique name for the new API key."},"is_management_key":{"type":"boolean","description":"Whether the new key should have management permissions.","default":false}}}}}},"responses":{"201":{"description":"API key created successfully. The `api_key` value is only shown once.","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"The name of the created key."},"is_management_key":{"type":"boolean","description":"Whether the key has management permissions."},"api_key":{"type":"string","description":"The API key token. Store it securely — it cannot be retrieved again."}}}}}},"400":{"description":"Bad request – Invalid input, duplicate name, or key limit reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized – Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden – The provided API key is not a management key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Delete API Key

> Deletes an API key by name. Also removes any associated budget configurations. You cannot delete the management key currently being used to authenticate. Requires a management API key for authentication.<br>

```json
{"openapi":"3.1.0","info":{"title":"Cortecs Management API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"A management API key must be used as the Bearer token."}},"schemas":{"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"A human-readable error message."},"detail":{"type":"string","description":"A human-readable error detail message."}}}}},"paths":{"/manage/api-keys":{"delete":{"summary":"Delete API Key","tags":["API Keys"],"description":"Deletes an API key by name. Also removes any associated budget configurations. You cannot delete the management key currently being used to authenticate. Requires a management API key for authentication.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"The name of the API key to delete."}}}}}},"responses":{"200":{"description":"API key deleted successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"deleted":{"type":"string","description":"The name of the deleted key."}}}}}},"400":{"description":"Bad request – Invalid input or attempting to delete the key in use.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized – Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden – The provided API key is not a management key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found – The specified API key does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Retrieve Current Project Settings

> Retrieves the current project settings and configuration details. Requires a management API key for authentication.<br>

```json
{"openapi":"3.1.0","info":{"title":"Cortecs Management API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"A management API key must be used as the Bearer token."}},"schemas":{"ProjectConfig":{"type":"object","required":["_id","project_id","inference_config","allow_overwrite","created_at","updated_at"],"properties":{"_id":{"type":"string","description":"Unique identifier of the project configuration."},"project_id":{"type":"string","description":"Identifier of the project this configuration belongs to."},"inference_config":{"type":"object","description":"The inference configuration for the project.","properties":{"allowed_providers":{"type":"array","description":"List of allowed providers.","items":{"type":"string"}},"eu_native":{"type":"boolean","description":"Whether to use only EU-based and regulated providers. Even when false, all endpoints are GDPR compliant."},"allow_quantization":{"type":"boolean","description":"Whether to allow quantization of the model. Quantization is only supported for some providers."},"allow_zero_data_retention":{"type":"boolean","description":"Whether to use only ZDR providers."},"enable_model_fallback":{"type":"boolean","description":"Whether to allow model fallback when a model is currently unavailable."},"preference":{"type":"string","description":"Preference for handling the request.","enum":["speed","cost","balanced"],"nullable":true},"max_tokens":{"type":"integer","description":"Maximum tokens allowed in output.","nullable":true}}},"allow_overwrite":{"type":"boolean","description":"Allow individual API calls to define their own inference configurations. If disabled, the global settings below will be enforced for all requests."},"created_at":{"type":"string","format":"date-time","description":"Date and time when this configuration was created."},"updated_at":{"type":"string","format":"date-time","description":"Date and time when this configuration was last updated."}}},"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"A human-readable error message."},"detail":{"type":"string","description":"A human-readable error detail message."}}}}},"paths":{"/manage/project-configs":{"get":{"summary":"Retrieve Current Project Settings","tags":["Project Config"],"description":"Retrieves the current project settings and configuration details. Requires a management API key for authentication.\n","responses":{"200":{"description":"Successfully returned the current project settings.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectConfig"}}}},"401":{"description":"Unauthorized – Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden – The provided API key is not a management key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found – Project configuration not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error."}}}}}}
```

## Update Current Project Settings

> Updates the current project settings and configuration details. Restricted to project admins. Requires a management API key for authentication.<br>

```json
{"openapi":"3.1.0","info":{"title":"Cortecs Management API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"A management API key must be used as the Bearer token."}},"schemas":{"ProjectConfigUpdateRequest":{"type":"object","description":"A request object for updating the project configuration. Required fields must be included, while other fields are optional. This endpoint is restricted to admins unless allow_overwrite is set to true.\n","required":["inference_config","created_at","updated_at"],"properties":{"inference_config":{"type":"object","description":"The inference configuration for the project.","properties":{"allowed_providers":{"type":"array","description":"List of allowed providers.","items":{"type":"string"}},"eu_native":{"type":"boolean","description":"Whether to consider only providers based and regulated within the EU. Even when false, all our endpoints are GDPR compliant."},"allow_quantization":{"type":"boolean","description":"Whether to allow quantized endpoints."},"max_tokens":{"type":"integer","description":"Maximum tokens allowed in output.","nullable":true},"preference":{"type":"string","description":"Preference for handling the request.","enum":["speed","cost","balanced"],"nullable":true},"allow_zero_data_retention":{"type":"boolean","description":"Whether to use only ZDR providers."},"enable_model_fallback":{"type":"boolean","description":"Whether to allow model fallback when a model is currently unavailable."}}},"allow_overwrite":{"type":"boolean","description":"Allow individual API calls to define their own inference configurations. If disabled, the global settings below will be enforced for all requests.\n","nullable":true},"created_at":{"type":"string","format":"date-time","description":"Timestamp when the configuration was created."},"updated_at":{"type":"string","format":"date-time","description":"Timestamp when the configuration was last updated."}}},"SuccessResponse":{"type":"object","properties":{"success":{"type":"boolean"}},"description":"Indicates whether the operation was successful."},"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"A human-readable error message."},"detail":{"type":"string","description":"A human-readable error detail message."}}}}},"paths":{"/manage/project-configs":{"put":{"summary":"Update Current Project Settings","tags":["Project Config"],"description":"Updates the current project settings and configuration details. Restricted to project admins. Requires a management API key for authentication.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectConfigUpdateRequest"}}}},"responses":{"200":{"description":"Project configuration updated successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"description":"Bad Request – Invalid configuration or registry validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized – Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden – Not a management key or user is not an admin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found – Project configuration not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error."}}}}}}
```

## List Budgets

> Lists budget rules for the authenticated project. Non-admin management key holders can see budgets that apply to them. Project admins can see all project budgets and can filter by scope, period, user\_id, and key\_name.<br>

```json
{"openapi":"3.1.0","info":{"title":"Cortecs Management API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"A management API key must be used as the Bearer token."}},"schemas":{"BudgetsResponse":{"type":"object","required":["budgets"],"properties":{"budgets":{"type":"array","items":{"$ref":"#/components/schemas/Budget"}}}},"Budget":{"type":"object","required":["scope","period","amount","user_id","key_name"],"properties":{"scope":{"type":"string","enum":["project","user","api-key"],"description":"Budget scope."},"period":{"type":"string","enum":["daily","weekly","monthly"],"description":"Budget period."},"amount":{"type":"integer","minimum":0,"description":"Budget amount."},"user_id":{"type":["string","null"],"description":"User identifier for user and api-key scoped budgets."},"key_name":{"type":["string","null"],"description":"API key name for api-key scoped budgets."}}},"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"A human-readable error message."},"detail":{"type":"string","description":"A human-readable error detail message."}}}}},"paths":{"/manage/budgets":{"get":{"summary":"List Budgets","tags":["Budgets"],"description":"Lists budget rules for the authenticated project. Non-admin management key holders can see budgets that apply to them. Project admins can see all project budgets and can filter by scope, period, user_id, and key_name.\n","parameters":[{"name":"scope","in":"query","required":false,"schema":{"type":"string","enum":["project","user","api-key"]}},{"name":"period","in":"query","required":false,"schema":{"type":"string","enum":["daily","weekly","monthly"]}},{"name":"user_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"key_name","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully returned budgets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetsResponse"}}}},"400":{"description":"Invalid filter.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - The provided API key is not a management key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Project configuration not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error."}}}}}}
```

## Upsert Budget

> Creates or updates a budget period for the authenticated project. Restricted to project admins using a management API key. PUT is also supported with the same body.<br>

```json
{"openapi":"3.1.0","info":{"title":"Cortecs Management API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"A management API key must be used as the Bearer token."}},"schemas":{"BudgetUpsertRequest":{"type":"object","required":["scope","period","amount"],"properties":{"scope":{"type":"string","enum":["project","user","api-key"]},"period":{"type":"string","enum":["daily","weekly","monthly"]},"user_id":{"type":["string","null"],"description":"Required for user scope and concrete api-key budgets. Must be null or omitted when key_name is '*' for api-key scope.","default":null},"key_name":{"type":["string","null"],"description":"Required for api-key scope. Use '*' with user_id null for the default per-api-key budget; otherwise user_id is required and the key must belong to that user.","default":null},"amount":{"type":"integer","minimum":0}}},"SuccessResponse":{"type":"object","properties":{"success":{"type":"boolean"}},"description":"Indicates whether the operation was successful."},"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"A human-readable error message."},"detail":{"type":"string","description":"A human-readable error detail message."}}}}},"paths":{"/manage/budgets":{"post":{"summary":"Upsert Budget","tags":["Budgets"],"description":"Creates or updates a budget period for the authenticated project. Restricted to project admins using a management API key. PUT is also supported with the same body.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetUpsertRequest"}}}},"responses":{"200":{"description":"Budget saved successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"description":"Invalid budget request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Not a management key or user is not an admin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Project configuration not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error."}}}}}}
```

## Delete Budget

> Deletes a single budget period for the provided scope. Restricted to project admins using a management API key. The request body may be JSON, or the same fields may be provided as query parameters.<br>

```json
{"openapi":"3.1.0","info":{"title":"Cortecs Management API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"A management API key must be used as the Bearer token."}},"schemas":{"BudgetDeleteRequest":{"type":"object","required":["scope","period"],"properties":{"scope":{"type":"string","enum":["project","user","api-key"]},"period":{"type":"string","enum":["daily","weekly","monthly"]},"user_id":{"type":["string","null"],"description":"Required for user scope and concrete api-key budgets. Must be null or omitted when key_name is '*' for api-key scope.","default":null},"key_name":{"type":["string","null"],"description":"Required for api-key scope. Use '*' with user_id null for the default per-api-key budget; otherwise user_id is required and the key must belong to that user.","default":null}}},"SuccessResponse":{"type":"object","properties":{"success":{"type":"boolean"}},"description":"Indicates whether the operation was successful."}}},"paths":{"/manage/budgets":{"delete":{"summary":"Delete Budget","tags":["Budgets"],"description":"Deletes a single budget period for the provided scope. Restricted to project admins using a management API key. The request body may be JSON, or the same fields may be provided as query parameters.\n","requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetDeleteRequest"}}}},"responses":{"200":{"description":"Budget deleted successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"description":"Invalid budget delete request."},"401":{"description":"Unauthorized - Missing or invalid token."},"403":{"description":"Forbidden - Not a management key or user is not an admin."},"404":{"description":"Not Found - Project configuration not found."},"500":{"description":"Internal server error."}}}}}}
```

## Retrieve Project Balance

> Retrieves the current balance information of the authenticated project. Requires a management API key belonging to a project admin.<br>

```json
{"openapi":"3.1.0","info":{"title":"Cortecs Management API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"A management API key must be used as the Bearer token."}},"schemas":{"UserBalance":{"type":"object","properties":{"current_balance":{"type":"number","format":"float","description":"The current balance of the user."},"currency":{"type":"string","description":"The currency in which the balance is expressed."}}},"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"A human-readable error message."},"detail":{"type":"string","description":"A human-readable error detail message."}}}}},"paths":{"/manage/balance":{"get":{"summary":"Retrieve Project Balance","tags":["Balance"],"description":"Retrieves the current balance information of the authenticated project. Requires a management API key belonging to a project admin.\n","responses":{"200":{"description":"Successfully retrieved project balance.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserBalance"}}}},"401":{"description":"Unauthorized – Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden – Not a management key or user is not an admin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found – Project configuration not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error."}}}}}}
```

## List Project Members

> Returns all members of the authenticated project. Requires a management API key belonging to a project admin.<br>

```json
{"openapi":"3.1.0","info":{"title":"Cortecs Management API","version":"1.0.0"},"servers":[{"url":"https://api.cortecs.ai/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"A management API key must be used as the Bearer token."}},"schemas":{"ProjectMembersResponse":{"type":"object","required":["members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ProjectMember"}}}},"ProjectMember":{"type":"object","required":["id","name","email","role"],"properties":{"id":{"type":"string","description":"The Auth0 user identifier of the project member."},"name":{"type":"string","description":"The display name of the project member."},"email":{"type":"string","format":"email","description":"The email address of the project member."},"role":{"type":["string","null"],"description":"The project role of the member."}}},"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"A human-readable error message."},"detail":{"type":"string","description":"A human-readable error detail message."}}}}},"paths":{"/manage/project-members":{"get":{"summary":"List Project Members","tags":["Project"],"description":"Returns all members of the authenticated project. Requires a management API key belonging to a project admin.\n","responses":{"200":{"description":"Successfully returned the project members.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectMembersResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Not a management key or user is not an admin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Project configuration not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error."}}}}}}
```


# Security & Compliance


# Data Governance & Controls

### **GDPR by default**

The fundamental difference between a traditional AI gateway and Cortecs lies in where the legal boundary is drawn. Conventional routers optimize only for API integration, which leaves you fully liable for downstream data transfers.

By absorbing this extensive vendor due diligence, our managed approach cuts out months of legal bottlenecks.

|                                      | **Conventional Router**                                                                               | **Cortecs**                                                    |
| ------------------------------------ | ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
| Concept                              | Pass-Through Gateway                                                                                  | Managed Gateway                                                |
| Role                                 | Acts solely as a routing engine.                                                                      | Acts as the primary Data Processor.                            |
| LLM Provider Status                  | Direct Processors to your organization.                                                               | Subprocessors under Cortecs.                                   |
| Data Processing Agreements (DPAs)    | Requires signing separate DPAs with every single LLM provider used.                                   | One DPA built into our Terms.                                  |
| Cross-Border Transfers (SCCs & TIAs) | You must execute Standard Contractual Clauses and Transfer Impact Assessments for each non-EU vendor. | We manage the downstream compliance for all integrated models. |
| Compliance Boundary                  | Stops at the router; the connection to the LLM is legally exposed to you.                             | Encompasses the router *and* the downstream LLM providers.     |
| Liability Shift                      | You carry 100% of the vendor risk and legal liability for the providers.                              | We take the responsibility for our downstream providers.       |

### Certified security level <i class="fa-badge-check">:badge-check:</i>

ISO 27001 represents the European gold standard for information security. We closely monitor our partners’ security levels and certification statuses. In the selection grid, providers holding an active ISO certification feature a verification badge <i class="fa-badge-check">:badge-check:</i>. Choose these badged providers to seamlessly enforce ISO 27001 compliance throughout your value chain.

<figure><img src="/files/fssS2mHRNMZCfHkebPIv" alt=""><figcaption></figcaption></figure>

### Fine-grained settings

**Compliance Settings** define rules that control how your data is handled, either **project-wide** or **per request**.

These settings allow you to enforce compliance and governance requirements across a project, or override them selectively for individual requests when needed.

Use the pages below to configure specific controls:

* 🇪🇺 **Sovereign Cloud:** Restrict routing to providers based and regulated within the EU.
* 🗑️ **Zero Data Retention (ZDR):** Route requests only to endpoints that do not retain data.
* ⚡ **Quantization** : Allow requests to be routed to **quantized endpoints**

{% hint style="info" %}
By default, all requests remain within Europe and your data is not used for AI training. You can use additional settings to further customize specific routing requirements.
{% endhint %}


# Sovereign Cloud

The **Sovereign Cloud** setting allows you to ensure that your project uses only providers located within the 🇪🇺 European Union. This guarantees **data sovereignty** and ensures that your data is free from non-EU regulatory control.

> 💡 **Note:** This setting determines whether to consider only providers **based and regulated within the EU**. **Even when false**, our endpoints remain **GDPR compliant**.

## **Via Web Console**

1. Go to your [**Project Settings**](https://cortecs.ai/userArea/console?tab=inference) → **Inference Section**.
2. Toggle **SovereignCloud ON** ✅ to filter the available providers and use **only EU-based providers**.

<figure><img src="/files/1NzjYVyI6Z6Wuu958bbA" alt=""><figcaption></figcaption></figure>

3. Toggle **OFF** ❌ to make **all providers available** again.

<figure><img src="/files/UjJqEdqc1g8N2VnDhaiR" alt=""><figcaption></figcaption></figure>

## **Via API**

You can also set this preference directly in your requests by including the `eu_native` parameter:

```json
{
  "model": "gpt-oss-120b",
  "messages": [...],
  "eu_native": true
}
```

* `true` ✅ → Only EU providers are used
* `false` ❌ → All providers are available (**GDPR compliance is still ensured**)

You can also update this parameter using the [**Project Config API**](https://docs.cortecs.ai/advanced-usage/project-configuration/update-project-config)

> 💡 This ensures that all team requests automatically follow the EU-only policy.

## Compliance Focus

* **Sovereignty**: EU-only routing ensures data is routed to EU-native providers.
* **Routing:** Likewise, the routing itself takes place on EU-native cloud infrastructure.
* **Data residency**: Even with `eu_native = false`, European data residency is ensured. But data might be processed by entities of non-EU companies (Microsoft, Google, AWS, ...)

The Sovereign Cloud setting gives your organization fine-grained **control over regulatory compliance**, while GDPR protections are always maintained.


# Zero Data Retention (ZDR)

**Zero Data Retention (ZDR)** means that a provider does **not store your request or response data for any period of time**. When enabled, requests are routed **only to endpoints that guarantee zero data retention**, helping you meet strict privacy and regulatory requirements.

> 💡 **Note:** Even when using providers that retain data for a limited period, **your data is never used for model training**. Retention, when applicable, is strictly for operational, security, or monitoring purposes.

## Via Web Console

1. Go to your [**Project Settings**](https://cortecs.ai/userArea/console?tab=inference) **→ Inference Section**.
2. Toggle **Zero Data Retention** **ON** ✅ to route requests **only to endpoints with data retention = 0**.

<figure><img src="/files/ukBOrmrkb0420Pv4suBH" alt=""><figcaption></figcaption></figure>

3. Toggle **OFF** ❌ to allow routing to **all available endpoints**, including those with non-zero retention periods.

<figure><img src="/files/OXvaWNBuppR7R39MZh6T" alt=""><figcaption></figcaption></figure>

## Via API

You can also control this behavior directly in your requests using the `allow_zero_data_retention` parameter:

```json
{
  "model": "gpt-oss-120b",
  "messages": [...],
  "allow_zero_data_retention": true
}
```

* `true` ✅ → Requests are routed **only to Zero Data Retention endpoints**
* `false` ❌ → Requests may be routed to **all endpoints**, regardless of retention duration

For **project-wide enforcement**, you can also configure this setting via the [**Project Config API**](https://docs.cortecs.ai/advanced-usage/project-configuration/update-project-config), ensuring all team requests follow the same policy. 🏢

## Data Retention Overview

| Provider       | Data Retention       |
| -------------- | -------------------- |
| Scaleway       | Retained for 0 days  |
| OVH            | Retained for 0 days  |
| Nebius         | Retained for 0 days  |
| Ionos          | Retained for 0 days  |
| Mistral        | Retained for 0 days  |
| Microsoft      | Retained for 30 days |
| Google Vertex  | Retained for 0 days  |
| Amazon Bedrock | Retained for 0 days  |
| Inceptron      | Retained for 0 days  |
| Infercom       | Retained for 0 days  |
| Tensorix       | Retained for 0 days  |
| AKI            | Retained for 0 days  |
| Berget         | Retained for 0 days  |

> 📌 Retention durations may be subject to provider contractual terms and compliance requirements. For a complete and up-to-date list of ZDR for all providers see our [Privacy Policy](https://cortecs.ai/privacyPolicy).

## Compliance Focus

* **Zero Data Storage**: Ensures no request or response data is retained.
* **Privacy by Design**: Ideal for sensitive, regulated, or confidential workloads.
* **GDPR Compliance**: All endpoints comply with GDPR, regardless of retention duration.
* **Governance Control**: Can be enforced at the project level.

Zero Data Retention helps organizations minimize data exposure, simplify audits, and meet strict internal or regulatory privacy requirements without compromising GDPR compliance.


# Professional Secrecy Agreement

Restricted routing for information protected by German § 203 StGB

If you are subject to professional secrecy under **§ 203 StGB**, information entrusted to you in your professional capacity may require additional confidentiality safeguards.

Cortecs supports these workloads through a Professional Secrecy Addendum and routing restricted to a defined set of providers. Both measures are required for the setup described on this page.

{% hint style="warning" %}
**Default routing is not suitable for § 203 workloads.** By default, Cortecs may route requests across its broader provider pool. Do not submit information protected by § 203 StGB until the Professional Secrecy Addendum is in effect and restricted routing has been configured.
{% endhint %}

## Set up restricted § 203 routing

{% stepper %}
{% step %}

### 1. Conclude the Professional Secrecy Addendum

Sign the **Professional Secrecy Addendum** with Cortecs GmbH. Contact [privacy@cortecs.ai](mailto:support@cortecs.ai) to request it.

The addendum establishes the additional confidentiality obligations for the approved provider chain. It does not replace your Data Processing Agreement or other applicable data-protection terms, and it does not replace your own assessment of professional-law requirements or whether a particular disclosure is permitted and necessary.
{% endstep %}

{% step %}

### 2. Restrict routing to approved providers

Use only providers approved by Cortecs for restricted § 203 routing. You can apply the restriction at project level OR per API request:

* In the dashboard, go to **Settings** → **Inference** and select only providers from the approved list below.
* In an API request, pass the exact identifiers from the approved list in `allowed_providers`.

The addendum alone does not restrict routing and does not make default routing suitable for § 203 workloads.
{% endstep %}
{% endstepper %}

### UI example

In the dashboard, go to **Settings** → **Inference** and select only providers from the list of [approved providers](#approved-providers). Make sure your selection exactly matches the approved providers.

<figure><img src="/files/8DUhaSBnajaoQOFe1Zhh" alt="An example of a specific provider selection." width="563"><figcaption><p>An example of a specific provider selection. Make sure it matches approved providers.</p></figcaption></figure>

### API example

```bash
curl 'https://api.cortecs.ai/v1/chat/completions' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <API_KEY>' \
  -d '{
    "model": "<MODEL_NAME>",
    "messages": [
      { "role": "user", "content": "<YOUR_MESSAGE>" }
    ],
    "allowed_providers": [
      "amazon_ireland",
      "amazon_paris",
      "ionos",
      "ovh",
      "aki",
      "infercom",
      "google"
    ]
  }'
```

When `allowed_providers` is set, Cortecs will not route or fall back to a provider outside that allowlist. If none of the listed providers can serve the request, the request fails. See [Routing Concept](/routing/advanced-usage#parameter-handling) for more information about routing parameters.

## Approved Providers

Use the API identifiers exactly as shown or select them by name in the UI.

<table data-header-hidden data-search="false"><thead><tr><th></th><th width="170.28125"></th><th></th></tr></thead><tbody><tr><td>Name</td><td>Provider IDs</td><td>Legal entity</td></tr><tr><td>Amazon</td><td><code>amazon_ireland, amazon_paris</code></td><td>Amazon Web Services EMEA SARL</td></tr><tr><td>Ionos</td><td><code>ionos</code></td><td>IONOS SE</td></tr><tr><td>OVH</td><td><code>ovh</code></td><td>OVH SA</td></tr><tr><td>AKI</td><td><code>aki</code></td><td>AKI.IO GmbH</td></tr><tr><td>Google</td><td><code>google</code></td><td>Google Cloud EMEA Limited</td></tr><tr><td>Infercom</td><td><code>infercom</code></td><td>Infercom SCS</td></tr></tbody></table>

{% hint style="info" %}
Additional providers may be added to this list on a continuous basis. Customers should review this page regularly to stay informed of the current approved providers.
{% endhint %}


# Quantization

**Quantization** allows requests to be routed to **quantized endpoints**, which may deliver **faster inference** and **lower costs**, with a slight reduction in accurac&#x79;**.**

Because quantization affects inference behavior, this setting gives you explicit control over the model version used. You may choose to disable this feature to retain the original model for precision-critical tasks or regulatory compliance.

> 💡 **Note:** Quantized endpoints follow the same **security** and **data retention** as non-quantized endpoints.

## Via Web Console

1. Go to your [**Project Settings**](https://cortecs.ai/userArea/console?tab=inference) **→ Inference Section**.
2. Toggle **Allow Quantization** **ON** ✅to allow **routing** to quantized endpoints.

<figure><img src="/files/aNeCpe3GLYppebfdHN2E" alt=""><figcaption></figcaption></figure>

3. Toggle **OFF** ❌ to restrict routing to **non-quantized endpoints only**.

<figure><img src="/files/FJXefcd6Pf6MdYLk492w" alt=""><figcaption></figcaption></figure>

## Via API

You can also control quantization directly in your requests using the `allow_quantization` parameter:

```json
{
  "model": "devstral-2512",
  "messages": [...],
  "allow_quantization": true
}
```

* `true` ✅ *(default)* → Quantized endpoints are allowed
* `false` ❌ → Only non-quantized endpoints are used

For **project-wide enforcement**, you can also configure this setting via the [**Project Config API**](https://docs.cortecs.ai/advanced-usage/project-configuration/update-project-config), ensuring all team requests follow the same policy. 🏢

## When to use Quantization

* Reduce latency for real-time or high-throughput workloads
* Lower inference costs at scale
* Accept small accuracy trade-offs in exchange for performance gains

## Compliance Focus

* Quantized and non-quantized endpoints are **GDPR compliant**
* Data is **never used for model training**
* Quantization alters inference behavior, which may impact EU AI Act conformity assessments. Disable this setting if strict adherence to the original model behavior is required.


# Agents & Automations

Connect autonomous agents and automation tools to Cortecs

Cortecs works with agents and automation tools that support OpenAI-compatible or Anthropic-compatible endpoints.

* [Claude Code](/integration-examples/agents-and-automations/claude-code)
* [Hermes Agent](/integration-examples/agents-and-automations/hermes-agent)
* [n8n](/integration-examples/agents-and-automations/n8n)
* [OpenClaw](/integration-examples/agents-and-automations/openclaw)
* [Pydantic AI](/integration-examples/agents-and-automations/pydantic-ai)


# Claude Code

Use Cortecs models with Claude Code

[Claude Code](https://code.claude.com/) is Anthropic's terminal-based coding agent. Connect it to Cortecs through the Anthropic-compatible Messages API.

{% hint style="info" %}
Before you begin, create a Cortecs API key by following the [Quickstart](/quickstart) and choose a tool-calling model from the [model catalog](https://cortecs.ai/serverlessModels).
{% endhint %}

## 1. Install Claude Code

On macOS, Linux, or WSL:

```bash
curl -fsSL https://claude.ai/install.sh | bash
```

See the [Claude Code setup guide](https://code.claude.com/docs/en/setup) for other platforms.

## 2. Connect to Cortecs

Set the following variables in the terminal where you will run Claude Code:

```bash
export ANTHROPIC_BASE_URL="https://api.cortecs.ai"
export ANTHROPIC_AUTH_TOKEN="<API_KEY>"
unset ANTHROPIC_API_KEY

export ANTHROPIC_MODEL="<MODEL_ID>"
export ANTHROPIC_DEFAULT_OPUS_MODEL="<MODEL_ID>"
export ANTHROPIC_DEFAULT_SONNET_MODEL="<MODEL_ID>"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="<MODEL_ID>"
export CLAUDE_CODE_SUBAGENT_MODEL="<MODEL_ID>"

claude
```

Use the base URL without `/v1`; Claude Code adds `/v1/messages`. Run `/status` inside Claude Code to confirm that the Anthropic base URL points to Cortecs.

For persistent or managed configuration, see the [Claude Code gateway documentation](https://code.claude.com/docs/en/llm-gateway-connect).


# Hermes Agent

Use Cortecs models with Hermes Agent

[Hermes Agent](https://hermes-agent.nousresearch.com/) is an autonomous agent from Nous Research with persistent memory, tools, and messaging integrations. It supports custom OpenAI-compatible endpoints.

{% hint style="info" %}
Before you begin, create a Cortecs API key by following the [Quickstart](/quickstart) and choose a tool-calling model from the [model catalog](https://cortecs.ai/serverlessModels).
{% endhint %}

## 1. Install Hermes Agent

On macOS, Linux, or WSL:

```bash
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
```

See the [Hermes Agent documentation](https://hermes-agent.nousresearch.com/docs) for other platforms.

## 2. Connect to Cortecs

Run:

```bash
hermes model
```

Select **Custom endpoint**, then enter:

* **API base URL:** `https://api.cortecs.ai/v1`
* **API key:** Your Cortecs API key
* **Model name:** The exact Cortecs model ID
* **Context length (if prompted):** The catalog value; Hermes requires at least 64,000 tokens

Start the agent with:

```bash
hermes chat
```

For more configuration options, see the [Hermes Agent provider documentation](https://hermes-agent.nousresearch.com/docs/integrations/providers).


# n8n

Use Cortecs models in automated n8n workflows

[n8n](https://n8n.io/) is a workflow automation platform with built-in AI nodes. Because Cortecs provides an OpenAI-compatible API, you can use Cortecs models in n8n without installing a community node.

{% hint style="info" %}
Before you begin, create a Cortecs API key by following the [Quickstart](/quickstart) and choose a model from the [model catalog](https://cortecs.ai/serverlessModels).
{% endhint %}

## 1. Create a Cortecs credential

1. In n8n, open **Credentials**, create a credential, and select **OpenAI**.
2. Enter the following values:
   * **API Key:** Your Cortecs API key
   * **Base URL:** `https://api.cortecs.ai/v1`
   * **Organization ID:** Leave blank
3. Save the credential.

## 2. Add a Cortecs model

1. Add an **OpenAI Chat Model** node to an AI Agent, Basic LLM Chain, or another AI workflow.
2. Select the Cortecs credential.
3. Select a model or enter its exact model ID from the [model catalog](https://cortecs.ai/serverlessModels).
4. Leave **Use Responses API** enabled. It is the n8n default and the recommended option for AI Agent workflows. Disable it only if you need the Cortecs Chat Completions endpoint.
5. Run the workflow to test the connection.

For an **AI Agent**, choose a model that supports tool calling.

For API details, see the Cortecs [Responses API](https://docs.cortecs.ai/api-overview/responses-beta). For node-specific options, see the [n8n OpenAI Chat Model documentation](https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.lmchatopenai/).


# OpenClaw

The AI that actually does things

[OpenClaw](https://openclaw.ai/) brings your AI agents directly into your daily conversations on WhatsApp, Telegram, or Matrix. OpenClaw is a self-hosted solution that lets you interact with your personal assistants from anywhere, keeping infrastructure under your control.

This guide will walk you through the setup process and show you how to combine **OpenClaw** with **Cortecs.**

{% hint style="info" %}
*Before you begin: Make sure you have generated your Cortecs API key. If not, check out our* [*QuickStart*](https://docs.cortecs.ai/quickstart) *guide.*
{% endhint %}

## 1. Install OpenClaw

Run the following command in your terminal to install OpenClaw

```apache
curl -fsSL https://openclaw.ai/install.sh | bash
```

For additional installation options, refer to the [OpenClaw documentation](https://docs.openclaw.ai/install).

## 2. Complete Onboarding

After the installation completes, the onboarding process starts automatically. If this is not the case, run the following command

```
openclaw onboard --install-daemon
```

During onboarding configure the system to your liking. Answer the following options when prompted:

1. Model/auth provider: **Custom Provider**
2. API Base URL: **<https://api.cortecs.ai/v1>**
3. How do you want to provide this API key: **Paste API key now**
4. API Key: **Paste your generated Cortecs API key**
5. Endpoint compatibility: **OpenAI Responses-compatible**
6. Model ID: Copy the exact ID of your preferred model from the [model catalog](https://cortecs.ai/serverlessModels).
7. Endpoint ID: **cortecs**
8. *... Proceed with the remainder of the configuration to your liking*

{% hint style="info" %}
The Cortecs [Responses API](https://docs.cortecs.ai/api-overview/responses-beta) is recommended for OpenClaw agent workflows. Choose **OpenAI-compatible** only if a model or workflow requires Chat Completions.
{% endhint %}

Your default model is now set up, and you are able to chat with your model using the dashboard provided by OpenClaw.

Set up your connected communication gateway by running the following command in your terminal:

```
openclaw tui
```

## 3. Adding Multiple Models (Optional)

You can configure multiple models using a single API key. The various models are listed in our [catalog](https://cortecs.ai/serverlessModels).

Adding new models to OpenClaw is very straightforward. The simplest approach is to prompt your default model to add new ones. By pasting the following prompt into the chat, OpenClaw is automatically able to add your model. Adapt the prompt to use a model of your liking, or add multiple if desired.

```
Add the model <MODEL_ID> from provider cortecs to my config.
Add it to the models and the agents sections in the config.
Then restart the gateway.
```

Now you are able to switch to the new model/s using the command

```
/model <MODEL_ID>
```

For faster switching, you can prompt OpenClaw to assign aliases to the models. Then you can switch using your defined alias with the following commands, for example:

```
/model oss
/model opus
/model mini
```


# Pydantic AI

Build Pydantic AI agents with Cortecs

[Pydantic AI](https://ai.pydantic.dev/) can use a custom OpenAI-compatible provider. Its Responses model is the preferred option for new Cortecs agents.

## 1. Install Pydantic AI

```bash
pip install "pydantic-ai-slim[openai]"
```

## 2. Configure a Responses model

```python
import os

from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIResponsesModel
from pydantic_ai.providers.openai import OpenAIProvider

provider = OpenAIProvider(
    base_url="https://api.cortecs.ai/v1",
    api_key=os.environ["CORTECS_API_KEY"],
)

model = OpenAIResponsesModel(
    os.environ["CORTECS_MODEL"],
    provider=provider,
)

agent = Agent(
    model,
    instructions="Answer with a short, practical explanation.",
)

result = agent.run_sync("How does provider routing improve reliability?")
print(result.output)
```

Choose a model that lists `tools` in `supported_features` before adding Pydantic AI tools. Cortecs does not currently document OpenAI-managed conversation storage, so avoid Pydantic AI features that depend on that service.

## Chat Completions fallback

If a Pydantic AI feature or model requires Chat Completions, change only the model class:

```python
from pydantic_ai.models.openai import OpenAIChatModel

model = OpenAIChatModel(
    os.environ["CORTECS_MODEL"],
    provider=provider,
)
```

Both configurations use the same Cortecs base URL and API key. See [API Compatibility](/api-overview/api-compatibility) for endpoint differences and [Advanced Usage](/routing/advanced-usage) for routing controls.

See the current [Pydantic AI OpenAI model documentation](https://pydantic.dev/docs/ai/models/openai/) for framework-specific options. Use only options that also appear in the Cortecs API reference.


# Coding

One of the fastest-growing applications for LLMs is coding. A rising number of open-source coding tools let users integrate their preferred LLMs. Pairing these tools with privacy-preserving LLMs ensures your source code remains secure, cannot be used for training, and won’t be leaked.

Additionally, they provide precise cost control down to the token level, avoiding expensive enterprise subscriptions.

You can connect any coding agent that supports OpenAI-compatible endpoints. Here are quickstart guides to help you get started with some of the most popular tools:

* [Opencode](/integration-examples/coding/opencode)
* [Kilo Code](/integration-examples/coding/kilo-code)
* [Cline](/integration-examples/coding/cline)
* [GitHub Copilot](/integration-examples/coding/github-copilot)
* [Pi](/integration-examples/coding/pi)


# Opencode

AI coding agent built for the terminal

[**Opencode**](https://opencode.ai/) is a powerful, open-source AI coding agent built specifically for the terminal, featuring a native, responsive, and themeable terminal user interface. **Opencode** offers developers terminal-based coding assistance, debugging, file management, and command execution — all within the CLI.<br>

This guide will walk you through the setup process and show you how to combine **Opencode** with **Cortecs** for enhanced productivity.

{% hint style="info" %}
*Before you begin: Make sure you have generated your Cortecs API key. If not, check out our* [*QuickStart*](https://docs.cortecs.ai/quickstart) *guide.*
{% endhint %}

## 1. Install Opencode

Run the following command in your terminal to install Opencode:

```apache
curl -fsSL https://opencode.ai/install | bash
```

For additional installation options, refer to the [Opencode documentation](https://opencode.ai/docs#install).

## 2. Connect to cortecs

Cortecs provides a **native integration** for Opencode:

1. Run the authentication command:

```bash
opencode auth login
```

2. Select **Cortecs** as the provider:

<figure><img src="/files/ZUkbKWqLgeAoa2BZZzDo" alt="" width="563"><figcaption></figcaption></figure>

3. Enter your **Cortecs API key** and press Enter:

<figure><img src="/files/l0vS35VSN1UWUcxhvlh4" alt="" width="563"><figcaption></figcaption></figure>

Your authentication is now complete :white\_check\_mark:.

## 3. Start using Opencode

1. Launch Opencode by typing `opencode` in your console:

<figure><img src="/files/mwJoxsOxi49UYs0zMEFE" alt="" width="563"><figcaption></figcaption></figure>

2. Once the Opencode terminal opens, start a new session using `/new`, then use `/models` to view and select a model:

<figure><img src="/files/q5iPsmvBR5U4SM1FDmJ7" alt="" width="563"><figcaption></figcaption></figure>

Choose the model you want to use and press Enter ✅.

> 💡 **Tip:** If you’re looking for a specific model, you can either:
>
> * Join the [Discord](https://discord.com/invite/bPFEFcWBhp) community 💬 and request it, or
> * Add it directly to the [Models.dev](https://github.com/sst/models.dev/tree/dev/providers/cortecs/models) open-source database in the Cortecs provider folder.

**You’re all set!** 🎉

You can now start a discussion with your AI agent!

<figure><img src="/files/VosUFUA6QfaCECHhvqtY" alt="" width="563"><figcaption></figcaption></figure>

Enjoy the power of **Cortecs** and **Opencode**, explore different models, and share feedback with the community on [Discord](https://discord.com/invite/bPFEFcWBhp) 👩‍💻👨‍💻.


# Kilo Code

Autonomous coding agent right in your IDE

[**Kilo Code**](https://kilocode.ai/docs/) is one of the most popular coding assistants available today, and it’s completely free as a Visual Studio Code extension. By combining Kilo Code with Cortecs, you can create a privacy-preserving coding assistant. This guide will walk you through the setup.

{% hint style="info" %}
*Before you begin: Make sure you have generated your Cortecs API key. If not, check out our* [*QuickStart*](/quickstart) *guide.*
{% endhint %}

## 1. Install Kilo Code

First, install the **Kilo Code** extension in your VS Code. You can find it in the [Visual Studio Code Marketplace](https://marketplace.visualstudio.com/items?itemName=kilocode.Kilo-Code). Follow the official installation instructions.

Once installed, you’ll need to configure an **external provider**.

The first thing is to install the extension in your VSCode. See the [official documentation](https://kilocode.ai/install) to see how to do that.

## 2. Connect to cortecs

Cortecs provides **OpenAI-compatible API endpoints**, making it easy to integrate with Kilo Code and many other tools.

Use the following settings to connect Kilo Code to Cortecs:\
– **API Provider:** OpenAI Compatible\
– **Base URL:** <code class="expression">space.vars.DEFAULT\_API\_BASE\_URL</code>\
– **API Key:** Your API Key\
– **Model:** <code class="expression">space.vars.DEFAULT\_CODING\_MODEL</code> (feel free to pick another one from the [catalogue](https://cortecs.ai/serverlessModels))

## 3. (Optional) Enable Local Code Indexing

To improve context awareness, enable [**code indexing**](https://kilocode.ai/docs/features/codebase-indexing). It can be deployed locally, so no code is stored outside of your computer.

1. Start a local Qdrant vector database: docker `docker run -p 6333:6333 qdrant/qdrant`
2. In Kilo Code, click the **Indexing** button in the bottom-right corner (see screenshot).
3. Configure the embedding model:

   – **API Provider:** OpenAI Compatible\
   – **Base URL:** <https://api.cortecs.ai/v1/\\>
   – **API Key:** Your API Key\
   – **Model:** bge-large-en-v1.5 (feel free to pick another one from the [catalogue](https://cortecs.ai/serverlessModels))

   \- **Model dimension:** 1024 (reasonable default)
4. Save the settings and press *Start indexing*.

Once complete, Kilo Code will have full local context of your codebase — without sending data to external servers.

<figure><img src="/files/cAUrvj0QYOfZjPEVMQ7g" alt="" width="188"><figcaption></figcaption></figure>

Enjoy your **privacy-preserving coding assistant** with the power of Cortecs and Kilo Code. Explore other models, tweak the setup to your needs, and join the conversation on our [Discord](https://discord.com/invite/bPFEFcWBhp) to share feedback 👩‍💻👨‍💻


# Cline

Autonomous coding agent right in your IDE

[Cline](https://docs.cline.bot/getting-started/what-is-cline) is an open source AI coding agent that brings frontier AI models directly to your VS Code editor. Unlike autocomplete tools, Cline is a true coding agent that can understand entire codebases, plan complex changes, and execute multi-step tasks. This guide will walk you through the setup.

{% hint style="info" %}
*Before you begin: Make sure you have generated your Cortecs API key. If not, check out our* [*QuickStart*](/quickstart) *guide.*
{% endhint %}

## 1. Install Cline

First, install the **Cline** extension in your VS Code. You can find it by following the instructions on their [website](https://cline.bot/) or in the [Visual Studio Code Marketplace](https://marketplace.visualstudio.com/items?itemName=saoudrizwan.claude-dev).

<figure><img src="/files/kXOvUWZ4hl8DFSmXy2mJ" alt=""><figcaption></figcaption></figure>

Once installed, you’ll need to configure an **external provider**.

## 2. Connect to cortecs

Cortecs provides **OpenAI-compatible API endpoints**, making it easy to integrate with Cline and many other tools.

To set up the connection, follow these steps:

1. Select `Use your own API key` on first start or navigate to the Settings
2. Configure the connection with the following settings:\
   – **API Provider:** OpenAI Compatible\
   – **Base URL:** <code class="expression">space.vars.DEFAULT\_API\_BASE\_URL</code>\
   – **API Key:** Your API Key\
   – **Model:** <code class="expression">space.vars.DEFAULT\_CODING\_MODEL</code> (feel free to pick another one from the [catalogue](https://cortecs.ai/serverlessModels))

<figure><img src="/files/i1XvddQviJMllDvRe30C" alt="" width="375"><figcaption></figcaption></figure>

Enjoy your **privacy-preserving coding assistant** with the power of Cortecs and Cline. Explore other models, tweak the setup to your needs, and join the conversation on our [Discord](https://discord.com/invite/bPFEFcWBhp) to share feedback 👩‍💻👨‍💻


# GitHub Copilot

Use Cortecs models in GitHub Copilot Chat

Visual Studio Code supports custom model endpoints for GitHub Copilot Chat. Connect Cortecs to use its models for chat and agent tools in VS Code.

{% hint style="info" %}
Before you begin, create a Cortecs API key by following the [Quickstart](/quickstart) and choose a tool-calling model from the [model catalog](https://cortecs.ai/serverlessModels).
{% endhint %}

## 1. Add a custom endpoint

1. Install the latest Visual Studio Code and the **GitHub Copilot Chat** extension.
2. Open the Command Palette and run **Chat: Manage Language Models**.
3. Select **Add Models**, then **Custom Endpoint**.
4. Use **Cortecs** as the group and display name, enter your Cortecs API key, and select **Responses** as the API type.

## 2. Configure a model

VS Code opens `chatLanguageModels.json`. Update the generated model entry with:

* **id:** The exact Cortecs model ID
* **name:** The label shown in the model picker
* **url:** `https://api.cortecs.ai/v1/responses`
* **toolCalling:** `true` for a model that supports tool calling
* **vision:** `true` only for a model that supports image input
* **maxOutputTokens:** A supported output limit for the model
* **maxInputTokens:** The model's context size minus `maxOutputTokens`

Use the [model catalog](https://cortecs.ai/serverlessModels) to check capabilities and context size. Keep the API key value generated by VS Code instead of adding the key directly to version-controlled files.

Save the file, return to Copilot Chat, and select the Cortecs model from the model picker. If it does not appear, reload VS Code.

{% hint style="info" %}
The Cortecs [Responses API](https://docs.cortecs.ai/api-overview/responses-beta) is recommended for reasoning, tool-calling, and multi-turn agent workflows. VS Code also supports **Chat Completions**; select it and use `https://api.cortecs.ai/v1/chat/completions` only if a model or workflow requires that API.
{% endhint %}

{% hint style="warning" %}
Custom endpoints power Copilot Chat and agent features, but not inline code completions, semantic search, or other embedding-based features.
{% endhint %}

For the full configuration schema, see the [Visual Studio Code language model documentation](https://code.visualstudio.com/docs/agent-customization/language-models#_add-a-custom-endpoint-model).


# Pi

Use Cortecs models with the Pi coding agent

[Pi](https://pi.dev/) is a terminal-based coding agent that supports custom OpenAI-compatible providers. Cortecs can be added directly through Pi's model configuration.

{% hint style="info" %}
Before you begin, create a Cortecs API key by following the [Quickstart](/quickstart) and choose a tool-calling model from the [model catalog](https://cortecs.ai/serverlessModels).
{% endhint %}

## 1. Install Pi

Install Pi with Node.js and npm:

```bash
npm install -g --ignore-scripts @earendil-works/pi-coding-agent
```

## 2. Add Cortecs

Create or update `~/.pi/agent/models.json`:

```json
{
  "providers": {
    "cortecs": {
      "baseUrl": "https://api.cortecs.ai/v1",
      "api": "openai-responses",
      "apiKey": "$CORTECS_API_KEY",
      "models": [
        { "id": "<MODEL_ID>" }
      ]
    }
  }
}
```

{% hint style="info" %}
The Cortecs [Responses API](https://docs.cortecs.ai/api-overview/responses-beta) is recommended for Pi's agent workflows. Change `api` to `openai-completions` only if a model or workflow requires Chat Completions.
{% endhint %}

Replace `<MODEL_ID>` with the exact ID from the model catalog. Add more entries to `models` if you want to use several models.

## 3. Start Pi

Set your API key and launch Pi:

```bash
export CORTECS_API_KEY="<API_KEY>"
pi
```

Run `/model` inside Pi and select the model listed under **cortecs**.

For additional model options, see Pi's [custom model documentation](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/models.md).


# Chat

Open-source chat platforms allow you to integrate your preferred LLM while maintaining full control over your data. By using privacy-preserving endpoints, you can prevent data leaks and ensure enterprise compliance.

At the same time, these solutions provide precise cost control down to the token level, helping you avoid expensive enterprise subscriptions.

You can connect any chat application that supports **OpenAI-compatible** endpoints. Here are quickstart guides to help you get started with [Open WebUI](/integration-examples/chat/open-webui) or [LobeChat](/integration-examples/chat/lobechat).


# Open WebUI

A Privacy-Preserving Chat Assistant

[**Open WebUI**](https://docs.openwebui.com/) is an extensible, feature-rich, and user-friendly self-hosted AI platform. By combining **Open WebUI** with Cortecs, you can create a privacy-preserving AI Chatbot Platform. This guide will walk you through the setup process.

{% hint style="info" %}
*Before you begin: Make sure you have generated your Cortecs API key. If not, check out our* [*QuickStart*](/quickstart) *guide.*
{% endhint %}

## 1. Deploy Open WebUI

There are multiple ways to deploy Open WebUI.

To get started quickly, follow the official [Quick Start guide](https://docs.openwebui.com/getting-started/quick-start/) for Open WebUI.

Once installation is complete, you’ll need to configure the external provider.

## 2. Connect to cortecs

Cortecs provides **OpenAI-compatible API endpoints**, making it easy to integrate with [Open WebUI](https://docs.openwebui.com/getting-started/quick-start/starting-with-openai-compatible) and many other tools. To connect:

1. Open Open WebUI in your browser.
2. Go to ⚙️ **Settings -> Admin Settings** → **Connections**.
3. At **Manage OpenAI API Connections c**lick ➕ **Add Connection.**
   1. **Base URL:** <code class="expression">space.vars.DEFAULT\_API\_BASE\_URL</code>
   2. **API Key:** Your API Key
4. Click Save.

<figure><img src="/files/fnAGaSNy7SazrDx0ygZA" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Cortecs Endpoints are **OpenAI compatibl**e to make easier its integration in a lot of products.
{% endhint %}

## 3. (Optional) Configure a Embedding Model

By default, Open WebUI uses **SentenceTransformers** for embedding generation. You can optionally switch to a Cortecs embedding model. To configure:

1. Open Open WebUI in your browser.
2. Go to ⚙️ **Settings** → **Admin Settings** → **Documents** → **Embedding**.
   1. **Embedding Model Engine:** OpenAI
   2. **Base URL:** `https://api.cortecs.ai/v1/`
   3. **API Key:** Your API Key
   4. **Embedding Model:** Choose one of the embedding models of the [models list](https://cortecs.ai/serverlessModels)
3. Click Save.

<figure><img src="/files/UNQysvfBL3qgFVTzGLgA" alt=""><figcaption></figcaption></figure>

## 4. Start Chatting!

You're all set!

* Open the chat interface.
* Select your connected server's model from the model menu.
* Start chatting with your AI assistant.

<figure><img src="/files/BKYT3bdZlt055Wr3CgVy" alt=""><figcaption></figcaption></figure>


# LobeChat

A Privacy-Preserving Chat Assistant

[LobeChat](https://lobehub.com/de/docs/usage/start) is an open-source, modern design ChatGPT/LLMs UI/framework. This guide will walk you through the setup process.

{% hint style="info" %}
*Before you begin: Make sure you have generated your Cortecs API key. If not, check out our* [*QuickStart*](/quickstart) *guide.*
{% endhint %}

## 1. Deploy LobeChat

There are multiple ways to deploy LobeChat.

To get started quickly, follow the official [Quick Start guide](https://lobehub.com/de/docs/self-hosting/start) for LobeChat.

Once installation is complete, you’ll need to configure the external provider.

## 2. Connect to cortecs

Cortecs provides **OpenAI-compatible API endpoints**, making it easy to integrate with LobeChat and many other tools. To connect:

1. Open LobeChat in your browser.
2. Go to ⚙️ **Settings** → **Language Model** → **OpenAI**.
   1. **API Key:** Your API Key
   2. **API Proxy Address:** <code class="expression">space.vars.DEFAULT\_API\_BASE\_URL</code>
   3. Click `Get Model List`.
   4. Select Models to show

## 4. Start Chatting!

You're all set!

* Open the chat interface.
* Select your connected server's model from the model menu.
* Start chatting with your AI assistant.

<figure><img src="/files/UjEuXdudJzpA4LfVTnbM" alt=""><figcaption></figcaption></figure>


# Tooling

Enterprise developers increasingly rely on agent orchestration frameworks to build, deploy, and manage complex LLM-powered applications. These frameworks let you:

* Chain LLM calls for multi-step reasoning,
* Connect to private data sources like databases and vector stores,
* Monitor performance and output quality.

These frameworks are flexible and model-agnostic, allowing connections to any **OpenAI-compatible** endpoint. This lets developers switch between open-source or commercial LLMs to optimize cost, performance, or capabilities.

You can connect any framework that supports OpenAI-compatible endpoints. Here are quickstart guides to help you get started with [LangChain](/integration-examples/tooling/langchain) or [Langfuse](/integration-examples/tooling/langfuse).

Additional guides are available for the [OpenAI SDK](/integration-examples/tooling/openai-sdk), [Vercel AI SDK](/integration-examples/tooling/vercel-ai-sdk), and [LlamaIndex](/integration-examples/tooling/llamaindex).


# OpenAI SDK

Use the official OpenAI SDKs with Cortecs

The official OpenAI Python and JavaScript SDKs can call Cortecs through its compatible APIs. Prefer the Responses API for new agent workflows and use Chat Completions when a library or model requires it.

{% hint style="info" %}
Create a Cortecs API key by following the [Quickstart](/quickstart), then choose a model with the required capabilities from the [Models API](/api-overview/models).
{% endhint %}

## Responses API

{% tabs %}
{% tab title="Python" %}
Install the SDK:

```bash
pip install openai
```

```python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.cortecs.ai/v1",
    api_key=os.environ["CORTECS_API_KEY"],
)

response = client.responses.create(
    model=os.environ["CORTECS_MODEL"],
    instructions="Answer concisely.",
    input="Name three uses for semantic search.",
    extra_body={"preference": "balanced"},
)

print(response.output_text)
```

{% endtab %}

{% tab title="JavaScript" %}
Install the SDK:

```bash
npm install openai
```

```javascript
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.cortecs.ai/v1",
  apiKey: process.env.CORTECS_API_KEY,
});

const response = await client.responses.create({
  model: process.env.CORTECS_MODEL,
  instructions: "Answer concisely.",
  input: "Name three uses for semantic search.",
});

console.log(response.output_text);
```

{% endtab %}
{% endtabs %}

The JavaScript SDK does not expose Cortecs routing fields as typed parameters. Set project defaults in Cortecs or use a client that supports custom request body fields when per-request routing is required.

## Chat Completions fallback

Use this shape when a dependency only supports Chat Completions:

```python
completion = client.chat.completions.create(
    model=os.environ["CORTECS_MODEL"],
    messages=[
        {"role": "system", "content": "Answer concisely."},
        {"role": "user", "content": "Name three uses for semantic search."},
    ],
    extra_body={"preference": "balanced"},
)

print(completion.choices[0].message.content)
```

The fallback endpoint is `https://api.cortecs.ai/v1/chat/completions`. See [API Compatibility](/api-overview/api-compatibility) before translating more advanced Responses requests.

For request-shape differences, see OpenAI's [Responses migration guide](https://developers.openai.com/api/docs/guides/migrate-to-responses). Cortecs compatibility is limited to the fields in the Cortecs API reference.


# Vercel AI SDK

Use Cortecs with the Vercel AI SDK

The Vercel AI SDK supports both the Responses API and OpenAI-compatible Chat Completions. Use Responses for new agent workflows.

## Responses API

Install the required packages:

```bash
npm install ai @ai-sdk/openai
```

Configure the OpenAI provider with the Cortecs base URL:

```typescript
import { createOpenAI } from "@ai-sdk/openai";
import { generateText } from "ai";

const cortecs = createOpenAI({
  name: "cortecs",
  apiKey: process.env.CORTECS_API_KEY,
  baseURL: "https://api.cortecs.ai/v1",
});

const { text } = await generateText({
  model: cortecs.responses(process.env.CORTECS_MODEL!),
  prompt: "Explain model routing in two sentences.",
});

console.log(text);
```

Choose a model that advertises the capabilities your application uses in the [Models API](/api-overview/models).

## Chat Completions fallback

If a workflow or middleware expects Chat Completions, use the OpenAI-compatible provider:

```bash
npm install @ai-sdk/openai-compatible
```

```typescript
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { generateText } from "ai";

const cortecs = createOpenAICompatible({
  name: "cortecs",
  apiKey: process.env.CORTECS_API_KEY,
  baseURL: "https://api.cortecs.ai/v1",
});

const { text } = await generateText({
  model: cortecs.chatModel(process.env.CORTECS_MODEL!),
  prompt: "Explain model routing in two sentences.",
  providerOptions: {
    cortecs: {
      preference: "balanced",
    },
  },
});

console.log(text);
```

Provider options are forwarded in the request body by the OpenAI-compatible provider. See [Advanced Usage](/routing/advanced-usage) for the Cortecs routing fields you can pass.

See the Vercel AI SDK documentation for the [OpenAI provider](https://ai-sdk.dev/providers/ai-sdk-providers/openai) and [OpenAI-compatible providers](https://ai-sdk.dev/providers/openai-compatible-providers).


# LangChain

A framework for orchestrating LLMs

[LangChain](https://www.langchain.com/) is a framework for building and deploying applications powered by large language models (LLMs), streamlining the entire lifecycle from development to production.

It offers open-source components and integrations for building applications, LangGraph for creating stateful agents with streaming and human-in-the-loop support, and LangSmith for inspecting, monitoring, and evaluating performance to ensure optimization.

Finally, with LangGraph Platform, developers can deploy their applications as production-ready APIs and Assistants.

This guide will walk you through the setup.

{% hint style="info" %}
*Before you begin: Make sure you have generated your Cortecs API key. If not, check out our* [*QuickStart*](/quickstart) *guide.*
{% endhint %}

## 1. Install LangChain

LangChain offers both [Python](https://python.langchain.com/docs/how_to/installation/) and [JavaScript](https://js.langchain.com/docs/how_to/installation/) libraries.

To get started quickly, follow the installation instructions in the documentation for your preferred language.

Once the framework is installed, you can begin building applications by connecting to an external provider.

## 2. Connect to cortecs

Cortecs provides **OpenAI-compatible API endpoints**, making it easy to integrate with LangChain and many other tools.

To connect and use the LLM, create an `ChatOpenAI` object, with the following settings:

– `api_key`: Your API Key\
– `base_url`: <code class="expression">space.vars.DEFAULT\_API\_BASE\_URL</code>\
– `model`: <code class="expression">space.vars.DEFAULT\_CHAT\_MODEL</code> (feel free to pick another one from the [catalogue](https://cortecs.ai/serverlessModels))\
– (optional) `extra_body`: `{"preference": "balanced"}`

```python
from langchain_openai import ChatOpenAI
from pydantic import SecretStr

llm = ChatOpenAI(
    model="gpt-5-mini",
    # you also can use env vars to configure base_url and api_key
    api_key=SecretStr("eyJhbG***"),
    base_url="https://api.cortecs.ai/v1",
    extra_body= {"preference": "balanced"}
)

print(llm.invoke("Hi").content)
```

### 2.1. Embedding Model

To create embeddings and use LangChain with vector databases, you can instantiate an `OpenAIEmbeddings` object with the following settings:

– `api_key`: Your API Key\
– `base_url`: <code class="expression">space.vars.DEFAULT\_API\_BASE\_URL</code>\
– `model`: <code class="expression">space.vars.DEFAULT\_EMBEDDING\_MODEL</code> (feel free to pick another embedding model from the [catalogue](https://cortecs.ai/serverlessModels))\
– (optional) `model_kwargs`: `{"extra_body": {"preference": "balanced"}}`

```python
from langchain_openai import OpenAIEmbeddings
from pydantic import SecretStr

embedding_model = OpenAIEmbeddings(
    model="text-embedding-3-large",
    api_key=SecretStr("eyJhbG***"),
    base_url="https://api.cortecs.ai/v1",
    model_kwargs= {"extra_body": {"preference": "balanced"}}
)

print(embedding_model.embed_query("Hi"))
```

Enjoy your **privacy-preserving LLM applications** with the power of Cortecs and LangChain. Explore other models, tweak the setup to your needs, and join the conversation on our [Discord](https://discord.com/invite/bPFEFcWBhp) to share feedback 👩‍💻👨‍💻


# LlamaIndex

Use LlamaIndex with Cortecs through Chat Completions

LlamaIndex provides an OpenAI-compatible adapter for custom inference services. The adapter uses Chat Completions, so treat this integration as a fallback when your workflow cannot use the Cortecs Responses API.

## 1. Install the adapter

```bash
pip install llama-index-llms-openai-like
```

## 2. Connect to Cortecs

```python
import os

from llama_index.llms.openai_like import OpenAILike

llm = OpenAILike(
    model=os.environ["CORTECS_MODEL"],
    api_base="https://api.cortecs.ai/v1",
    api_key=os.environ["CORTECS_API_KEY"],
    is_chat_model=True,
    is_function_calling_model=True,
)

response = llm.complete("Explain semantic search in two sentences.")
print(response)
```

Set `is_function_calling_model=True` only when the selected model lists `tools` in `supported_features` in the [Models API](/api-overview/models). For Responses-native agents, use the [OpenAI SDK](/integration-examples/tooling/openai-sdk), [Vercel AI SDK](/integration-examples/tooling/vercel-ai-sdk) or [Pydantic AI](/integration-examples/agents-and-automations/pydantic-ai) instead.

See the LlamaIndex [OpenAI-like adapter source and usage guide](https://github.com/run-llama/llama_index/tree/main/llama-index-integrations/llms/llama-index-llms-openai-like) for current adapter options.


# Langfuse

Open Source LLM Engineering Platform

[Langfuse](https://langfuse.com/) is an open-source LLM engineering platform that helps teams collaboratively debug, analyze, and iterate on their LLM applications.

All platform features are natively integrated to accelerate the development workflow. Langfuse is open, self-hostable, and extensible.

This guide will walk you through the setup.

{% hint style="info" %}
*Before you begin: Make sure you have generated your Cortecs API key. If not, check out our* [*QuickStart*](/quickstart) *guide.*
{% endhint %}

## 1. Deploy Langfuse

There are multiple ways to deploy Langfuse.

To get started quickly, choose your preferred deployment strategy and follow the instructions in the [documentation](https://langfuse.com/self-hosting).

Once deployment is complete, you’ll need to configure an external provider.

## 2. Connect to cortecs

Cortecs provides **OpenAI-compatible API endpoints**, making it easy to integrate with Langfuse and many other tools.

### 2.1. Prompt Management

One of the core features of Langfuse is [prompt management](https://langfuse.com/docs/prompt-management/overview), which includes storing, versioning, and retrieving your prompts. To experiment with prompts, Langfuse needs to be connected to an LLM provider such as Cortecs.

To set up the connection, follow these steps in the administration console:

1. Navigate to `Settings -> LLM-Connections`
2. Configure the connection with the following settings:\
   – **LLM adapter:** openai\
   – **API Key:** Your API Key\
   – **API Base URL:** <code class="expression">space.vars.DEFAULT\_API\_BASE\_URL</code>\
   – **Enable default models:** Disabled\
   – **Add custom model name:** <code class="expression">space.vars.DEFAULT\_CHAT\_MODEL</code> (feel free to pick another one from the [catalogue](https://cortecs.ai/serverlessModels))

<figure><img src="/files/AmAghcnk91pdvJYqwQcr" alt="" width="375"><figcaption></figcaption></figure>

Once the LLM connection is created, you can experiment with prompts, store versions, and later [retrieve and use them directly in your code](https://langfuse.com/docs/prompt-management/get-started).

<figure><img src="/files/YmznD4BA9j47K70juDfW" alt=""><figcaption></figcaption></figure>

```python
from langfuse._client.get_client import get_client

langfuse = get_client()
prompt = langfuse.get_prompt("Friend")
compiled_prompt = prompt.compile(name="Freddy")
```

### 2.2. Tracing

Langfuse provides [tracing capabilities](https://langfuse.com/docs/observability/overview) to monitor and analyze the calls made to an LLM. This feature allows you to gain visibility into model interactions and performance. To integrate tracing, Langfuse offers multiple options, including [drop-in replacements and flexible connection methods](https://langfuse.com/docs/observability/get-started), making it easy to incorporate into your existing codebase.

```python
from langfuse.openai import openai

client = openai.OpenAI(
    api_key="eyJhbG***",
    base_url="https://api.cortecs.ai/v1"
)

completion = client.chat.completions.create(
    model="gpt-5-mini",
    messages=[
        {"role": "system", "content": "You are a professional comedian."},
        {"role": "user", "content": "Tell me a joke."}],
    stream=True,
    extra_body={"preference": "balanced"}
)

for chunk in completion:
  print(chunk.choices[0].delta.content)

```

<figure><img src="/files/DhAKgcYtXyZVUEveLnJC" alt=""><figcaption></figcaption></figure>

Enjoy your **privacy-preserving LLM engineering platform** with the power of Cortecs and Langfuse. Explore other models, tweak the setup to your needs, and join the conversation on our [Discord](https://discord.com/invite/bPFEFcWBhp) to share feedback 👩‍💻👨‍💻


