# Token Counting

> POST /v1/messages/count_tokens model না চালিয়েই request-এর input size জানায়। count কতটা নিখুঁত, এতে কত খরচ, আর chat, completions, responses ও embeddings-এর token কীভাবে গুনবেন বা আন্দাজ করবেন।

token কত, তার ওপর নির্ভর করে request-এর খরচ কত, সেটা model-এর context window-তে আঁটবে কি না, আর আপনার plan-এর কতটা খরচ হবে। Tokens-এ token জানার দুটো উপায় আছে। একটা counting endpoint, যেটা request পাঠানোর আগেই input-এর size বলে দেয়। আরেকটা প্রতিটা response-এর `usage` object, যেটা বলে আসলে কত বিল হলো। এই পেজে দুটোই আছে, সাথে দুটোর কোনোটাই হাতে না থাকলে কীভাবে আন্দাজ করবেন সেটাও।

## POST /v1/messages/count_tokens দিয়ে token গোনা

`POST https://tokens.bd/v1/messages/count_tokens` [`/v1/messages`](/docs/messages)-এর মতোই body নেয় আর input token-এর সংখ্যা ফেরত দেয়। এটা কখনো model চালায় না, কোনো text-ও তৈরি করে না। এটা Anthropic format-এ কাজ করে, তাই Anthropic SDK-র base URL হিসেবে দিতে হয় শুধু host-টা, অর্থাৎ `https://tokens.bd`।

:::code-tabs

```bash title="cURL"
curl -i https://tokens.bd/v1/messages/count_tokens \
  -H "x-api-key: $TOKENS_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "deepseek/deepseek-v4.1-flash",
    "system": "You are a concise senior engineer.",
    "messages": [
      {"role": "user", "content": "Explain idempotency keys in two sentences."}
    ]
  }'
```

```python title="Python"
import os
import anthropic

client = anthropic.Anthropic(
    base_url="https://tokens.bd",
    api_key=os.environ["TOKENS_API_KEY"],
)

count = client.messages.count_tokens(
    model="deepseek/deepseek-v4.1-flash",
    system="You are a concise senior engineer.",
    messages=[{"role": "user", "content": "Explain idempotency keys in two sentences."}],
)
print(count.input_tokens)
```

```typescript title="Node.js"
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({
  baseURL: "https://tokens.bd",
  apiKey: process.env.TOKENS_API_KEY,
});

const count = await client.messages.countTokens({
  model: "deepseek/deepseek-v4.1-flash",
  system: "You are a concise senior engineer.",
  messages: [{ role: "user", content: "Explain idempotency keys in two sentences." }],
});
console.log(count.input_tokens);
```

:::

response-এ থাকে মাত্র একটা field:

```json
{ "input_tokens": 31 }
```

সংখ্যাটা বোঝানোর জন্য দেওয়া। Tokens-এর সব endpoint-এর মতো এখানেও `model` বাধ্যতামূলক, তবে `max_tokens` লাগে না। `system`, text ও image-সহ `messages`, আর `tools` পাঠাতে পারেন, count-এ সবকটাই ধরা হয়। authentication `/v1/messages`-এর মতোই: `x-api-key` বা `Authorization: Bearer`। অন্য জায়গার মতো এখানেও `content-type: application/json` পাঠান।

## নিখুঁত count, না আন্দাজ

token কীভাবে গোনা হবে সেটা ঠিক করে model, তাই Tokens দুইভাবে উত্তর দেয়:

| কী হয়                                                                                                                                                   | কীভাবে বুঝবেন                              |
| -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
| model-টা যে provider-দের মাধ্যমে চলে, তাদের কেউ Anthropic Messages protocol বোঝে। তাই request তার কাছে যায় আর আপনি তার নিজের count পান।                 | আলাদা কোনো header নেই।                     |
| model-এর কোনো provider ওই protocol বোঝে না, অথবা যে বোঝে সে down আছে বা 404, 405, 429 বা কোনো 5xx error দিয়েছে। তখন Tokens নিজেই locally গোনে। | response header `x-tokens-estimated: true`। |

যে model শুধু OpenAI-format provider-এর মাধ্যমে চলে, তার native counting নেই, তাই সে সব সময় আন্দাজই পায়। কোনো সংখ্যা token-পর্যায়ে নিখুঁত ধরে নেওয়ার আগে header-টা দেখে নিন (`curl -i` ওটা দেখিয়ে দেয়)।

