What you’ll learn
- Do I need to change my model names when I switch from OpenAI?
- Will streaming and tool calls behave exactly like OpenAI's API?
- What status code do I get when my balance runs out?
- Can I call Claude or Gemini models from the same OpenAI client?
The base URL is the easy part of leaving a provider; the failure paths are where migrations go wrong. To migrate from OpenAI to TokenLab, you change two values in your OpenAI SDK client: base_url and api_key. The rest of this guide covers what to confirm around that change. That means the model ID you send, its current price, streaming, tool calls, error handling, timeouts and billing. Facts below come from TokenLab docs and the live model API, each with its observed date.
Key Takeaways
- The core change is two values: the TokenLab base URL
https://api.tokenlab.sh/v1and a TokenLab API key (they start withsk-). - TokenLab documents OpenAI SDK support for Chat Completions and Responses. Optional parameters, tool options and Responses-only fields still depend on the selected model.
- Read the price of your model from the live API before you decide anything. On 2026-10-03,
gpt-5.5listed $1.50 input and $9.00 output per 1M tokens. - Run the checklist at the end before you move production traffic. Most surprises live in error handling, timeouts and billing, not in the happy path.
The Two-Value Change to Migrate from OpenAI to TokenLab
Start with the key. Per the Quickstart (observed 2026-10-03), you create an account, create an API key, and save the full value immediately. It is shown only once, and the prefix in the key list cannot authenticate requests. Check your balance before the first call, because requests bill at the selected model's current price.
Then change the client. The migration guide (observed 2026-10-03) describes the recipe as: set base_url / baseURL to https://api.tokenlab.sh/v1, replace the key, and choose a model ID from GET /v1/models.
For example, imagine a service that has the string gpt-5.5 in its config. After the two-value change, that same string is a valid request, but we would still confirm the ID first. GET /v1/models and GET /v1/models/{model} are public discovery endpoints and work without a key.
Python
import os
from openai import OpenAI
# Before: client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
client = OpenAI(
api_key=os.environ["TOKENLAB_API_KEY"],
base_url="https://api.tokenlab.sh/v1",
timeout=30.0,
max_retries=0,
)
response = client.chat.completions.create(
model="gpt-5.5",
messages=[{"role": "user", "content": "Hello, world!"}],
)
print(response.choices[0].message.content)
Node.js
import OpenAI from 'openai';
// Before: new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
const client = new OpenAI({
apiKey: process.env.TOKENLAB_API_KEY,
baseURL: 'https://api.tokenlab.sh/v1',
timeout: 30_000,
maxRetries: 0,
});
const completion = await client.chat.completions.create({
model: 'gpt-5.5',
messages: [{ role: 'user', content: 'Hello' }],
});
console.log(completion.choices[0].message.content);
cURL
curl https://api.tokenlab.sh/v1/chat/completions \
-H "Authorization: Bearer $TOKENLAB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-5.5","messages":[{"role":"user","content":"Say hello"}]}'
The timeout and retry settings in the first two samples mirror the Quickstart examples (observed 2026-10-03), which use a 30-second timeout and zero SDK retries. We keep retries at zero during testing so that a failing request is visible instead of being retried silently.
Pass the base URL explicitly in client configuration. The SDK guide (observed 2026-10-03) recommends this over relying on older environment-variable aliases. Keep the key on the server and in a secret manager, never in client-side code.
Pick the Model ID and Read Its Price
A migration should not assume a model ID or a price. Both live in the model API. We read https://api.tokenlab.sh/v1/models/gpt-5.5 and https://api.tokenlab.sh/v1/models/laguna-s-2.1 on 2026-10-03. Pricing for both was last updated 2026-10-02T16:53:30.068Z.
| Field | gpt-5.5 |
laguna-s-2.1 |
|---|---|---|
| Lifecycle stage | active | active |
| Max input / output tokens | 1,000,000 / 128,000 | 1,048,576 / 131,072 |
| Accepted request formats | openai_chat_completions, openai_responses |
openai_chat_completions |
| Capabilities listed | coding, json-mode, prompt-cache, reasoning, tool-use, vision | tool-use |
| Input, USD per 1M tokens | 1.5 | 0.1 |
| Output, USD per 1M tokens | 9 | 0.2 |
| Cache read, USD per 1M tokens | 0.15 | 0.01 |
Sources: gpt-5.5 and laguna-s-2.1, both observed 2026-10-03.
To turn those rates into a number, here is an estimate with the working shown. Take a job with 1M input tokens and 100k output tokens, with no cache hits.
gpt-5.5: 1 × $1.50 + 0.1 × $9.00 = $1.50 + $0.90 = $2.40.laguna-s-2.1: 1 × $0.10 + 0.1 × $0.20 = $0.10 + $0.02 = $0.12.
These are estimates from listed per-token rates. Your final charge is the Usage record. Tokenization differs by model, so the same text produces different token counts on different models.
We do not claim a saving here. To compare against what you pay today, put the TokenLab rates next to your own OpenAI invoice, or the OpenAI pricing page, on the day you switch. Prices change, and the billing guide (observed 2026-10-03) says not to hard-code a copied price table. It points to GET /v1/models/:model/pricing for current values.
Other model IDs follow the same pattern. The docs examples use gpt-5.6-terra and gpt-5.6-luna for Chat Completions, and claude-sonnet-5 and gemini-3.5-flash on their own routes. Read each model's accepted formats before you point traffic at it. For wider comparisons, see the model directory, the OpenRouter vs TokenLab comparison and the model rankings. Image and video teams can start with the best AI image models API 2026 and best AI video models API 2026. For code tasks, see best AI models for coding.
What to Check Next When You Migrate from OpenAI to TokenLab
TokenLab documents the OpenAI SDK as working with Chat Completions and Responses. That is compatibility with the request and response format, not a promise that every model behaves the same. The API formats guide (observed 2026-10-03) says optional parameters depend on the model. It also says a model does not necessarily accept all four API formats, and tokenlab.accepted_request_formats shows which it accepts. Treat each area below as something to test with your real traffic.
Streaming
stream: true sends partial message deltas as server-sent events. Set stream_options with include_usage: true to receive token usage in stream chunks, as the Create Chat Completion reference (observed 2026-10-03) documents.
stream = client.chat.completions.create(
model="gpt-5.5",
messages=[{"role": "user", "content": "Count to five."}],
stream=True,
stream_options={"include_usage": True},
)
for chunk in stream:
if chunk.choices:
print(chunk.choices[0].delta.content or "", end="")
Two behaviors to plan for. If a stream is interrupted after output arrived, do not treat it as a complete response. The error handling guide (observed 2026-10-03) warns that repeating it may produce different output or a second charge. And streaming can finish before billing does, so the billing ID may be absent.
Tool calls
The Chat Completions reference lists tools, tool_choice and parallel_tool_calls. It says parallel calls work "when supported by the selected model." Function calling is documented as "supported by the selected model," so check the capabilities list. In the table above, both gpt-5.5 and laguna-s-2.1 list tool-use, but only gpt-5.5 lists json-mode and vision. Send your real tool schemas, not a toy example, and check that the returned arguments parse.
If you plan to call Claude models, note the migration guide's rule. Claude tool calls, thinking blocks and Anthropic message fields belong on /v1/messages, and Chat Completions does not guarantee them.
Error shapes
Chat Completions and Responses return an OpenAI-style error object. Per the error handling guide, only message and type are always present. Fields such as code, param, retryable and retry_after appear when relevant. Branch on HTTP status and code, not on the message text, and make your parser tolerate missing fields. Anthropic Messages and Gemini keep their own error formats, so one parser will not cover every route.
| Status | Code | What it means |
|---|---|---|
| 401 | invalid_api_key |
Key is missing, invalid, inactive or revoked |
| 401 | expired_api_key |
Key has expired |
| 402 | insufficient_balance |
Account balance cannot cover the request |
| 402 | quota_exceeded |
The key's own usage limit was reached |
| 403 | model_not_allowed |
This key cannot use the requested model |
| 429 | rate_limit_exceeded |
Too many requests; wait for Retry-After |
Sources: Authentication and error handling, observed 2026-10-03.
This table corrects a common assumption. An empty balance is a 402, not a 401. If your current code treats every 4xx as a bad key, update it.
Timeouts and retries
The migration guide says existing retry, timeout and streaming code can usually stay. Review it against the documented retry rules.
- Do not repeat 400, 401, 402, 403, 404 or 413 responses unchanged.
- Retry 429 after the server-provided delay.
- Retry 500–504 only when
retryableistrue, and respectretry_after. - A
503 all_channels_failedcan come back withretryable: false. In that case the operation has no supply in the selected delivery tier, so repeating it will not help.
Save the Request ID from the response headers with the model and your own job ID. It is what you need for an investigation.
Billing
One balance works across models, with no subscription or minimum spend, per the billing guide. Each completed request is charged once, for the delivery option that produced it. The options are TokenLab Verified, Official and Auto, and Auto tries Verified first, then Official. Set a spending limit on each API key if you want a hard stop. When the limit is reached, requests with that key return 402.
Non-streaming OpenAI-compatible responses include billing_transaction_id when billing finishes before the response is sent. It may also appear in the X-Billing-Transaction-ID header. Store it, and reconcile against the Usage page rather than your own token math.
Verification Checklist After You Migrate from OpenAI to TokenLab
Run these in order against a staging key before production traffic moves. Each row traces to a documented behavior above.
| Step | What to run | What you should see |
|---|---|---|
| 1. Model discovery | GET /v1/models/gpt-5.5 (no key needed) |
Lifecycle active and the accepted formats you plan to use |
| 2. Authenticated request | The Python or cURL sample above | A non-empty answer; the request appears in the Requests view with model, status and usage |
| 3. Usage fields | Read usage on a non-streaming response |
prompt_tokens, completion_tokens, total_tokens |
| 4. Streaming | stream: true with include_usage: true |
SSE chunks, then usage; an interrupted stream is handled as incomplete |
| 5. Tool calls | Your real tools and tool_choice |
Arguments parse and match your schema |
| 6. Vision or JSON mode | Only if the model lists vision or json-mode |
Expected output; skip the test if the capability is not listed |
| 7. Bad key | Request with a deleted or wrong key | 401 invalid_api_key |
| 8. No balance or key limit | Use a key with a low limit or an empty workspace | 402 insufficient_balance or quota_exceeded |
| 9. Model restriction | Restrict a key's model list, then request another model | 403 model_not_allowed |
| 10. Timeout and retry | Force a timeout in staging | Your code retries only per retryable and retry_after |
| 11. Billing | Compare billing_transaction_id and Usage with your estimate |
Charge matches the model's current price and the recorded tokens |
After the table passes, change your production configuration and deploy. Keep the old OpenAI key active until Usage confirms the new path is stable.
Frequently Asked Questions
Do I need to change my model names when I switch from OpenAI?
Not necessarily, but confirm each one. TokenLab model IDs are exact strings, so check them with GET /v1/models or GET /v1/models/{model}. On 2026-10-03 the live API listed gpt-5.5 as active. If a request returns model_not_found, the ID is unknown or unavailable. Read the model list and use a current ID.
Will streaming and tool calls behave exactly like OpenAI's API?
TokenLab documents streaming through SSE and function calling through the OpenAI-compatible request format. The docs also say supported options depend on the selected model. We therefore treat the result as compatible, not identical. Test streaming, tools, tool_choice and any response_format you use with the specific model you plan to run.
What status code do I get when my balance runs out?
You get HTTP 402 with the code insufficient_balance. A key that reached its own spending limit also returns 402, with quota_exceeded. A missing, invalid or revoked key returns 401. Do not retry any of these unchanged. Top up the balance, raise the key limit, or replace the key.
Can I call Claude or Gemini models from the same OpenAI client?
The model catalog lists claude-sonnet-5 and gemini-3.5-flash with openai_chat_completions among their request formats. Basic chat can therefore go through the same client. Claude-specific fields such as thinking blocks and Claude tool use belong on /v1/messages. Gemini-native fields stay on the /v1beta route. Keep one API format per conversation.
Start Building on TokenLab
Create a key at TokenLab, set the base URL to https://api.tokenlab.sh/v1, and run the Quickstart request before touching production.
Sources
Prices checked 2026-10-03
- TokenLab Docs: QuickstartSources checked 2026-10-03
- TokenLab Docs: AuthenticationSources checked 2026-10-03
- TokenLab Docs: Migration GuidesSources checked 2026-10-03
- TokenLab Docs: SDKs & LibrariesSources checked 2026-10-03
- TokenLab Docs: API formatsSources checked 2026-10-03
- TokenLab Docs: Handle API errorsSources checked 2026-10-03
- TokenLab Docs: Billing and pricingSources checked 2026-10-03
- TokenLab Docs: Create Chat CompletionSources checked 2026-10-03



