Switching from OpenAI direct: migrating an existing integration
Base URL, key, model id. What carries over unchanged, what needs a second look, and how to verify the swap actually took.
The three things that change
Point the SDK at https://token-share.app, swap the key for your token-share key, and use a model id from this catalog. Everything the SDK does around that — request construction, retries, streaming iteration, tool-call parsing — is unchanged, because the wire format is the one it already speaks.
The model id is the part that is not a mechanical substitution. There is no gpt-4o or o3 here; the OpenAI-family ids are gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4 and gpt-5.4-mini, plus gpt-image-2 for images. Read GET /v1/models to see what is live rather than guessing at a mapping.
One consequence catches people: which endpoint a model answers on is fixed by the model, not chosen by you. The gpt-5.x text models answer on /v1/responses. Grok and Gemini answer on /v1/chat/completions. If your integration is built on chat completions and you want to call gpt-5.6-terra, that is a route change, not just an id change.
import OpenAI from 'openai';
const client = new OpenAI({
baseURL: 'https://token-share.app/v1',
apiKey: process.env.TOKEN_SHARE_KEY,
});
// gpt-5.x text models answer on /v1/responses
const answer = await client.responses.create({
model: 'gpt-5.6-terra',
input: 'Explain what changed in this diff.',
});
console.log(answer.output_text);
// Grok and Gemini answer on /v1/chat/completions
const chat = await client.chat.completions.create({
model: 'gemini-3-flash',
messages: [{ role: 'user', content: 'Explain what changed in this diff.' }],
});
console.log(chat.choices[0]?.message?.content);What your error handling should expect
Errors produced after routing keep the shape of the route you called, so an OpenAI-shaped caller gets an OpenAI-shaped error object. Errors raised before routing — bad key, unknown model, empty balance — use the gateway's own shape, which a strict SDK error parser may not recognise. Branch on the HTTP status first and treat the body as diagnostic text.
The statuses themselves are conventional. 401 for credentials, 402 and 403 for funding, 400 for a model the catalog does not know, 429 for capacity, 503 for availability, 502 when every provider tried has failed. The SDK's built-in retry on 429 and 5xx does the right thing here.
Every response carries x-token-share-request-id. If your existing logging captures OpenAI's x-request-id, capture this one in the same place — it is the handle for looking a request up.
Verifying the swap, and what it costs
Verify with the response, not the config. Read x-token-share-request-id off a live call — if it is present, the request went through this gateway. A stale environment variable in a container is the usual reason a migration looks done and is not.
Pricing is a multiplier on the official per-token rate, and it is per model rather than catalog-wide: as low as 0.05×, 0.1× for mainstream models. Most of the OpenAI-family ids are 0.1×, gpt-5.6-luna is 0.3×, and stable-gpt-6-astra is 0.2×. When you budget, multiply that model's own official rate by that model's own multiplier.
Because the multiplier is uniform across a model's token buckets, the shape of your bill does not change — an output-heavy workload stays output-heavy. What changes is the absolute number, so a cost model you already trust ports over with the multiplier applied.