# OpenAI থেকে Tokens-এ চলে আসা

> OpenAI API call করা app Tokens-এ সরানোর গাইড: কোন তিনটা সেটিং বদলাতে হয়, কী একই থাকে, কোন endpoint আর আচরণ আলাদা, সীমা দেওয়া key দিয়ে কীভাবে পরীক্ষা করবেন আর দরকার হলে কীভাবে ফিরে যাবেন।

আপনার app যদি আগে থেকেই OpenAI API call করে, তাহলে Tokens-এ আসতে তিনটা জিনিস বদলাতে হয়: base URL, API key আর model id। chat completions, streaming আর tool calling-এর request ও response format একই থাকে, তাই বেশিরভাগ code হাত দিতে হয় না। কোথায় কোথায় তফাত আছে, তা এই পাতায় লেখা আছে। উদ্দেশ্য একটাই: তফাতগুলো যেন test-এ ধরা পড়ে, production-এ নয়।

## কী বদলায়, কী একই থাকে

| Setting          | OpenAI                                          | Tokens                                           | কোথায় বসাবেন                                                                     |
| ---------------- | ----------------------------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------------- |
| Base URL         | `https://api.openai.com/v1` (SDK-র default)     | `https://tokens.bd/v1`                            | `base_url` (Python) বা `baseURL` (Node.js), অথবা `OPENAI_BASE_URL` variable       |
| API key          | `sk-...`                                        | [API keys](/docs/api-keys) থেকে `tok_live_...`   | `api_key` বা `apiKey`, অথবা `OPENAI_API_KEY` variable                             |
| Model id         | OpenAI-র নিজের id                               | `/models` থেকে `provider/model` ধাঁচের একটা alias | প্রতিটা request-এর `model` field-এ                                                |
| Org আর project   | `OpenAI-Organization`, `OpenAI-Project` header | লাগে না। বাদ দিন।                                | Client options                                                                    |

OpenAI-র official Python আর Node.js SDK কোডে মান না দিলে `OPENAI_API_KEY` আর `OPENAI_BASE_URL` variable পড়ে (SDK source দেখে নিশ্চিত করা, অক্টোবর 2026)। দুটো variable বদলে দিলেই code না ছুঁয়ে endpoint বদলে যায়। শুধু model id-টা code বা config-এ নিজে বদলে নিতে হবে।

যা একই থাকে:

- `POST /v1/chat/completions`-এর request আর response JSON: `messages`, `tools`, `tool_choice`, `response_format`, `stream` আর `usage` object-সহ। দেখুন [Chat Completions](/docs/chat-completions)।
- Server-Sent Events streaming। শেষের usage chunk আসে শুধু তখনই, যখন আপনি `stream_options: {"include_usage": true}` পাঠান। OpenAI-তেও তাই হয়।
- `Authorization: Bearer <key>` দিয়ে authentication।
- `POST /v1/responses`-এ Responses API (নিচে দেখুন)।
- OpenAI SDK-র class আর error type। কোনো error status এলে OpenAI-তে যে exception উঠত, এখানেও সেটাই ওঠে।

## আগে আর পরে

:::code-tabs

```diff title="Python"
 import os
 from openai import OpenAI

-client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
+client = OpenAI(
+    base_url="https://tokens.bd/v1",
+    api_key=os.environ["TOKENS_API_KEY"],
+)

 resp = client.chat.completions.create(
-    model="your-openai-model",
+    model="deepseek/deepseek-v4.1-flash",
     messages=[{"role": "user", "content": "What does HTTP 429 mean?"}],
     max_tokens=300,
 )
 print(resp.choices[0].message.content)
```

```diff title="Node.js"
 import OpenAI from "openai";

-const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
+const client = new OpenAI({
+  baseURL: "https://tokens.bd/v1",
+  apiKey: process.env.TOKENS_API_KEY,
+});

 const resp = await client.chat.completions.create({
-  model: "your-openai-model",
+  model: "deepseek/deepseek-v4.1-flash",
   messages: [{ role: "user", content: "What does HTTP 429 mean?" }],
   max_tokens: 300,
 });
 console.log(resp.choices[0].message.content);
```

