> 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 Chat Completion from Together AI to Sarvam

> Request fields, reasoning, error codes, and Together-only features to change when moving chat traffic from Together AI to Sarvam's /v2 API, with before/after code.

*Last updated: October 23, 2026*

This guide covers moving Together AI Chat Completions calls for open-weight models to
Sarvam's [`/v2` API](/api/token-factory/chat-completions).

> **Tip**
>
> **In short:** change `base_url`, `api_key`, and `model`. Replace `reasoning: {"enabled": false}`
> with `reasoning_effort: "none"`, send `logprobs` as `true` instead of a number, and remove
> Together-only fields such as `safety_model`: Sarvam returns `400` for request fields it
> doesn't support. Remember that `403` now means an auth error, not a context-length error.

## Migration checklist

1. Create an API key in the [Sarvam dashboard](https://indus.sarvam.ai/key-management?ref=docs).
2. Change `base_url` to `https://api.sarvam.ai/v2` and `api_key` to your Sarvam key.
3. Replace each model ID using the [model ID table](/api/token-factory/migrations/from-together/overview#model-ids).
4. Replace `reasoning: {"enabled": false}` with `reasoning_effort: "none"` ([Reasoning](#reasoning)).
5. Remove Together-only fields: `safety_model`, `compliance`, `echo`, and others ([list](#together-only-fields-to-remove)).
6. Send `logprobs` as `true`, with the count in `top_logprobs`.
7. Update error handling: `403` now means an invalid key, not a prompt that's too long.
8. Set `max_tokens` explicitly, then run your tests and watch for `400` responses that name a field.

## Quick start

|             | Together AI                   | Sarvam                                                                                               |
| ----------- | ----------------------------- | ---------------------------------------------------------------------------------------------------- |
| Base URL    | `https://api.together.ai/v1`  | `https://api.sarvam.ai/v2`                                                                           |
| Auth header | `Authorization: Bearer <key>` | `api-subscription-key: <key>` or `Authorization: Bearer <key>`                                       |
| Model ID    | `moonshotai/Kimi-K3`          | `kimi-k3` (see the [model ID table](/api/token-factory/migrations/from-together/overview#model-ids)) |

#### Before (Together AI)

#### Python (Together SDK)

```python
from together import Together

client = Together(api_key="YOUR_TOGETHER_API_KEY")

response = client.chat.completions.create(
    model="deepseek-ai/DeepSeek-V4-Pro-0813",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Suggest a name for a coffee shop in Bengaluru."},
    ],
    max_tokens=2000,
    reasoning={"enabled": False},
)

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

#### JavaScript (Together SDK)

```javascript
import Together from "together-ai";

const together = new Together({ apiKey: "YOUR_TOGETHER_API_KEY" });

const response = await together.chat.completions.create({
  model: "deepseek-ai/DeepSeek-V4-Pro-0813",
  messages: [
    { role: "system", content: "You are a helpful assistant." },
    { role: "user", content: "Suggest a name for a coffee shop in Bengaluru." },
  ],
  max_tokens: 2000,
  reasoning: { enabled: false },
});

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

#### cURL

```bash
curl https://api.together.ai/v1/chat/completions \
  -H "Authorization: Bearer YOUR_TOGETHER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-ai/DeepSeek-V4-Pro-0813",
    "messages": [{"role": "user", "content": "Suggest a name for a coffee shop in Bengaluru."}],
    "max_tokens": 2000,
    "reasoning": {"enabled": false}
  }'
```

#### 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.chat.completions.create(
    model="deepseekv4-pro",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Suggest a name for a coffee shop in Bengaluru."},
    ],
    max_tokens=2000,
    reasoning_effort="none",
)

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

#### 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.chat.completions.create({
  model: "deepseekv4-pro",
  messages: [
    { role: "system", content: "You are a helpful assistant." },
    { role: "user", content: "Suggest a name for a coffee shop in Bengaluru." },
  ],
  max_tokens: 2000,
  reasoning_effort: "none",
});

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

#### Python (Sarvam SDK)

```python
from sarvamai import SarvamAI

client = SarvamAI(api_subscription_key="YOUR_SARVAM_API_KEY")

response = client.chat.completions_v2(
    model="deepseekv4-pro",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Suggest a name for a coffee shop in Bengaluru."},
    ],
    max_tokens=2000,
    reasoning_effort="none",
)

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

#### JavaScript (Sarvam SDK)

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

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

const response = await client.chat.completionsV2({
  model: "deepseekv4-pro",
  messages: [
    { role: "system", content: "You are a helpful assistant." },
    { role: "user", content: "Suggest a name for a coffee shop in Bengaluru." },
  ],
  max_tokens: 2000,
  reasoning_effort: "none",
});

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

#### cURL

```bash
curl https://api.sarvam.ai/v2/chat/completions \
  -H "api-subscription-key: YOUR_SARVAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseekv4-pro",
    "messages": [{"role": "user", "content": "Suggest a name for a coffee shop in Bengaluru."}],
    "max_tokens": 2000,
    "reasoning_effort": "none"
  }'
```

## Reasoning

| Together AI                                          | Sarvam                                | Note                                                                                                                                                                      |
| ---------------------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `reasoning_effort: "low"` / `"high"` / `"max"`       | Same                                  | Each model's default is listed under [Reasoning](/api/token-factory/models#reasoning).                                                                                    |
| `reasoning_effort: "medium"`                         | Use `"low"`, `"high"`, or `"max"`     | Accepted on some models and returns `400` on others, such as `glm5.3`.                                                                                                    |
| `reasoning: {"enabled": false}`                      | `reasoning_effort: "none"`            | The `reasoning` object returns `400`. `"none"` turns thinking off on `deepseekv4-pro`, `mimo-v2.6-flash`, and `mimo-v2.6-pro`. `kimi-k3` and `glm5.3-flash` always think. |
| `reasoning: {"enabled": true}`                       | Remove                                | Reasoning models think by default.                                                                                                                                        |
| `chat_template_kwargs`                               | Same                                  | Passed to the model. `{"enable_thinking": false}` turns thinking off on the MiMo models.                                                                                  |
| `choices[].message.reasoning` (DeepSeek V4 Pro)      | `choices[].message.reasoning_content` | Sarvam uses `reasoning_content` for every model, and `delta.reasoning_content` when streaming.                                                                            |
| `choices[].message.reasoning_content` (Kimi K3, GLM) | Same                                  |                                                                                                                                                                           |

## Together-only fields to remove

Sarvam validates request fields and returns `400 invalid_request_error` for fields it
doesn't support, so leftover Together options fail loudly instead of being ignored.

| Together field                       | What to do on Sarvam                                                                                                              |
| ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
| `reasoning` object                   | Replace with `reasoning_effort` (see [Reasoning](#reasoning)).                                                                    |
| `safety_model`                       | Remove. Run moderation as a separate step before or after the call.                                                               |
| `compliance`                         | Remove.                                                                                                                           |
| `context_length_exceeded_behavior`   | Remove. Sarvam returns an error when the prompt plus `max_tokens` is longer than the context window, as Together does by default. |
| `echo`                               | Remove. Keep the prompt on your side.                                                                                             |
| `response_format: {"type": "regex"}` | Use `response_format` with a `json_schema`, and put the pattern in a string property's `pattern`.                                 |
| `logprobs: 5` (a number)             | Use `logprobs: true` with `top_logprobs: 5`.                                                                                      |
| `functions`, `function_call`         | Use `tools` and `tool_choice`. The legacy fields return `400`.                                                                    |

## Parameter concept map

| Together AI                                                               | Sarvam                     | Note                                                                                                                                                                                    |
| ------------------------------------------------------------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `messages`, `max_tokens`, `temperature`, `top_p`, `top_k`, `stop`, `seed` | Same                       | Set `max_tokens` explicitly: when it's omitted, generation isn't capped at a small default.                                                                                             |
| `repetition_penalty`, `frequency_penalty`, `presence_penalty`             | Same                       |                                                                                                                                                                                         |
| `min_p`                                                                   | Not supported              | Remove it. The open-weight models accept only `0`, which is the same as leaving it out.                                                                                                 |
| `tools`, `tool_choice`, `parallel_tool_calls`                             | Same                       | `parallel_tool_calls: false` is enforced on every model; see [V2 feature support](/api/token-factory/chat-completions#v2-feature-support).                                              |
| `response_format` (`json_schema`, `json_object`)                          | Same                       |                                                                                                                                                                                         |
| `n`                                                                       | Same                       | Supported on most models. `temperature` must be above `0` when `n` > 1.                                                                                                                 |
| `stream: true`                                                            | Same                       | As on Together, the last chunk before `[DONE]` carries `usage` with an empty `choices` array; keep skipping it.                                                                         |
| `image_url` content parts                                                 | Same                       | Sarvam accepts inline base64 data URIs only, not remote image URLs, on models with image input. See each [model page](/api/token-factory/models).                                       |
| `video_url` content parts                                                 | Same, as a base64 data URI | On the MiMo models and `kimi-k3` (beta, short clips). Sarvam doesn't fetch video URLs.                                                                                                  |
| `input_audio` content parts                                               | Same, on the MiMo models   | `wav` or `mp3`. For FLAC, OGG, or Opus, send an `audio_url` part with a data URI. See [Media input](/api/token-factory/migrations/from-together/overview#media-input-and-request-size). |
| `finish_reason: "eos"`                                                    | `finish_reason: "stop"`    |                                                                                                                                                                                         |

## Responses API

Together doesn't offer a Responses API. Sarvam does: if you want the OpenAI Responses format,
see the [Responses API guide](/api/token-factory/responses-api). It's
stateless, like Chat Completions.

## What's different by design

* **No dedicated endpoints to manage.** Models that are dedicated-only on Together, such as
  Gemma 4 31B, are called by model ID on Sarvam.
* **Strict request validation.** Unsupported fields return `400` with the field named,
  instead of being dropped silently. `gemma4` is less strict: it accepts some fields, such as
  `prediction` and `logit_bias`, and ignores them.
* **One reasoning field.** Reasoning comes back in `reasoning_content` for every model.
* **Different meaning for `403`.** On Sarvam it's an auth error. See the
  [status code table](/api/token-factory/migrations/from-together/overview#errors-and-rate-limits).

## Platform features without a direct equivalent

| Together feature                               | On Sarvam                                                                                                      |
| ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| Batch API                                      | Not available. Send requests concurrently within your [rate limits](/api/getting-started/pricing#rate-limits). |
| Fine-tuning and LoRA adapters                  | Not available on the `/v2` API.                                                                                |
| Dedicated endpoints and provisioned throughput | Not needed for these models. Contact [Sarvam](/api/getting-started/help) for capacity needs.                   |
| Llama Guard moderation (`safety_model`)        | Not available. Run moderation separately.                                                                      |

## Full example

A wrapper that turns thinking off, asks for log probabilities, and maps status codes:

#### Before (Together AI)

```python
from together import Together

client = Together(api_key="YOUR_TOGETHER_API_KEY")

def ask(prompt: str) -> str:
    response = client.chat.completions.create(
        model="deepseek-ai/DeepSeek-V4-Pro-0813",
        messages=[{"role": "user", "content": prompt}],
        max_tokens=2000,
        reasoning={"enabled": False},
        logprobs=3,
    )
    return response.choices[0].message.content
```

#### After (OpenAI SDK)

```python
import time
from openai import OpenAI, APIStatusError

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

def ask(prompt: str) -> str:
    for attempt in range(3):
        try:
            response = client.chat.completions.create(
                model="deepseekv4-pro",
                messages=[{"role": "user", "content": prompt}],
                max_tokens=2000,
                reasoning_effort="none",
                logprobs=True,
                top_logprobs=3,
            )
            return response.choices[0].message.content
        except APIStatusError as e:
            if e.status_code == 403:
                raise RuntimeError("Invalid API key. Check your credentials.") from e
            if e.status_code in (429, 503):
                time.sleep(2 ** attempt)  # back off, then retry
                continue
            raise
    raise RuntimeError("Model is busy. Try again later.")
```

#### After (Sarvam SDK)

```python
import time
from sarvamai import SarvamAI
from sarvamai.core.api_error import ApiError

client = SarvamAI(api_subscription_key="YOUR_SARVAM_API_KEY")

def ask(prompt: str) -> str:
    for attempt in range(3):
        try:
            response = client.chat.completions_v2(
                model="deepseekv4-pro",
                messages=[{"role": "user", "content": prompt}],
                max_tokens=2000,
                reasoning_effort="none",
                # The Python SDK doesn't have logprobs arguments yet; send them as extra body fields.
                request_options={
                    "additional_body_parameters": {"logprobs": True, "top_logprobs": 3},
                },
            )
            return response.choices[0].message.content
        except ApiError as e:
            if e.status_code == 403:
                raise RuntimeError("Invalid API key. Check your credentials.") from e
            if e.status_code in (429, 503):
                time.sleep(2 ** attempt)  # back off, then retry
                continue
            raise
    raise RuntimeError("Model is busy. Try again later.")
```

## Common mistakes

#### Treating 403 as a context-length error

On Sarvam, `403` means the API key is missing or invalid. Don't trim the prompt and retry
on `403`; check the key instead.

#### Keeping the organisation prefix in the model ID

`moonshotai/Kimi-K3` returns `404` on Sarvam. Use `kimi-k3`. Model IDs are
case-sensitive. See the [model ID table](/api/token-factory/migrations/from-together/overview#model-ids).

#### Sending reasoning: \{enabled: false}

Sarvam returns `400`. Use `reasoning_effort: "none"` on models that can turn thinking
off.

#### Sending logprobs as a number

Sarvam expects `logprobs: true` and the count in `top_logprobs`.

#### Sending images or video by URL

Sarvam accepts images, audio, and video only as inline base64 data URIs; URLs return `400`.
Download the file and encode it before sending. See
[Media input](/api/token-factory/migrations/from-together/overview#media-input-and-request-size).

## See also

* [Migration overview](/api/token-factory/migrations/from-together/overview): base URL, auth, model IDs, and status codes
* [Chat Completion overview](/api/token-factory/chat-completions)
* [Responses API guide](/api/token-factory/responses-api)
* [Open-Weight Models](/api/token-factory/models)
* [Errors & Troubleshooting](/api/getting-started/errors-troubleshooting)