> This page is for Model APIs.

> Sarvam Voice Agents (Samvaad) is a voice AI agent platform for Indian languages: build, test and deploy AI calling agents on your own phone numbers, from ₹3 a minute. Start here: https://docs.sarvam.ai/voice-agents/why-voice-agents.
> For clean Markdown of any page, append `.md` to the page URL.
> For a complete documentation index, see https://docs.sarvam.ai/llms.txt. For a section index, append `/llms.txt` to any section URL (for example https://docs.sarvam.ai/voice-agents/llms.txt).
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.sarvam.ai/_mcp/server.

# Migrating the Responses API from OpenRouter to Sarvam

> Request fields, reasoning items, function tools, streaming, and OpenRouter-only options to change when moving Responses API calls from OpenRouter to Sarvam's /v2/responses.

*Last updated: October 23, 2026*

This guide covers moving OpenRouter [Responses API](https://openrouter.ai/docs/api/reference/responses/overview)
calls to Sarvam's [`POST /v2/responses`](/api/token-factory/responses-api).
For Chat Completions, see [Migrating Chat Completion](/api/token-factory/migrations/from-openrouter/chat-completion).

> **Tip**
>
> **In short:** both Responses APIs are stateless, so your history handling carries over. Change
> `base_url`, `api_key`, and `model`, remove OpenRouter-only fields such as `provider`,
> `models`, and `plugins`, and replace server tools like `openrouter:web_search` with your own
> function tools.

## Migration checklist

1. Change `base_url` to `https://api.sarvam.ai/v2` and `api_key` to your Sarvam key.
2. Replace each model ID using the [model ID table](/api/token-factory/migrations/from-openrouter/overview#model-ids).
3. Remove OpenRouter-only fields: `provider`, `models`, `plugins`, and `stop` ([list](#fields-to-remove)).
4. Replace OpenRouter server tools with function tools you run yourself ([Tools](#tools)).
5. On `glm5.3` and `glm5.3-flash`, don't send `"max"`; omitting `reasoning.effort` gives `max` on `glm5.3` and `high` on `glm5.3-flash` ([Reasoning](#reasoning)).
6. Set `max_output_tokens`: it has no default cap on Sarvam.
7. If you use the `sarvamai` SDK, read the reply from the `message` item in `output` ([quick start](#quick-start)).

## Quick start

#### Before (OpenRouter)

#### Python (OpenAI SDK)

```python
from openai import OpenAI

client = OpenAI(
    api_key="YOUR_OPENROUTER_API_KEY",
    base_url="https://openrouter.ai/api/v1",
)

response = client.responses.create(
    model="deepseek/deepseek-v4-pro-0813",
    instructions="You are a helpful assistant.",
    input="Explain database indexing in three short points.",
    reasoning={"effort": "high"},
    max_output_tokens=3000,
    extra_body={"provider": {"sort": "throughput"}},
)

print(response.output_text)
```

#### JavaScript (OpenAI SDK)

```javascript
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: "YOUR_OPENROUTER_API_KEY",
  baseURL: "https://openrouter.ai/api/v1",
});

const response = await client.responses.create({
  model: "deepseek/deepseek-v4-pro-0813",
  instructions: "You are a helpful assistant.",
  input: "Explain database indexing in three short points.",
  reasoning: { effort: "high" },
  max_output_tokens: 3000,
  provider: { sort: "throughput" },
});

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

#### cURL

```bash
curl https://openrouter.ai/api/v1/responses \
  -H "Authorization: Bearer YOUR_OPENROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek/deepseek-v4-pro-0813",
    "input": "Explain database indexing in three short points.",
    "reasoning": {"effort": "high"},
    "max_output_tokens": 3000,
    "provider": {"sort": "throughput"}
  }'
```

#### After (Sarvam)

#### Python (OpenAI SDK)

```python
from openai import OpenAI

client = OpenAI(
    api_key="YOUR_SARVAM_API_KEY",
    base_url="https://api.sarvam.ai/v2",
)

response = client.responses.create(
    model="deepseekv4-pro",
    instructions="You are a helpful assistant.",
    input="Explain database indexing in three short points.",
    reasoning={"effort": "high"},
    max_output_tokens=3000,
)

print(response.output_text)
```

#### JavaScript (OpenAI SDK)

```javascript
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: "YOUR_SARVAM_API_KEY",
  baseURL: "https://api.sarvam.ai/v2",
});

const response = await client.responses.create({
  model: "deepseekv4-pro",
  instructions: "You are a helpful assistant.",
  input: "Explain database indexing in three short points.",
  reasoning: { effort: "high" },
  max_output_tokens: 3000,
});

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

#### Python (Sarvam SDK)

```python
from sarvamai import SarvamAI

client = SarvamAI(api_subscription_key="YOUR_SARVAM_API_KEY")

response = client.responses.create(
    model="deepseekv4-pro",
    instructions="You are a helpful assistant.",
    input="Explain database indexing in three short points.",
    reasoning={"effort": "high"},
    max_output_tokens=3000,
)

# The Sarvam SDK has no output_text shortcut; read the message item.
message = next(item for item in response.output if item.type == "message")
print(message.content[0].text)
```

#### JavaScript (Sarvam SDK)

```javascript
import { SarvamAIClient } from "sarvamai";

const client = new SarvamAIClient({ apiSubscriptionKey: "YOUR_SARVAM_API_KEY" });

const response = await client.responses.create({
  model: "deepseekv4-pro",
  instructions: "You are a helpful assistant.",
  input: "Explain database indexing in three short points.",
  reasoning: { effort: "high" },
  max_output_tokens: 3000,
});

const message = response.output.find((item) => item.type === "message");
console.log(message.content[0].text);
```

#### cURL

```bash
curl https://api.sarvam.ai/v2/responses \
  -H "api-subscription-key: YOUR_SARVAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseekv4-pro",
    "input": "Explain database indexing in three short points.",
    "reasoning": {"effort": "high"},
    "max_output_tokens": 3000
  }'
```

## Conversation history

Both APIs are stateless: send the whole conversation in `input` on every call. Code that
already does this for OpenRouter works unchanged. `previous_response_id`, `store: true`,
`conversation`, and `background: true` return `400` on Sarvam, as on OpenRouter.

## Reasoning

| OpenRouter                                  | Sarvam             | Note                                                                                                                                                     |
| ------------------------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `reasoning.effort`                          | `reasoning.effort` | `low`, `high`, or `max`. On `glm5.3` and `glm5.3-flash`, `"max"` returns `400`; omitting the field gives `max` on `glm5.3` and `high` on `glm5.3-flash`. |
| `reasoning.effort: "none"`                  | Same               | Turns thinking off on `deepseekv4-pro`, `mimo-v2.6-flash`, and `mimo-v2.6-pro`.                                                                          |
| `reasoning.max_tokens`, `reasoning.exclude` | Not supported      | Choose an effort level, and size `max_output_tokens` for reasoning plus the answer.                                                                      |
| `reasoning.summary`                         | Same               | With `"auto"` or `"detailed"`, the reasoning item's `summary` is filled.                                                                                 |
| Reasoning item in `output`                  | Same               | Read the trace from the item's `content[0].text`. `summary` is empty unless you set `reasoning.summary`.                                                 |

Reasoning tokens count toward `max_output_tokens`, which has no default cap on Sarvam.

## Tools

Sarvam's Responses API supports **function tools** only, in the same flat Responses format:
`{"type": "function", "name": ..., "parameters": ...}`. OpenRouter server tools, such as
`openrouter:web_search`, return `400`. Run those services from your own code and expose them as
function tools.

The function call round trip is the same as on OpenRouter: the model returns a
`function_call` item, you run the function, and you send back the call plus a
`function_call_output` item in the next request's `input`. See the [full example](#full-example).

|                              | Sarvam                                                                                            |
| ---------------------------- | ------------------------------------------------------------------------------------------------- |
| `tool_choice`                | `"auto"`, `"none"`, `"required"`, or a named function                                             |
| `parallel_tool_calls: false` | Limits a turn to one tool call on every open-weight model; `sarvam-105b` ignores it on this route |
| `max_tool_calls`             | Returns `400`                                                                                     |

## Fields to remove

Sarvam returns `400` with the field named for request fields it doesn't support.

| OpenRouter field                                                    | What to do on Sarvam                         |
| ------------------------------------------------------------------- | -------------------------------------------- |
| `provider`, `models`                                                | Remove. Retry on `429` and `503` yourself.   |
| `plugins`, `openrouter:*` server tools                              | Remove. Use function tools.                  |
| `stop`                                                              | Remove. Not a Responses parameter on Sarvam. |
| `max_tool_calls`                                                    | Remove. Stop the tool loop in your own code. |
| `previous_response_id`, `store: true`, `conversation`, `background` | Remove. Send the full history in `input`.    |

## Parameter concept map

| OpenRouter                                   | Sarvam                   | Note                                                                                                |
| -------------------------------------------- | ------------------------ | --------------------------------------------------------------------------------------------------- |
| `input` (string or items), `instructions`    | Same                     |                                                                                                     |
| `max_output_tokens`, `temperature`, `top_p`  | Same                     | Set `max_output_tokens`: there's no default cap.                                                    |
| `text.format` (`json_schema`, `json_object`) | Same                     |                                                                                                     |
| `input_image` content parts                  | Same                     | Inline base64 data URIs only, on models with image input.                                           |
| `input_audio` content parts                  | Same, on the MiMo models | `wav` or `mp3` only on the Responses API.                                                           |
| Video input                                  | Not supported            | Send video on Chat Completions.                                                                     |
| `include`, `truncation`, `text.verbosity`    | Accepted                 |                                                                                                     |
| `stream: true`                               | Same                     | Standard events: `response.created`, `response.output_text.delta`, `response.completed`, and so on. |
| `response.output_text` (OpenAI SDK)          | Same                     | The `sarvamai` SDK doesn't have this shortcut; read the `message` item in `output`.                 |

## Full example

A function-calling loop that sends the call and its result back in `input`:

#### After (OpenAI SDK)

```python
import json
from openai import OpenAI

client = OpenAI(
    api_key="YOUR_SARVAM_API_KEY",
    base_url="https://api.sarvam.ai/v2",
)

tools = [{
    "type": "function",
    "name": "get_weather",
    "description": "Get the weather for a city",
    "parameters": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"],
    },
}]

def get_weather(city: str) -> str:
    return f"31°C and sunny in {city}"  # call your real service here

history = [{"role": "user", "content": "What's the weather in Delhi?"}]
response = client.responses.create(model="kimi-k3", input=history, tools=tools, max_output_tokens=3000)

for item in response.output:
    if item.type == "function_call":
        result = get_weather(**json.loads(item.arguments))
        history += [
            {"type": "function_call", "call_id": item.call_id, "name": item.name, "arguments": item.arguments},
            {"type": "function_call_output", "call_id": item.call_id, "output": result},
        ]

final = client.responses.create(model="kimi-k3", input=history, tools=tools, max_output_tokens=3000)
print(final.output_text)
```

#### After (Sarvam SDK)

```python
import json
from sarvamai import SarvamAI

client = SarvamAI(api_subscription_key="YOUR_SARVAM_API_KEY")

tools = [{
    "type": "function",
    "name": "get_weather",
    "description": "Get the weather for a city",
    "parameters": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"],
    },
}]

def get_weather(city: str) -> str:
    return f"31°C and sunny in {city}"  # call your real service here

history = [{"role": "user", "content": "What's the weather in Delhi?"}]
response = client.responses.create(model="kimi-k3", input=history, tools=tools, max_output_tokens=3000)

for item in response.output:
    if item.type == "function_call":
        result = get_weather(**json.loads(item.arguments))
        history += [
            {"type": "function_call", "call_id": item.call_id, "name": item.name, "arguments": item.arguments},
            {"type": "function_call_output", "call_id": item.call_id, "output": result},
        ]

final = client.responses.create(model="kimi-k3", input=history, tools=tools, max_output_tokens=3000)
message = next(item for item in final.output if item.type == "message")
print(message.content[0].text)
```

## Common mistakes

#### Sending reasoning.effort: max to glm5.3

`glm5.3` and `glm5.3-flash` return `400` for the literal string `"max"` on the Responses
API. Omit `reasoning.effort` instead: that gives `max` on `glm5.3` and `high` on `glm5.3-flash`.

#### Leaving max_output_tokens unset

Sarvam doesn't cap output by default, so a reasoning model can generate for a long time.
Set `max_output_tokens`.

#### Reading response.output_text with the sarvamai SDK

The shortcut exists in the `openai` package only. With `sarvamai`, read the `message`
item in `output`.

#### Expecting OpenRouter server tools to work

Server tools such as `openrouter:web_search` return `400`. Call the service yourself and
expose it as a function tool.

## See also

* [Migration overview](/api/token-factory/migrations/from-openrouter/overview): base URL, auth, and model IDs
* [Migrating Chat Completion from OpenRouter](/api/token-factory/migrations/from-openrouter/chat-completion)
* [Responses API guide](/api/token-factory/responses-api)
* [Responses API reference](/api-reference/responses/create)