OpenAI SDK base_url Setup for Türkiye: Switch to 708+ Models with One Line

calendar_month July 8, 2026 schedule 8 min read

To point your OpenAI SDK at multiple models from Türkiye, set base_url to https://api.onysoft.com/v1 and supply an sk-ony- prefixed key; the rest of your code stays unchanged. The same switch works with zero code changes via the OPENAI_BASE_URL environment variable, and writing a provider/model ID in the model field unlocks 708+ models on one prepaid balance.

You have a working codebase built on the OpenAI SDK — but you also want Claude's reasoning, Gemini's long context, or DeepSeek's price-performance ratio. The traditional path means a separate SDK, separate keys, and a separate error format per provider. This guide covers the whole migration: the one-line change in Python, Node.js, and curl, the environment-variable method, a table of how each SDK version accepts base_url, the response-format difference between streaming and non-streaming calls, and a pre-production checklist.

The gateway is operated by Onysoft Veri Merkezi A.S., a datacenter company based in Izmir, Türkiye: you top up a balance in lira, usage is deducted at the TCMB central-bank rate, and corporate e-invoices are issued — no foreign card or VPN needed. This article also carries data you will not find elsewhere for this query: real response times measured across 6,959 requests in the last 14 days, the per-response cost field in action, and a priced scenario with lira equivalents.

What Exactly Does the base_url Change Do?

base_url is the root address the official OpenAI SDKs send every request to; change this single value to https://api.onysoft.com/v1 and your existing code starts talking to 708+ models — Claude, GPT, Gemini, and DeepSeek included — through Onysoft AI Gateway, on the same request and response schema. The SDK itself, your request bodies, your error handling: none of it changes.

Why would you want this? Wiring a separate SDK per provider looks harmless on day one and gets expensive by month six; as the codebase grows, vendor lock-in accumulates silently, and switching models stops being a config change and becomes a refactoring project. A single compatible endpoint inverts that equation:

  • Lock-in broken: when a better model ships, the switching cost is near zero — update the model ID, redeploy.
  • A/B model testing: run the same prompt through anthropic/claude-sonnet-5 and openai/gpt-5.6-terra in parallel and compare quality against spend; the per-response cost field hands you the spend side for free.
  • Fallbacks: a few-line retry layer that reroutes to a second model when the primary errors out is trivial when both live behind the same API.

Operating from Türkiye adds one more layer to the equation: a lira balance, corporate e-invoicing, and a KVKK counterparty under Turkish law. That layer is detailed in the Türkiye LLM Gateway guide, with the broader picture in the AI API guide.

Python, Node.js, and curl: the One-Line Change in Three Languages

In all three languages, the only thing that changes is the line where the client is constructed. In Python (official openai package):

from openai import OpenAI

client = OpenAI(
    base_url="https://api.onysoft.com/v1",  # the only line that changes
    api_key="sk-ony-YOUR_KEY",
)

resp = client.chat.completions.create(
    model="anthropic/claude-sonnet-5",
    messages=[{"role": "user", "content": "Introduce yourself in one sentence."}],
)
print(resp.choices[0].message.content)

In Node.js/TypeScript (official openai package, v4+):

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.onysoft.com/v1", // the only line that changes
  apiKey: "sk-ony-YOUR_KEY",
});

const resp = await client.chat.completions.create({
  model: "openai/gpt-5.6-luna",
  messages: [{ role: "user", content: "One API, many models. Summarize?" }],
});
console.log(resp.choices[0].message.content);

Without any SDK, straight from curl:

curl https://api.onysoft.com/v1/chat/completions \
  -H "Authorization: Bearer sk-ony-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/gemini-3.6-flash",
    "messages": [{"role": "user", "content": "Summarize this support ticket in one sentence."}]
  }'

On the PHP side, the community-standard openai-php/client package does the same job with OpenAI::factory()->withBaseUri('https://api.onysoft.com/v1'). Every model is addressed as provider/model (anthropic/claude-opus-5, deepseek/deepseek-v4-flash, and so on); pull the current ID list programmatically from GET /v1/models, or try a model without touching code in the Playground.

Migrating Without Touching the Codebase: the OPENAI_BASE_URL Environment Variable

The official Python (openai ≥ 1.0) and Node.js (openai ≥ 4.0) SDKs read base_url from the OPENAI_BASE_URL environment variable when no constructor parameter is given — meaning you can migrate without writing a single line of code:

export OPENAI_BASE_URL="https://api.onysoft.com/v1"
export OPENAI_API_KEY="sk-ony-YOUR_KEY"
# If your code constructs OpenAI() / new OpenAI() with no arguments,
# nothing else needs to change.