```diff title="curl"
-curl https://api.openai.com/v1/chat/completions \
-  -H "Authorization: Bearer $OPENAI_API_KEY" \
+curl https://tokens.bd/v1/chat/completions \
+  -H "Authorization: Bearer $TOKENS_API_KEY" \
   -H "Content-Type: application/json" \
   -d '{
-    "model": "your-openai-model",
+    "model": "deepseek/deepseek-v4.1-flash",
     "messages": [{"role": "user", "content": "What does HTTP 429 mean?"}],
     "max_tokens": 300
   }'
```

:::

curl বা সরাসরি HTTP client ব্যবহার করলে `Content-Type: application/json` header রাখতে ভুলবেন না। এটা না থাকলে Tokens body পড়ে না, আর 400 `invalid_request` ("must specify a 'model' field") ফেরত দেয়। SDK নিজেই header-টা বসিয়ে দেয়।

### Model id বেছে নিন

OpenAI-র id নিজে নিজে অনুবাদ করতে যাবেন না। Tokens-এর id হলো `provider/model` ধাঁচের alias, আর সেটা সবসময় provider-এর নিজের id-র সাথে মেলে না। আগে দেখে নিন আপনার key কোন কোন model call করতে পারে, তারপর সেখান থেকে id copy করুন:

```bash
curl -s https://tokens.bd/v1/models -H "Authorization: Bearer $TOKENS_API_KEY"
```

এই তালিকা key ধরে ছাঁটা হয়। যে key-তে allowed-models list আছে, বা যে অ্যাকাউন্টে plan অথবা Wallet-এ ব্যালান্স নেই, সে কম model দেখবে। দাম, context window আর capability পাবেন [/models](/models) পাতায়, API response-এ এসব থাকে না। কোনটা নেবেন বুঝতে [Choosing a model](/docs/choosing-a-model) দেখুন। model বদলালে উত্তরও বদলায়, অর্থাৎ এই switch আসলে একটা model বদলও। তাই শুধু connection নয়, আপনার prompt-গুলোও test করুন।

## Endpoint

| OpenAI endpoint                                            | Tokens-এ                                                                                                                                 |
| ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `POST /v1/chat/completions`                                | Supported.                                                                                                                               |
| `POST /v1/responses`                                       | যে model-এর পেছনের provider এটা implement করে, সেখানে supported। দেখুন [Responses API](/docs/responses)।                                  |
| `POST /v1/completions` (legacy)                            | যেখানে provider implement করে সেখানে supported। অনেক chat model করে না।                                                                    |
| `POST /v1/embeddings`                                      | শুধু catalog-এর যেসব model embedding model, সেগুলোর জন্য।                                                                                  |
| `GET /v1/models`                                           | Supported, key ধরে ছাঁটা।                                                                                                                |
| `GET /v1/models/{id}` (`models.retrieve`)                  | Supported নয়: 404 `unsupported_endpoint`। list call করে নিজে filter করুন।                                                                  |
| Images, audio, files, uploads, batches, fine-tuning, moderations | Supported নয়: 404 `unsupported_endpoint`।                                                                                          |
| Assistants, threads, runs                                  | Supported নয়: 404 `unsupported_endpoint`। OpenAI 26 August 2026-এ Assistants API বন্ধ করেছে আর Responses API-র দিকে যেতে বলেছে।             |
| Realtime API                                               | Supported নয়।                                                                                                                           |

তালিকার বাইরের যেকোনো path-এ 404 আর `unsupported_endpoint` code আসে। আপনার app এর কোনোটা ব্যবহার করলে সেই অংশ OpenAI-তেই রেখে দিন, আর শুধু text call-গুলো সরান। তখন দুটো client থাকবে, প্রতিটার নিজের base URL আর key।

