Migrate an existing OpenAI integration
Moving production traffic onto Salyro is a configuration change — a base URL, a key and a model id — not a rewrite.
The fear that stops most teams from putting a gateway in front of their model provider is that it means rewriting the integration. It does not. Salyro speaks the OpenAI wire format, so your existing client keeps working — the request bodies, the response shapes and the error handling around them all stay as they are.
What changes is three settings. This guide is the whole change, in the order that keeps production running while you make it.
What actually changes
- baseURL: 'https://api.openai.com/v1'
+ baseURL: 'https://api.salyro.com/v1'
- apiKey: process.env.OPENAI_API_KEY
+ apiKey: process.env.SALYRO_API_KEY
- model: 'gpt-4o-mini'
+ model: 'openai/gpt-4o-mini'
The third line is optional at first — see Model ids can wait below — which means the migration can be two lines if you want it to be.
Set up the gateway
Create a gateway for the environment you are migrating
One gateway per environment, starting with the one you are least afraid of. Migrating staging first is not caution for its own sake: it is how you find out whether anything in your stack cares about the hostname before production does.
Connect the OpenAI key you already use
Under the gateway's Providers, connect the same OpenAI key your application uses today. You are not creating a new relationship with OpenAI — the same account, the same billing, the same rate limits. Salyro verifies the key with OpenAI before storing it.
Issue a Salyro API key
Under API Keys. This is what replaces
OPENAI_API_KEYin your environment. It is shown once.Change the two settings
Point the client at
https://api.salyro.com/v1and give it the Salyro key. Deploy as you would any configuration change.Confirm from the request log
Send real traffic and check the gateway's requests. A request appearing there is direct evidence the traffic is going through the gateway, which a successful response on its own does not prove — the old configuration also returns successful responses.
Model ids can wait
A model id with no provider prefix — gpt-4o-mini — resolves to OpenAI. That
alias exists precisely so that this migration does not require editing every
model string in a codebase on the same day as changing the endpoint.
It is an OpenAI alias and nothing more. There is no default provider: a bare name is never tried against Anthropic, Gemini or Grok.
Once the traffic is flowing, move to canonical ids:
model: 'openai/gpt-4o-mini';
It is worth doing rather than leaving. The canonical form says which provider account the request will spend against, and it is the form you need the moment a second provider is connected — which is the whole reason to be behind a gateway.
Verify the responses are the same
They should be identical, and confirming that is a five-minute job worth doing rather than assuming:
# Before — direct to OpenAI
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Say hello."}]}'
# After — through the gateway
curl https://api.salyro.com/v1/chat/completions \
-H "Authorization: Bearer $SALYRO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"openai/gpt-4o-mini","messages":[{"role":"user","content":"Say hello."}]}'
const before = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const after = new OpenAI({
apiKey: process.env.SALYRO_API_KEY,
baseURL: 'https://api.salyro.com/v1',
});
const body = {
messages: [{ role: 'user' as const, content: 'Say hello.' }],
};
console.log(await before.chat.completions.create({ ...body, model: 'gpt-4o-mini' }));
console.log(await after.chat.completions.create({ ...body, model: 'openai/gpt-4o-mini' }));
The bodies are the same shape, the usage counts come out the same, and
streaming behaves the same way. The one field that differs is model in the
response, which echoes the canonical id the request resolved to.
What you gain
Nothing about the model changes, so the value of the migration is entirely in what the gateway adds around it:
- A request log. Every request through the gateway is recorded with its model, provider, status and timing. See Logs & conversations.
- Cost you can attribute. Token counts are priced per model and per provider, broken down by gateway — which becomes cost per environment, per feature or per customer once your gateways are split along that line. See Attribute cost per feature or customer.
- A key you can revoke. Your provider key stops travelling in application configuration. What your code carries is a Salyro key bound to one gateway, which you can rotate as often as you like without touching the OpenAI account.
- A second provider, when you want one. Connect Anthropic, Gemini or Grok to the same gateway and the only thing that changes in your code is a model id.
What to check before you migrate
Compatibility has a defined scope, and it is worth knowing the edges before a deployment finds them for you.
Two more differences worth knowing:
- Unsupported parameters fail loudly. Salyro does not silently drop a
parameter it cannot honour — it returns a
400naming it. That is the intended behaviour, and it is stricter than what you may be used to. See the Public API reference. - There is no automatic failover. Routing is pass-through. If OpenAI is down, your request fails; Salyro will not quietly try Anthropic instead. Which provider serves a request is decided by the model id and by nothing else.
Rolling back
Rolling back is the same two settings in reverse, and nothing in Salyro holds onto your traffic — your OpenAI key still works directly, because it is still your key and your account. That is worth knowing before you deploy rather than during an incident.
The gateway's logs and usage for the period you were live remain readable afterwards — nothing deletes them on a schedule. See Logs & conversations for how far one view reaches.