This method has two practical advantages: rollback is also a one-variable job (set it back, redeploy), and routing staging and production to different endpoints stays inside CI/CD configuration and never enters code review. Which path applies to which version:

SDK / packageVersionbase_url in codeEnvironment variable
openai (Python)≥ 1.0OpenAI(base_url=...)OPENAI_BASE_URL
openai (Python, legacy)0.xopenai.api_base = "..."OPENAI_API_BASE
openai (Node.js)≥ 4.0new OpenAI({ baseURL: ... })OPENAI_BASE_URL
openai (Node.js, legacy)3.xnew Configuration({ basePath: ... })
openai-php/client (PHP)allwithBaseUri(...)— (read the variable yourself)

Verified: August 5, 2026 — official SDK documentation.

The 0.x Python and 3.x Node lines have been unmaintained for years; treat the migration as an opportunity to move to the current major version — every example above targets the current majors.

Streaming and the cost Field: How the Response Format Differs Between the Two Modes

The rule is simple: with streaming on, the response arrives as raw OpenAI SSE chunks; with streaming off, the response body is wrapped in a success/data envelope, and the request's charge appears in the data.cost field in USD. The raw JSON body of a non-streaming call looks like this:

{
  "success": true,
  "data": {
    "id": "chatcmpl-...",
    "model": "openai/gpt-5.6-luna",
    "choices": [ ... ],
    "usage": { "prompt_tokens": 12, "completion_tokens": 84 },
    "cost": 0.0000774
  }
}

If you work with curl or your own HTTP client, read the content from .data.choices[0].message.content and the charge from .data.cost (| jq '.data.cost'). That cost field is one of the gateway's distinguishing features: instead of totaling spend from the dashboard at the end of the day, you can log each request's charge from the response itself and run quality-versus-cost A/B comparisons per request.

With streaming on there is no envelope: chunks arrive in the raw OpenAI SSE format and end with data: [DONE], so your existing streaming code needs no adaptation:

stream = client.chat.completions.create(
    model="anthropic/claude-sonnet-5",
    messages=[{"role": "user", "content": "Explain microservice architecture."}],
    stream=True,
)

for chunk in stream:
    delta = chunk.choices[0].delta.content
    if delta:
        print(delta, end="", flush=True)

The one difference to note: the cost field does not appear in stream chunks. Spend on streamed requests shows up in the dashboard usage breakdown; if per-request cost logging is critical for a given call, making it non-streaming and recording data.cost is the cleanest solution.

How It Works on Onysoft: Prices, Real Latency, and OnyRouter

After the migration, what sets your invoice is no longer code — it is the string you write in the model field. Current sale prices from the catalog show the spread between the extremes:

ModelInput ($/1M tokens)Output ($/1M tokens)Input (TRY/1M)Output (TRY/1M)
anthropic/claude-opus-5$7.50$37.50₺356.66₺1,783.31
anthropic/claude-sonnet-5$3.00$15.00₺142.67₺713.33
openai/gpt-5.6-terra$1.50$9.00₺71.33₺428.00
openai/gpt-5.6-luna$0.15$0.90₺7.13₺42.80
google/gemini-3.6-flash$2.25$11.25₺107.00₺535.00
deepseek/deepseek-v4-flash$0.21$0.42₺9.99₺19.97

Measured: August 5, 2026 — api.onysoft.com live catalog. TRY equivalents calculated at the August 5, 2026 TCMB rate (1 USD = 47.555 TRY).

A concrete scenario: a chatbot generating 10M input + 2.5M output tokens per month costs $67.50 (₺3,209.96) on anthropic/claude-sonnet-5, $3.75 (₺178.33) on openai/gpt-5.6-luna, and $3.15 (₺149.80) on deepseek/deepseek-v4-flash — and switching between the three is exactly the one-string change this article is about. Run your own profile through the cost calculator.

On speed, here is measurement rather than estimation: across 6,959 successful requests through the gateway in the last 14 days, average end-to-end response time was 3.8 seconds, with the fastest at 0.3 seconds. What pulls the average up is not the gateway but long-generation flagship and reasoning requests in the traffic; the 0.3-second floor shows how thin the layer is with lightweight models.

If you would rather delegate model selection to the gateway, OnyRouter is built in:

resp = client.chat.completions.create(
    model="onysoft/auto",  # OnyRouter: the gateway picks the best-fit model
    messages=[{"role": "user", "content": "Optimize this SQL query."}],
)
print(resp.model)  # the selected model is reported transparently