Tokens-এ এমন দুটো endpoint আছে যা OpenAI-তে নেই: `GET /v1/tokens/usage` (plan window, Wallet-এর ব্যালান্স আর key-র সীমা, দেখুন [Models and usage](/docs/models-and-usage)) আর Anthropic-ধাঁচের `POST /v1/messages` ([Messages](/docs/messages))।

### Responses API

আপনার code `client.responses.create` ব্যবহার করলে একই বদলে সেটাও Tokens base URL-এ চলে। [Responses API পাতা](/docs/responses) থেকে দুটো সতর্কতা:

- Tokens prompt বা response জমিয়ে রাখে না। `store: true` বা `previous_response_id` দিয়ে conversation-এর state ধরে রাখার ওপর ভরসা করবেন না। প্রতিবার call-এ পুরো conversation `input`-এ পাঠান।
- web search আর file search-এর মতো hosted tool আসলে provider-এর feature। gateway দিয়ে এগুলো চলবে, এটা ধরে নেবেন না। আগে test করে নিন।

যে model শুধু এমন provider থেকে আসে যে Anthropic-এর Messages protocol বোঝে, সেটা chat completions-এর উত্তর দেয় (Tokens request-টা অনুবাদ করে নেয়), কিন্তু `/v1/responses`, `/v1/completions` আর `/v1/embeddings` দেয় না। এসব call 400 `endpoint_not_supported_for_model` দিয়ে fail করে। এমন model-এর জন্য chat completions ব্যবহার করুন।

## যে পার্থক্যগুলো ঝামেলা বাধাতে পারে

### Rate limit অ্যাকাউন্ট ধরে, আর default-এ কম

OpenAI organization আর project ধরে প্রতি মিনিটের request ও token সীমিত করে, আর `x-ratelimit-*` header পাঠায়। Tokens সীমিত করে অ্যাকাউন্ট ধরে প্রতি মিনিটের request (default 60, নয়তো আপনার plan-এর মান) আর একসাথে চলা request (plan থাকলে 10, না থাকলে 3)। [rate limits](/docs/rate-limits) পাতায় প্রতি মিনিটে token-এর কোনো সীমা লেখা নেই। দুটোই অ্যাকাউন্ট ধরে, তাই বাড়তি key বানিয়ে কোনো সীমা বাড়ে না।

- 429-এর সাথে `Retry-After` আসে সেকেন্ডে। `x-ratelimit-*` header নেই, তাই যে code ওগুলো পড়ে সে কিছুই পাবে না। plan window-তে কতটা বাকি, তা দেখতে `GET /v1/tokens/usage` poll করুন।
- OpenAI-তে যে parallel job ঠিকঠাক চলত, এখানে সেটা `concurrency_limit`-এ আটকে যেতে পারে। parallelism নিজের দিকে সীমিত করুন, যেমন semaphore দিয়ে।
- `window_exhausted` আর `model_limit_reached`-এর `Retry-After` ঘণ্টা বা দিনের হতে পারে। এই দুটো loop-এ retry করবেন না। SDK default-এ 429 দুইবার retry করে। retry নিজে সামলালে `max_retries=0` (Python) বা `maxRetries: 0` (Node.js) দিন। [rate limits](/docs/rate-limits)-এর backoff উদাহরণে এটাই করা হয়েছে।

### Error-এর গড়ন একই, code আলাদা

Gateway-র error OpenAI-র JSON গড়নেই আসে: `error.message`, `error.type`, `error.code`, `error.param`, আর বাড়তি `error.request_id`। সিদ্ধান্ত নিন `error.code` দেখে। OpenAI-র code সাধারণত যা আশা করে, তার থেকে যেগুলো আলাদা:

| অবস্থা                | OpenAI                                          | Tokens                                                                                               |
| --------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| Credit শেষ            | quota বা spend-limit code-সহ 429                | 402 `insufficient_credits`, `no_funding` বা `outstanding_debt`। `type` হয় `insufficient_quota`।        |
| প্রতি মিনিটের limit   | `x-ratelimit-*` header-সহ 429                    | `Retry-After`-সহ 429 `rate_limited`                                                                  |
| Provider-এর সমস্যা    | 500, বা 503 `server_is_overloaded`               | 502 `upstream_unreachable`, 504 `upstream_timeout`, অথবা provider-এর 5xx, `upstream_error` হিসেবে     |