locally যে হিসাব হয়, সেটা ইচ্ছে করেই মোটামুটি। এটা `system`, `messages` আর `tools`-এর text প্রায় চার character-এ এক token ধরে গোনে, প্রতিটা image বা document block-এর জন্য flat 1,600 token যোগ করে, প্রতিটা message-এর জন্য আরও কয়েকটা token ধরে, আর কমপক্ষে 1 ফেরত দেয়। এই সংখ্যাগুলো বদলে যেতে পারে। "এটা আঁটবে তো?" বা "মোটামুটি কত বড়?" জানতে এটা যথেষ্ট, কিন্তু নিখুঁত count নয়। code, JSON আর বাংলার মতো ইংরেজি-ভিন্ন text-এ চার character-এ এক token ধরাটা সবচেয়ে কম ঠিক হয়, কারণ ইংরেজি গদ্যের তুলনায় এগুলোতে প্রতি character-এ সাধারণত বেশি token লাগে। budget ঠিক করার আগে নিজের data মেপে দেখুন (নিচে দেখুন)।

provider যখন forward করে, count তখন Anthropic-এর নিজের endpoint-এর মতোই চলে। Anthropic-এর token counting docs অনুযায়ী, অক্টোবর 2026-এ মিলিয়ে দেখা হয়েছে: count নিজেও একটা আন্দাজ, তাই বিল হওয়া সংখ্যা থেকে সামান্য আলাদা হতে পারে। এটা system prompt, tool, image আর PDF গোনে, আর server tool, MCP connector এবং `url` বা `file` ধরনের image ও document source বাতিল করে দেয় (image আর PDF base64-এ পাঠান)। count আবার model-এর tokenizer-এর ওপরও নির্ভর করে, তাই যে model id পাঠাবেন সেটা দিয়েই গুনুন।

## Count করতে কত খরচ, আর এটা কিসের হিসাবে ধরা হয়

- **বিল হয় না।** count কখনো চার্জ করে না, plan-এর credit খরচ করে না, আর কোনো usage record-ও লেখে না।
- **তবু request-এর মতোই যাচাই হয়।** counting-ও inference-এর মতো একই admission ধাপ পার হয়। তাই লাগে একটা valid key, এমন model যা আপনার key আর plan call করতে পারে, আর এমন অ্যাকাউন্ট যাতে plan বা Wallet-এর ব্যালান্স আছে। এটা আপনার per-minute request limit-এ গোনা হয় আর চলার সময় একটা concurrency slot ধরে রাখে। usage window শেষ হয়ে গেলে (429 `window_exhausted`) বা key অন্য model-এর জন্য সীমিত থাকলে counting-ও আটকে যায়। `GET /v1/models` আর `GET /v1/tokens/usage`-এর মতো এটা rate limit থেকে মুক্ত নয়। [rate limits](/docs/rate-limits) পেজ দেখুন।
- **একই size-এর সীমা।** image-সহ body 10 MB পর্যন্ত হতে পারে।
- **Messages endpoint লাগে।** gateway-তে Anthropic Messages endpoint বন্ধ করা থাকলে counting 404 `anthropic_protocol_disabled` ফেরত দেয়, তখন নিচের উপায়গুলো ব্যবহার করুন।

এই endpoint-এর error Anthropic-এর error shape-এ আসে, ভেতরে থাকে Tokens-এর `code`। [Messages](/docs/messages) পেজে এটা বিস্তারিত আছে। code-গুলোর তালিকা [errors](/docs/errors) পেজে।

## অন্য endpoint-এর token গোনা

chat completions, completions, responses বা embeddings-এর জন্য কোনো counting endpoint নেই। তার বদলে এগুলো করুন।

### ফেরত আসা usage পড়ুন

প্রতিটা সফল inference response জানায় provider কত গুনেছে, আর Tokens ঠিক সেটার ওপরই বিল করে:

| Endpoint               | সংখ্যাগুলো কোথায়                                                                                                                                   |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/v1/chat/completions` | `usage.prompt_tokens`, `usage.completion_tokens`, `usage.total_tokens`; cache করা input জানানো হলে `usage.prompt_tokens_details.cached_tokens`-এ |
| `/v1/completions`      | `usage.prompt_tokens`, `usage.completion_tokens`, `usage.total_tokens`                                                                              |
| `/v1/embeddings`       | `usage.prompt_tokens`, `usage.total_tokens`                                                                                                         |
| `/v1/responses`        | `usage.input_tokens`, `usage.output_tokens`                                                                                                         |
| `/v1/messages`         | `usage.input_tokens`, `usage.output_tokens`, সাথে provider জানালে cache-এর field-ও                                                                  |

stream-এর ক্ষেত্রে chat completions তখনই `usage` দেয়, যখন আপনি `stream_options: {"include_usage": true}` দেন। Anthropic-format stream-এ এটা আসে `message_start` আর `message_delta` event-এ। বিস্তারিত [streaming](/docs/streaming) পেজে। প্রতিটা request-এর খরচ দেখা যায় [usage analytics](/docs/usage-and-alerts)-এ, আর plan-এর window ও Wallet-এর ব্যালান্স কতটা বাকি তা পাবেন `GET /v1/tokens/usage`-এ ([models and usage](/docs/models-and-usage))।

### এক token-এর request দিয়ে মেপে নিন

লম্বা generation চালানোর আগে chat model-এর জন্য prompt-এর ঠিক size জানতে চাইলে আসল prompt-টা `max_tokens` 1 দিয়ে পাঠান, আর `usage.prompt_tokens` পড়ুন:

```bash
curl https://tokens.bd/v1/chat/completions \
  -H "Authorization: Bearer $TOKENS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek/deepseek-v4.1-flash",
    "messages": [{"role": "user", "content": "Explain idempotency keys in two sentences."}],
    "max_tokens": 1
  }'
