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

> OpenRouter থেকে Tokens-এ app সরানোর গাইড: base URL, key আর model id কী বদলাবেন, OpenRouter-এর routing field, header আর model suffix-এর কী হয়, error ও limit-এ কী তফাত, আর কীভাবে test করবেন ও roll back করবেন।

OpenRouter আর Tokens, দুটোই একটা OpenAI-compatible endpoint দিয়ে অনেক provider-এর model দেয়। তাই OpenRouter-এর জন্য লেখা app-এ সাধারণত অন্য যেকোনো OpenAI app-এর মতোই তিনটা বদল লাগে: base URL, key আর model id। আসল কাজটা অন্য জায়গায়: OpenAI format-এর ওপর OpenRouter যা যা বাড়তি করে, যেমন provider routing, model fallback, model suffix, attribution header আর cost field। Tokens এগুলো করে না। প্রতিটার কী হয়, তা এই পাতায় আলাদা করে বলা আছে।

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

| Setting  | OpenRouter                                          | Tokens                                              | কোথায় বসাবেন                           |
| -------- | --------------------------------------------------- | --------------------------------------------------- | --------------------------------------- |
| Base URL | `https://openrouter.ai/api/v1`                      | `https://tokens.bd/v1`                               | SDK-তে `base_url` বা `baseURL`          |
| API key  | OpenRouter-এর একটা key                              | [API keys](/docs/api-keys) থেকে `tok_live_...`      | `api_key` বা `apiKey`                   |
| Model id | `provider/model`, OpenRouter-এর slug                | `provider/model`, `/models` থেকে Tokens-এর alias    | প্রতিটা request-এর `model` field-এ      |
| Header   | `HTTP-Referer`, `X-Title` (attribution, ঐচ্ছিক)     | লাগে না। বাদ দিন।                                   | `default_headers` বা `defaultHeaders`   |

যা একই থাকে:

- `POST /v1/chat/completions`-এর OpenAI request ও response format: `messages`, `tools`, `stream` আর `usage` object-সহ। দেখুন [Chat Completions](/docs/chat-completions)।
- `Authorization: Bearer <key>` দিয়ে authentication, আর Server-Sent Events streaming।
- যেকোনো OpenAI SDK, অথবা OpenRouter-এ যে Vercel AI SDK, LangChain-এর মতো library চালাচ্ছিলেন, সেগুলো। এদের base URL আর key একই জায়গায় বদলে নিন।

## আগে আর পরে