Routing itself is free; only the selected model's usage is billed. Full details in the OnyRouter guide.

Migration Checklist: 401, 404, 402, and Honest Limits

Work through this list before going to production; the first three items alone close most migration errors:

  1. Key (401 Unauthorized): an old OpenAI key (sk-proj-...) may still sit in your environment. Onysoft keys start with sk-ony- and must travel in the Authorization: Bearer header — the SDKs handle that automatically.
  2. Endpoint (404): the trailing /v1 on base_url is frequently dropped. The correct value is https://api.onysoft.com/v1.
  3. Model ID (404 / model_not_found): the provider prefix is mandatory: anthropic/claude-sonnet-5, not claude-sonnet-5. Take IDs from GET /v1/models or the catalog's copy button.
  4. Balance and 402: before every request the gateway compares the estimated cost, padded by a 20% safety margin (×1.2), against your balance; if it falls short, the request returns 402 without ever reaching the model. Handle 402 separately in your retry layer — the fix is a top-up, not a retry.
  5. Per-key limits: issue separate keys for production and testing, and set per-key spending limits from the dashboard so a runaway loop cannot drain the budget.
  6. An honest note on embeddings: the gateway does not currently expose a /v1/embeddings endpoint. In a RAG setup, the cleanest architecture in practice is keeping embedding traffic with your current provider and moving generation (chat/completions) traffic to the gateway — the two workloads live on different keys and cost profiles anyway.
  7. Coming from the Anthropic SDK: the gateway serves the OpenAI schema, not Anthropic's native /v1/messages protocol. You reach Claude models through the OpenAI SDK too; messages.create calls need converting to chat.completions.create.
  8. Image/video/music: these models run on asynchronous endpoints: POST /v1/video/generate returns a task_id, polled via GET /v1/video/status/{task_id}; a plain HTTP client is enough — no OpenAI SDK involved.

For anything beyond the list, the error-code section of the API documentation and 24/7 support have you covered. To start, open a free account and fire your first request from the Playground.

Last updated: August 5, 2026 · Data: api.onysoft.com live catalog

Frequently Asked Questions

How do I change base_url in the OpenAI SDK?

In Python, write OpenAI(base_url="https://api.onysoft.com/v1", api_key="sk-ony-..."); in Node.js, pass the same values as baseURL and apiKey. If you prefer not to touch code, set the OPENAI_BASE_URL and OPENAI_API_KEY environment variables — current SDKs read them automatically when no constructor parameters are given.

Which SDK versions support the OPENAI_BASE_URL environment variable?

The official Python SDK from 1.0 onward and the Node.js SDK from 4.0 onward read OPENAI_BASE_URL. The legacy Python 0.x line uses the OPENAI_API_BASE variable and the openai.api_base assignment, while Node 3.x accepts basePath in code only. We recommend upgrading from these unmaintained lines to the current majors.

Does my existing OpenAI code need any other changes?

No. Request bodies, streaming, tools, and JSON mode are fully compatible with the OpenAI chat/completions schema; the only difference is writing a provider/model ID in the model field (for example anthropic/claude-sonnet-5). The current ID list can also be fetched programmatically from GET /v1/models.

Are streaming responses byte-for-byte OpenAI format?

Yes — with streaming on, chunks arrive in the raw OpenAI SSE format and end with data: [DONE], so your existing streaming loop works unchanged. With streaming off, the response body is wrapped in a success/data envelope: the actual OpenAI body plus a cost field with the request's charge live inside data. Account for that difference in raw HTTP integrations.

How do I see the cost of a single request?

Every non-streaming response carries a data.cost field with that request's charge in USD; log it and you have per-request cost tracking inside your application. Stream chunks do not carry a cost field — spend on streamed requests appears in the dashboard usage breakdown. For monthly projections, use the calculator on the /calculator page.

What happens if my balance is insufficient?

Before every request, the gateway compares the estimated cost padded by a 20% safety margin (×1.2) against your balance; if it falls short, the request returns a 402 error without ever reaching the model. That prevents mid-generation cutoffs and surprise negative balances. Handle 402 separately in your retry layer: the fix is topping up from the dashboard — the balance takes effect immediately — not retrying.

Related pages

AI API Guide (Turkish) → Türkiye LLM Gateway Guide → OnyRouter: Automatic Model Selection → Full catalog of 708+ models with current pricing →

Ready to build?

Access 708+ AI models through a single API. Pay as you go — no subscription.

Create Free Account Browse Models

← All posts

Want help finding the right model?