```

এটার বিল হয়: input token আর বড়জোর একটা output token-এর দাম দিতে হয়। এটাও একটা request হিসেবে গোনা হয়। কিছু model খুব ছোট `max_tokens` নেয় না বা উপেক্ষা করে, তাই 400 এলে একটু বাড়িয়ে দিন। Messages format-এ আরও সস্তায় দেখতে চাইলে ওপরের counting endpoint ব্যবহার করুন।

### মোটামুটি নিয়মে আন্দাজ করুন

তাড়াতাড়ি একটা budget ধরতে, ইংরেজি গদ্যের character-সংখ্যাকে চার দিয়ে ভাগ করুন। gateway নিজের pre-flight check-এও তাই করে: forward করার আগে সে সবচেয়ে খারাপ ক্ষেত্রের খরচ ধরে রাখে, input-এর জন্য request body-র size-কে চার দিয়ে ভাগ করে, আর output-এর জন্য `max_tokens` (না দিলে 8,192) ধরে। এই reservation নিরাপত্তার জন্য বাড়তি ধরে রাখা অঙ্ক মাত্র, বিল নয়: চার্জ হয় provider-এর জানানো `usage`-এর ওপর। তবে এর ফলে `max_tokens` অনেক বড় দিলে, আসল উত্তর ছোট হলেও, টাকার অভাবে বা spend cap-এর কারণে request fail করতে পারে। তাই `max_tokens` যতটা দরকার তার কাছাকাছি রাখুন। [chat completions](/docs/chat-completions) পেজ দেখুন।

কোনো local tokenizer library শুধু সেই model-পরিবারের জন্যই নিখুঁত count দেয়, যার জন্য সেটা বানানো। অন্য model-এর বেলায় সেটাও আরেকটা আন্দাজ, তাই size ঠিক করতে ব্যবহার করুন, আর সত্যি সংখ্যার জন্য `usage` object দেখুন।

## পাঠানোর আগে দেখে নিন prompt আঁটবে কি না

prompt-এর token আর `max_tokens` মিলিয়ে model-এর context window-র ভেতরে থাকলে request আঁটে। context window-র মান [catalog](/models)-এ model-এর পেজে আছে। নিচের Python helper আগে গোনে, তারপর যতটা জায়গা বাকি তার ভিত্তিতে `max_tokens` ঠিক করে:

```python
import os
import anthropic

client = anthropic.Anthropic(
    base_url="https://tokens.bd",
    api_key=os.environ["TOKENS_API_KEY"],
)

CONTEXT_WINDOW = 128_000  # read this from the model's catalog page
messages = [{"role": "user", "content": open("big-file.txt").read()}]

used = client.messages.count_tokens(model="deepseek/deepseek-v4.1-flash", messages=messages).input_tokens
room = CONTEXT_WINDOW - used
if room < 1_000:
    raise SystemExit(f"Prompt is {used} tokens; too close to the context window.")

reply = client.messages.create(
    model="deepseek/deepseek-v4.1-flash",
    max_tokens=min(4_000, room),
    messages=messages,
)
print(reply.usage)
```

`CONTEXT_WINDOW`-এর জায়গায় আপনার model-এর আসল মান বসান। count যদি আন্দাজ হয়, তাহলে বাড়তি জায়গা রাখুন, যেমন 10 শতাংশ।

## আরও পড়ুন

- [Messages](/docs/messages): যে endpoint-এর body নিয়ে counting কাজ করে।
- [Chat completions](/docs/chat-completions), [Embeddings](/docs/embeddings) আর [Legacy completions](/docs/legacy-completions): প্রতিটার `usage` object দেখতে।
- [Plans and wallet](/docs/plans-and-wallet): token কীভাবে credit আর খরচে বদলায়।

---
Page: https://tokens.bd/bn/docs/token-counting