:::code-tabs

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

 client = OpenAI(
-    base_url="https://openrouter.ai/api/v1",
-    api_key=os.environ["OPENROUTER_API_KEY"],
-    default_headers={
-        "HTTP-Referer": "https://example.com",
-        "X-Title": "My app",
-    },
+    base_url="https://tokens.bd/v1",
+    api_key=os.environ["TOKENS_API_KEY"],
 )

 resp = client.chat.completions.create(
-    model="provider/openrouter-model-slug",
+    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({
-  baseURL: "https://openrouter.ai/api/v1",
-  apiKey: process.env.OPENROUTER_API_KEY,
-  defaultHeaders: { "HTTP-Referer": "https://example.com", "X-Title": "My app" },
+  baseURL: "https://tokens.bd/v1",
+  apiKey: process.env.TOKENS_API_KEY,
 });

 const resp = await client.chat.completions.create({
-  model: "provider/openrouter-model-slug",
+  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://openrouter.ai/api/v1/chat/completions \
-  -H "Authorization: Bearer $OPENROUTER_API_KEY" \
-  -H "HTTP-Referer: https://example.com" \
-  -H "X-Title: My app" \
+curl https://tokens.bd/v1/chat/completions \
+  -H "Authorization: Bearer $TOKENS_API_KEY" \
   -H "Content-Type: application/json" \
   -d '{
-    "model": "provider/openrouter-model-slug",
+    "model": "deepseek/deepseek-v4.1-flash",
     "messages": [{"role": "user", "content": "What does HTTP 429 mean?"}],
     "max_tokens": 300
   }'
```

:::

curl ব্যবহার করলে `Content-Type: application/json` রাখুন। এটা না থাকলে Tokens body পড়ে না, আর 400 `invalid_request` ফেরত দেয়।

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

## Model id দেখতে এক, কিন্তু আসলে এক নয়

OpenRouter-এর slug আর Tokens-এর alias, দুটোই `provider/model` ধাঁচের। কিন্তু তালিকা দুটো আলাদা। যে slug OpenRouter-এ চলে, Tokens-এ সেটা অচেনা হতে পারে, বা অন্য version-এর নাম হতে পারে। আবার Tokens-এর alias সবসময় provider-এর নিজের id-র সাথে মেলে না। কোনো pattern ধরে id বদলাতে যাবেন না।

1. আপনার key কোন কোন model call করতে পারে, তা দেখুন: `curl -s https://tokens.bd/v1/models -H "Authorization: Bearer $TOKENS_API_KEY"`। প্রতিটা `data[].id` ওই key-র জন্য valid।
2. দাম, context window আর capability আছে [/models](/models) পাতায়। API-র তালিকায় শুধু id থাকে। দেখুন [Choosing a model](/docs/choosing-a-model)।
3. পুরোনো id থেকে নতুন id-র একটা table configuration-এ রাখুন, যাতে mapping code-এর নানা জায়গায় ছড়িয়ে না থাকে।

`model`-এর মান alias-এর সাথে হুবহু মিলতে হবে। অচেনা id দিলে 404 `model_not_found` আসে।

## OpenRouter-এর feature, একটা একটা করে

OpenRouter-এর প্রতিটা feature নিয়ে Tokens কী করে, তা এখানে। এটা gateway code দেখে লেখা, আন্দাজে নয়।

**Model suffix।** OpenRouter `:free`, `:nitro`, `:floor`, `:exacto` (আর বাতিল হয়ে যাওয়া `:online`, `:thinking`, `:extended`) model id-র অংশ হিসেবে চালায়। Tokens পুরো string-টাকেই alias হিসেবে খোঁজে, তাই `some/model:nitro` দিলে 404 `model_not_found` আসে। suffix বাদ দিন। এর সমতুল্য কিছু নেই: Tokens-এ suffix নেই, আর request ধরে provider sort করাও নেই। সস্তা বা দ্রুত model চাইলে সেটা আলাদা একটা model id।

**Router model।** `openrouter/auto` আর OpenRouter-এর অন্য router id Tokens catalog-এ নেই (404 `model_not_found`)। একটা নির্দিষ্ট model বেছে নিন।

**Provider routing (`provider`)।** Tokens এই field পড়ে না। আবার প্রত্যাখ্যানও করে না: যে model-এর provider OpenAI protocol বোঝে (সাধারণত তাই হয়), সেখানে request body-র বাকি অংশ যেমন পাঠানো হয়েছে তেমনই provider-কে দিয়ে দেওয়া হয়। provider field-টা উপেক্ষা করবে নাকি 400 দেবে, তা provider-এর ব্যাপার, আর Tokens কোনো provider-এর আচরণ যাচাই করেনি। field-টা বাদ দিন। কোন provider model চালাবে, সেটা ঠিক করে Tokens, আপনি নন। আর response-এর `model` field-এ সবসময় সেই id-ই থাকে যেটা আপনি চেয়েছিলেন।

**Fallback (`models`, `route`)।** Implement করা নেই। নিয়ম ওপরের মতোই: forward হয়, কিন্তু কাজে লাগানো হয় না, তাই field-টার কোনো কাজ নেই। Tokens failover করে ঠিকই, তবে শুধু একই model-এর এক source থেকে আরেক source-এ: 429, 502, 503, 504 বা connection কেটে গেলে, আর উত্তরের একটা byte-ও আপনার কাছে পৌঁছানোর আগে, সে ওই model-এরই আরেকটা source-এ retry করে। অন্য model-এ কখনো যায় না। model fallback চাইলে সেটা আপনার code-এ করুন:

```python
import os

import openai
from openai import OpenAI

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

MODELS = ["deepseek/deepseek-v4.1-flash", "your-second-model-id"]  # ids from GET /v1/models


def ask(messages):
    last = None
    for model in MODELS:
        try:
            return client.chat.completions.create(model=model, messages=messages, max_tokens=512)
        except openai.APIStatusError as e:
            if e.status_code not in (429, 500, 502, 503, 504) or e.code == "window_exhausted":
                raise
            last = e
    raise last
```

`window_exhausted` বাদ রাখা হয়েছে, কারণ এটা পুরো অ্যাকাউন্টের plan window। অন্য model-এও একই জায়গায় আটকাবে।

**Prompt transform আর plugin (`transforms`, `plugins`)।** OpenRouter এগুলো দিয়ে লম্বা prompt ছোট করা, file parse করা, web search আর response মেরামতের সুবিধা দেয়। Tokens এর কিছুই করে না। `provider`-এর মতো এই field-গুলোও অচেনা body field হিসেবে provider-এর কাছে চলে যায়। prompt নিজেই ছোট করে নিন: model-এর context window ছাড়িয়ে গেলে Tokens prompt ছোট করে না, তখন কী হবে তা provider ঠিক করে।

**`reasoning` আর `usage` field।** বাকিগুলোর মতোই forward হয়। যে model reasoning সাপোর্ট করে, সেখানে এ দুটো নিয়ে কী করা হবে তা provider ঠিক করে। `usage: {"include": true}` request field-টা লাগেই না: OpenRouter-এর নিজের documentation একে deprecated বলে আর usage এমনিতেই পাঠায়, আর Tokens-এর উত্তরে provider-এর পাঠানো `usage` object সবসময় থাকে।

**Attribution header।** `HTTP-Referer`, `X-Title` আর `X-OpenRouter-*` header-গুলোর দাম শুধু OpenRouter-এ, app-এর পাতা আর ranking-এর জন্য। Tokens provider-কে request header পাঠায় একটা ছোট allow-list ধরে (`content-type`, `accept`, `openai-beta` আর `anthropic-version`, সাথে আরও কয়েকটা), বাকিগুলো error ছাড়াই ফেলে দেয়। পাঠালে ক্ষতি নেই, কিন্তু কোনো কাজও হয় না। code যেন উল্টো কিছু না বোঝায়, তাই বাদ দিয়ে দিন।

**কোনো field নিরাপদ কি না নিশ্চিত না হলে।** যে model ব্যবহার করবেন, সেটাতেই test করুন, নিচে বলা test key দিয়ে। provider কোনো field মানে কি না, তার একমাত্র প্রমাণ হলো চলতে থাকা একটা request।

যে model শুধু এমন provider থেকে আসে যে Anthropic-এর Messages protocol বোঝে, সেখানে Tokens আপনার chat completions request forward করে না, অনুবাদ করে নেয়। শুধু এই field-গুলো যায়: `messages` (text, image, tool call আর tool result), `max_tokens` বা `max_completion_tokens`, `temperature`, `top_p`, `stop`, `stream`, `tools`, `tool_choice`, `parallel_tool_calls` আর `user`। বাকি সব বাদ পড়ে, যেমন `n`, `response_format`, `seed`, `logprobs` আর penalty-গুলো। `temperature` সর্বোচ্চ 1-এ আটকে দেওয়া হয়, আর আপনি `max_tokens` না দিলে সেটা default 4096।

## Response আর usage-এর পার্থক্য

- Response-এর **`model`**-এ সবসময় সেই id-ই থাকে যেটা আপনি চেয়েছিলেন, যে provider-ই উত্তর দিক। OpenRouter-এর `model`-এ থাকে সে আসলে কোন model-এ route করেছে। তাই routing কী হলো দেখতে আপনি যদি এটা log করতেন, নতুন কিছু পাবেন না।
- **Cost field।** OpenRouter response-এ `cost`, `cost_details` আর `native_finish_reason` জুড়ে দেয়। Tokens provider-এর body-তে কিছুই যোগ করে না। প্রতিটা request-এর খরচ আছে আপনার [usage dashboard](/docs/usage-and-alerts)-এ আর CSV export-এ, model-এর catalog দামে হিসাব করা। আপনার নিজের customer-কে bill করতে যদি `usage.cost` পড়তেন, তাহলে export-এ চলে আসুন, নয়তো token সংখ্যা আর [/models](/models)-এর দাম দিয়ে নিজেই খরচ হিসাব করুন।
- **Usage খোঁজা।** `GET /generation?id=` বা `GET /key` বলে কিছু নেই। `GET /v1/tokens/usage` দেয় plan window, Wallet-এর ব্যালান্স আর যে key দিয়ে call করছেন তার cap ([Models and usage](/docs/models-and-usage))। response header `x-tokens-request-id` হলো সেই id, যা log-এ রাখবেন আর [support](/docs/support)-কে জানাবেন।
- **Streaming।** Stream-এর শেষে usage chunk আসে যখন আপনি `stream_options: {"include_usage": true}` পাঠান। দেখুন [Streaming](/docs/streaming)।

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

### Error

OpenRouter-এর error দেখতে `{"error": {"code": 429, "message": "...", "metadata": {...}}}`, যেখানে `code` একটা সংখ্যা। Tokens-এর error হলো `{"error": {"message", "type", "code", "param", "request_id"}}`, আর এর `code` একটা **string**, যেমন `rate_limited`। যে code `error.code`-কে সংখ্যা ধরে পড়ে, বা `error.metadata` পড়ে, তা বদলাতে হবে: error কোন ধরনের তা বুঝতে HTTP status আর কারণ বুঝতে `error.code` দেখুন। পুরো table [errors](/docs/errors) পাতায়।

| অবস্থা                   | OpenRouter                                    | Tokens                                                                               |
| ------------------------ | --------------------------------------------- | ------------------------------------------------------------------------------------ |
| Credit শেষ               | 402                                           | 402 `insufficient_credits`, `no_funding` বা `outstanding_debt`                       |
| Rate limit               | 429                                           | 429 `rate_limited`, `concurrency_limit`, `window_exhausted` বা `model_limit_reached` |
| আপনার দেওয়া key limit   | Key credit limit: 402                         | 403 `monthly_spend_cap_exceeded` (দেখুন [API keys](/docs/api-keys))                   |
| Timeout                  | 408                                           | 504 `upstream_timeout`                                                               |
| Model down               | 502                                           | 502 `upstream_unreachable`, অথবা provider-এর 5xx, `upstream_error` হিসেবে            |
| কোনো provider নেই        | 503                                           | 503 `no_upstream_available`                                                          |

OpenRouter-এর documentation বলে, streaming শুরু হওয়ার পরে কিছু fail করলে সেটা 200 response-এর ভেতরে একটা error event হয়ে আসে। এর জন্য আপনি body-র ভেতরে যে error check বসিয়েছিলেন, সেটা রেখে দিন।

Provider-এর নিজের error message বদলে একটা সাধারণ message বসানো হয়, আর `metadata.provider_*`-এর খুঁটিনাটি তথ্য নেই।

### Rate limit

OpenRouter free model-কে প্রতি মিনিটে 20 request-এ বেঁধে রাখে, আর paid model-এ platform-এর কোনো cap দেয় না। Tokens সীমিত করে **অ্যাকাউন্ট ধরে প্রতি মিনিটের request** (default 60, নয়তো আপনার plan-এর মান) আর **অ্যাকাউন্ট ধরে একসাথে চলা request** (plan থাকলে 10, না থাকলে 3)। OpenRouter-এ যে agent বা batch job অনেক parallelism নিয়ে চলত, সে এখানে `concurrency_limit`-এ আটকাতে পারে। তার parallelism সীমিত করুন। বেশি key বানালে limit বাড়ে না।

- 429-এর সাথে `Retry-After` আসে সেকেন্ডে। `X-RateLimit-*` header নেই। plan window দেখতে `GET /v1/tokens/usage` poll করুন।
- `window_exhausted` আর `model_limit_reached` মানে অপেক্ষা ঘণ্টা বা দিনেরও হতে পারে। এ দুটো loop-এ retry করবেন না।
- সংখ্যাগুলো আর একটা backoff উদাহরণ পাবেন [rate limits](/docs/rate-limits) পাতায়।

### আরও কিছু পার্থক্য

- **`/api/v1` path নেই।** Tokens-এর path `/v1`: `https://tokens.bd/v1`।
- **Supported নয় এমন endpoint।** Images, audio, files, batches, assistants, fine-tuning আর moderations 404 `unsupported_endpoint` দেয়। Embeddings চলে শুধু embedding model-এ। Supported: `/v1/chat/completions`, `/v1/responses`, `/v1/completions` (legacy), `/v1/embeddings`, `/v1/models`, `/v1/messages` আর `/v1/messages/count_tokens`।
- **Parameter নির্ভর করে model-এর ওপর।** `model` আর `n` (1 থেকে 4) ছাড়া Tokens body validate করে না। Tool calling, `response_format`, vision আর reasoning model ভেদে আলাদা। OpenAI o-series আর GPT-5 ও তার পরের model-এ chat completions-এ gateway `max_tokens`-এর নাম বদলে `max_completion_tokens` করে দেয়, আর `temperature` ও `top_p` 1-এর সমান না হলে সরিয়ে ফেলে।
- **Output reservation।** Tokens প্রতিটা request-এর সবচেয়ে খারাপ ক্ষেত্রের খরচ reserve করে, `max_tokens` ধরে, না দিলে 8,192 output token ধরে। ব্যালান্স কম থাকলে বা key-র cap প্রায় ভরে এলে বড় `max_tokens` প্রত্যাখ্যাত হতে পারে বা কমিয়ে দেওয়া হতে পারে। যতটা দরকার ততটাই দিন।
- **CORS নেই।** Browser থেকে call fail করে। Tokens call করুন server থেকে।
- **Body-র সাইজ।** 10 MB পর্যন্ত।
- **গোপনীয়তা।** Tokens রাখে usage metadata, prompt-এর লেখা নয়। যে provider model চালায় সে prompt দেখে, আর তার policy-ই খাটে। দেখুন [security and privacy](/docs/security-and-privacy)।
- **পেমেন্ট।** Tokens-এ bill হয় USD বা BDT-তে, plan বা Wallet থেকে। OpenRouter credit বলে কিছু নেই। দেখুন [plans and wallet](/docs/plans-and-wallet)।

Anthropic SDK দিয়ে OpenRouter-এর Anthropic-ধাঁচের Messages endpoint call করলে [Anthropic থেকে চলে আসা](/docs/migrate-from-anthropic) পাতাটাও পড়ে নিন। Tokens `POST /v1/messages` দেয়, আর সেখানে base URL-এ `/v1` থাকে না।

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

1. **দ্বিতীয় একটা key বানান** [/dashboard/keys](/dashboard/keys)-এ, একটা **কম monthly spend cap** দিয়ে, আর এমন **allowed-models list** দিয়ে যাতে শুধু test করা model-গুলোই থাকে। দুটোর কোনোটাই পরে বদলানো যায় না। Tokens প্রতিটা request-এর সবচেয়ে খারাপ ক্ষেত্রের খরচ cap-এর বিপরীতে গোনে।
2. **Base URL, key আর model id configuration থেকে পড়ুন**, constant থেকে নয়, যাতে switch করা মানে শুধু config বদল।
3. **কিছুদিন দুটোই চালান।** log থেকে request replay করুন, অথবা live traffic-এর একটা অংশ Tokens-এ mirror করে তার উত্তর ফেলে দিন। একই prompt দুই জায়গায় চালিয়ে মিলিয়ে দেখুন:

| যা দেখবেন                   | কীভাবে                                                                                            |
| --------------------------- | ------------------------------------------------------------------------------------------------- |
| মান                         | নিজের prompt বা eval চালান। জোড়ার দুটো model খুব কমই একই model হয়।                              |
| যে field আর পাঠাচ্ছেন না    | `provider`, `models`, `transforms` আর header ছাড়া একবার চালান। কোনো কিছু কি এগুলোর ওপর নির্ভর করত? |
| Tool call                   | আপনার বেছে নেওয়া model-এ আপনার schema অনুযায়ী argument valid JSON কি না।                         |
| `finish_reason`             | আগের চেয়ে বেশি `length` মানে `max_tokens` কম পড়ছে।                                              |
| একটা কাজ শেষ করার খরচ       | OpenRouter-এর `usage.cost`-এর সাথে [usage](/docs/usage-and-alerts)-এর খরচ মেলান।                  |
| Error                       | `error.code` ধরে গুনুন।                                                                           |

4. **ধীরে ধীরে বাড়ান**, feature flag বা শতাংশ ধরে। cut over-এর আগেই আপনার পছন্দমতো cap দিয়ে production key বানিয়ে রাখুন।

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

1. Tokens পুরো একটা billing cycle production traffic সামলানোর আগে পর্যন্ত আপনার OpenRouter key আর credit রেখে দিন।
2. পুরোনো base URL, key, model id আর header configuration-এ ফিরিয়ে দিন, তারপর deploy করুন বা flag উল্টে দিন।
3. যে Tokens key আর লাগবে না, সেটা [/dashboard/keys](/dashboard/keys)-এ revoke করুন। আপনার Wallet-এর ব্যালান্স অ্যাকাউন্টেই থাকে। দেখুন [refund policy](/refund-policy)।

id mapping যেহেতু configuration-এ আছে, roll back মানে একই বদলটা উল্টো দিকে করা।

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

- [Chat Completions](/docs/chat-completions), [Streaming](/docs/streaming) আর [Tool calling](/docs/tool-calling)।
- [Errors](/docs/errors) আর [Rate limits](/docs/rate-limits)।
- OpenAI-ধাঁচের switch-এর সাধারণ অংশগুলোর জন্য [OpenAI থেকে চলে আসা](/docs/migrate-from-openai)।

সূত্র, অক্টোবর 2026-এ দেখা: OpenRouter-এর [API overview](https://openrouter.ai/docs/api-reference/overview), [errors](https://openrouter.ai/docs/api-reference/errors), [limits](https://openrouter.ai/docs/api-reference/limits), [provider routing](https://openrouter.ai/docs/guides/routing/provider-selection), [model fallbacks](https://openrouter.ai/docs/guides/routing/model-fallbacks), [model variants](https://openrouter.ai/docs/guides/routing/model-variants), [usage accounting](https://openrouter.ai/docs/guides/guides/usage-accounting) আর [app attribution](https://openrouter.ai/docs/app-attribution)। Tokens-এর আচরণ নেওয়া হয়েছে gateway code আর এখানে দেওয়া পাতাগুলো থেকে। কোনো live OpenRouter অ্যাকাউন্টের বিপরীতে এটা test করা হয়নি।

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