Tokens-এ আরও কিছু code আছে যার OpenAI-তে সমতুল্য নেই: `model_not_found` (404, id catalog-এ নেই), `tier_permission_denied` (403, আপনার plan-এ model-টা নেই), আর key-র সীমার code `model_not_allowed_on_key` ও `monthly_spend_cap_exceeded` (403)।

আপনার code যদি প্রতিটা 429-কে "পরে আবার চেষ্টা করো" ধরে, আর প্রতিটা quota সমস্যাকে 429 ভাবে, তাহলে সে 402-ও retry করবে, যা কখনো সফল হয় না। পুরো তালিকা [errors](/docs/errors) পাতায়। 429 (`window_exhausted` আর `model_limit_reached` বাদে) আর 5xx backoff দিয়ে retry করুন। 400, 401, 402, 403 আর 404 retry করবেন না।

Model-এর পেছনের provider-এর নিজের error message বদলে একটা সাধারণ message বসানো হয়, যেমন "The request was rejected by the upstream provider."। তাই কোনো model কোনো parameter না নিলে যে 400 আসে, তাতে কোন parameter-টা সমস্যা তা বলা থাকে না। request-টা মিলিয়ে দেখুন [/models](/models)-এ সেই model-এর পাতার সাথে।

### Request id আলাদা

OpenAI পাঠায় `x-request-id`। Tokens প্রতিটা response-এ পাঠায় `x-tokens-request-id`, আর আপনি নিজের `x-request-id` পাঠালে সেটা `x-request-id`-তে ফিরিয়ে দেয়। `x-tokens-request-id` আপনার log-এ রেখে দিন। [Support](/docs/support) এই id ধরেই খোঁজে। provider-এর response header-এর মধ্যে Tokens শুধু একটা ছোট তালিকা পাস করে (`content-type`, `cache-control` আর `retry-after`), তাই rate-limit header-এর মতো provider-নির্দিষ্ট header আপনার কাছে পৌঁছায় না।

### Parameter নির্ভর করে model-এর ওপর

Tokens `model` আর `n` (1 থেকে 4) ছাড়া body-র আর কিছু validate করে না। `tools`, `response_format`, `reasoning_effort`, `seed`, `logprobs` ও এ ধরনের field সোজা model-এর পেছনের provider-এর কাছে যায়। কোনো model কোনোটা না মানলে হয় সেটা উপেক্ষা করে, নয়তো 400 দেয়। OpenAI-র model-এ যে feature সহজেই পেতেন, যেমন strict structured outputs বা image input, এখানে তা নির্ভর করে আপনি কোন model নিচ্ছেন তার ওপর। তাই সেই model-এর পাতা দেখে নিন।

একটা জায়গায় request বদলানো হয়। OpenAI-ধাঁচের reasoning model-এ (o-series আর GPT-5 ও তার পরের model) chat completions-এ gateway `max_tokens`-এর নাম বদলে `max_completion_tokens` করে দেয়, আর `temperature` ও `top_p` 1-এর সমান না হলে সরিয়ে ফেলে, কারণ ওই model-গুলো এগুলো নেয় না।

### Output-এর সীমা আর credit reservation

Request forward করার আগে Tokens সবচেয়ে খারাপ ক্ষেত্রের খরচটা reserve করে রাখে। হিসাব হয় আপনার `max_tokens` ধরে, না দিলে 8,192 output token ধরে। ব্যালান্স কম থাকলে বা key-র cap-এর কাছাকাছি পৌঁছালে বড় `max_tokens` প্রত্যাখ্যাত হতে পারে। ব্যালান্স কম হলে সেটা আপনার সামর্থ্য অনুযায়ী কমিয়েও দেওয়া হয় (16-র নিচে কখনো নামে না)। তাই `max_tokens` ততটাই দিন যতটা দরকার। টাকা কাটে যত token আসলে খরচ হয়েছে তার, reservation-এর নয়। দেখুন [Chat Completions](/docs/chat-completions)।

