Migrating Chat Completion from OpenRouter to Sarvam
Last updated: October 23, 2026
This guide covers moving OpenRouter Chat Completions and Responses calls for open-weight
models to Sarvam’s /v2 API.
In short: change base_url, api_key, and model. Then remove OpenRouter-only
fields such as provider, models, reasoning, and plugins: Sarvam returns
400 for request fields it doesn’t support instead of ignoring them. Read reasoning from
reasoning_content instead of reasoning.
Migration checklist
- Create an API key in the Sarvam dashboard.
- Change
base_urltohttps://api.sarvam.ai/v2andapi_keyto your Sarvam key. - Replace each model ID using the model ID table.
- Replace the
reasoningobject withreasoning_effort(Reasoning). - Remove OpenRouter-only fields:
provider,models,plugins,usage,session_id, and others (list). - Read reasoning from
reasoning_contentinstead ofreasoning. - Replace
modelsfallbacks with retries on429and503(full example). - Set
max_tokensexplicitly, then run your tests and watch for400responses that name a field.
Quick start
Before (OpenRouter)
After (Sarvam)
Reasoning
With the openai Python package, read the field with getattr, since it isn’t part of the
package’s typed response:
OpenRouter-only fields to remove
Sarvam validates request fields and returns 400 invalid_request_error with
Unsupported parameter(s) for fields it doesn’t support, so leftover OpenRouter options
fail loudly instead of being ignored.
Parameter concept map
Responses API
Both platforms’ Responses APIs are stateless. For base URL and field changes, reasoning items, function tools, and server-side tools, see Migrating the Responses API from OpenRouter.
What’s different by design
- One provider, no routing layer. Sarvam runs each model on its own infrastructure, so there are no upstream providers to rank, pin, or fail over between, and a model’s behaviour doesn’t change from request to request.
- Strict request validation. Unsupported fields return
400with the field named, instead of being dropped silently. This catches stale options early.gemma4is less strict: it accepts some fields, such aspredictionandlogit_bias, and ignores them. - Reasoning in
reasoning_content. Sarvam uses the same field name as many open-model servers, rather than OpenRouter’sreasoningandreasoning_details. - Billing in your Sarvam credits. Usage is metered per token against your Sarvam account. See Pricing.
Full example
A wrapper that replaces OpenRouter’s models fallback list with retries and a fallback
model in your own code:
Common mistakes
Leaving OpenRouter fields in extra_body
Fields like provider, models, reasoning, and plugins are often passed through
extra_body in the openai package and are easy to miss. Sarvam returns 400 with the
field name in the error message; remove each one it names.
Keeping the provider prefix in the model ID
moonshotai/kimi-k3 returns 404 on Sarvam. Use kimi-k3. See the
model ID table.
Reading message.reasoning
Sarvam returns reasoning in reasoning_content. Code that reads reasoning gets
None.
Expecting a fallback to happen automatically
Sarvam doesn’t retry on another model for you. Handle 429 and 503 in your code, as in
the full example.
Setting max_tokens too low on reasoning models
Reasoning tokens count against max_tokens. If the model spends the whole budget
thinking, content is empty and finish_reason is "length". Raise max_tokens or
lower reasoning_effort.
See also
- Migration overview: base URL, auth, and model IDs
- Chat Completion overview
- Responses API guide
- Open-Weight Models
- Errors & Troubleshooting