### Browser, সাইজ আর গোপনীয়তা

- CORS header নেই, তাই browser থেকে call fail করে। Tokens call করুন server থেকে। দেখুন [authentication](/docs/authentication)।
- Request body 10 MB পর্যন্ত হতে পারে (বেশি হলে 413 `request_entity_too_large`)। বড় base64 image-ও এই হিসাবে ধরা হয়।
- Tokens-এ network-এর একটা বাড়তি hop আছে, তাই প্রথম token আসার latency provider-কে সরাসরি call করার চেয়ে কম হবে না।
- আপনার prompt যায় সেই provider-এর কাছে, যে model-টা চালায়, আর সেই provider-এর data policy-ই সেখানে খাটে। Tokens নিজে রাখে usage metadata, prompt-এর লেখা নয়। দেখুন [security and privacy](/docs/security-and-privacy)।

### Billing

আপনি টাকা দেন Tokens-কে, USD বা BDT-তে, plan বা Wallet থেকে, প্রতিটা model-এর catalog দামে। যে traffic সরিয়ে আনলেন, তার জন্য OpenAI-র invoice আর আসবে না। দেখুন [plans and wallet](/docs/plans-and-wallet)।

## নিরাপদে switch পরীক্ষা করুন

1. **দ্বিতীয় একটা key বানান** [/dashboard/keys](/dashboard/keys)-এ। নাম দিন test-এর কথা মাথায় রেখে, একটা **কম monthly spend cap** দিন (যেমন কয়েক ডলার), আর যে এক-দুটো model চেষ্টা করবেন শুধু সেগুলো **allowed-models list**-এ রাখুন। cap আর list পরে বদলানো যায় না, তাই বদলাতে চাইলে নতুন key বানাতে হবে। Tokens প্রতিটা request-এর সবচেয়ে খারাপ ক্ষেত্রের খরচ cap-এর বিপরীতে গোনে, তাই cap-এর কাছাকাছি গিয়ে খুব বড় `max_tokens` প্রত্যাখ্যাত হতে পারে।
2. **Configuration দিয়ে switch করুন।** base URL, key আর model id environment variable বা config file থেকে পড়ুন, যাতে provider বদলাতে deploy-এ code বদলাতে না হয়।
3. **কিছুদিন দুটোই চালান।** একই prompt OpenAI আর Tokens, দুই জায়গায় পাঠিয়ে তুলনা করুন। log থেকে request replay করতে পারেন, নয়তো live traffic mirror করে Tokens-এর উত্তর ফেলে দিতে পারেন। ছোট একটা script-ই যথেষ্ট:

```python
import os
import time

from openai import OpenAI

openai_client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
tokens_client = OpenAI(base_url="https://tokens.bd/v1", api_key=os.environ["TOKENS_TEST_KEY"])

CANDIDATES = [
    ("openai", openai_client, "your-openai-model"),
    ("tokens", tokens_client, "deepseek/deepseek-v4.1-flash"),
]

prompt = [{"role": "user", "content": "Write a Python function that parses an ISO 8601 date."}]

for name, client, model in CANDIDATES:
    start = time.perf_counter()
    raw = client.chat.completions.with_raw_response.create(
        model=model, messages=prompt, max_tokens=400
    )
    elapsed = time.perf_counter() - start
    resp = raw.parse()
    print(name, resp.choices[0].finish_reason, resp.usage.total_tokens, f"{elapsed:.2f}s")
    print("  request id:", raw.headers.get("x-tokens-request-id") or raw.headers.get("x-request-id"))
```

4. **শুধু লেখা নয়, আপনার app-এর কাছে যা জরুরি তা মিলিয়ে দেখুন:**

| যা দেখবেন               | কীভাবে                                                                                                    |
| ----------------------- | --------------------------------------------------------------------------------------------------------- |
| উত্তরের মান             | দুই জায়গাতেই আপনার নিজের test prompt বা eval চালান। model-এ model-এ তফাত থাকেই।                          |
| Tool call               | argument কি আপনার schema অনুযায়ী valid JSON? model কি ঠিক tool-টা call করছে?                              |
| `finish_reason`         | আগের চেয়ে বেশি `length` মানে এই model-এর জন্য `max_tokens` কম পড়ছে।                                     |
| Token সংখ্যা আর খরচ     | Token-এর সংখ্যা model ভেদে আলাদা। একটা কাজ শেষ করতে কত খরচ হলো, তা তুলনা করুন [usage](/docs/usage-and-alerts)-এ। |
| Latency                 | `stream: true` দিয়ে প্রথম token আসতে কত সময় লাগছে, আপনার app যেখানে চলে সেখান থেকে।                       |
| Error                   | `error.code` ধরে গুনুন। 402 বা 429 `concurrency_limit` দেখলে বুঝবেন sizing-এ সমস্যা আছে।                   |

5. **ধীরে ধীরে বাড়ান।** traffic-এর একটা ছোট অংশ সরান (feature flag বা শতাংশ ধরে), এক-দুই দিন নজর রাখুন, তারপর বাড়ান। test key-র জায়গায় production key বসান, যার cap আপনার পছন্দমতো। cut over-এর আগেই সেটা বানিয়ে রাখুন, কারণ [rotate বা revoke](/docs/api-keys) করলে তা সাথে সাথে কার্যকর হয়।

## Roll back করবেন যেভাবে

ফেরার পথ খোলা রাখলে roll back মানে switch-এর উল্টোটা:

1. Tokens পুরো একটা billing cycle production traffic সামলানোর আগে পর্যন্ত আপনার OpenAI key আর তার billing চালু রাখুন।
2. একই configuration দিয়ে base URL, key আর model id আগের জায়গায় ফিরিয়ে দিন, তারপর redeploy করুন বা flag উল্টে দিন। `OPENAI_BASE_URL` ব্যবহার করে থাকলে সেটা unset করুন।
3. যে Tokens key আর লাগবে না, সেটা [/dashboard/keys](/dashboard/keys)-এ গিয়ে revoke বা rotate করুন।

Tokens-এ আপনার Wallet-এর ব্যালান্স আর plan অ্যাকাউন্টেই থাকে। Refund-এর নিয়ম [refund policy](/refund-policy)-তে। কিছু export করার দরকার নেই, কারণ Tokens prompt-এর লেখা রাখেই না।

## এরপর কোথায় যাবেন

- Request format-এর জন্য [Chat Completions](/docs/chat-completions), [Responses API](/docs/responses) আর [Streaming](/docs/streaming)।
- SDK সেটআপের জন্য [Python](/docs/python) আর [Node.js](/docs/nodejs)।
- পুরো code তালিকা আর backoff উদাহরণের জন্য [Errors](/docs/errors) আর [Rate limits](/docs/rate-limits)।
- [OpenRouter থেকে চলে আসা](/docs/migrate-from-openrouter) আর [Anthropic থেকে চলে আসা](/docs/migrate-from-anthropic)।

সূত্র, অক্টোবর 2026-এ দেখা: OpenAI-র [API reference overview](https://developers.openai.com/api/reference/overview), [error codes](https://developers.openai.com/api/docs/guides/error-codes), [rate limits](https://developers.openai.com/api/docs/guides/rate-limits), [Assistants migration](https://developers.openai.com/api/docs/assistants/migration), আর [openai-python](https://github.com/openai/openai-python) ও [openai-node](https://github.com/openai/openai-node)-এর source। Tokens-এর আচরণ নেওয়া হয়েছে gateway code আর এখানে দেওয়া পাতাগুলো থেকে। কোনো live OpenAI অ্যাকাউন্টের বিপরীতে এটা test করা হয়নি।

---
Page: https://tokens.bd/bn/docs/migrate-from-openai
