POST https://tokens.bd/v1/completions হলো OpenAI-র আদি text completions endpoint: আপনি একটা prompt string পাঠান, আর model সেই text-টার পরের অংশ লিখে দেয়। যেসব পুরোনো tool আর script এখনো এটা call করে, তাদের জন্য Tokens এটা পাস করে দেয়। নতুন কিছু বানালে chat completions ব্যবহার করুন। সব chat model সেটা সমর্থন করে, আর বেশির ভাগ coding agent সেটাই আশা করে।
সব model এই endpoint চালায় না
Tokens request-টা model-এর provider-এর কাছে পাঠিয়ে দেয়, আর model সাধারণ text completion করতে পারে কি না সেটা provider ঠিক করে। অনেক chat model পারে না, আর যেগুলো পারে তাদের কোনো তালিকাও নেই। এর ওপর কিছু দাঁড় করানোর আগে নিচের মতো ছোট একটা request দিয়ে আপনার model পরীক্ষা করে নিন।
Completions request পাঠানো#
curl https://tokens.bd/v1/completions \
-H "Authorization: Bearer $TOKENS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek/deepseek-v4.1-flash",
"prompt": "A one-line definition of HTTP 429:",
"max_tokens": 40,
"temperature": 0
}'import os
from openai import OpenAI
client = OpenAI(base_url="https://tokens.bd/v1", api_key=os.environ["TOKENS_API_KEY"])
resp = client.completions.create(
model="deepseek/deepseek-v4.1-flash",
prompt="A one-line definition of HTTP 429:",
max_tokens=40,
temperature=0,
)
print(resp.choices[0].text)
print(resp.usage)import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://tokens.bd/v1", apiKey: process.env.TOKENS_API_KEY });
const resp = await client.completions.create({
model: "deepseek/deepseek-v4.1-flash",
prompt: "A one-line definition of HTTP 429:",
max_tokens: 40,
temperature: 0,
});
console.log(resp.choices[0].text, resp.usage);error এলে কোন model চলে section-টা পড়ুন। Content-Type: application/json header-টা জরুরি: এটা না থাকলে gateway body পড়তে পারে না, আর model field নেই বলে 400 invalid_request দেয়।
Request-এর field#
body চলে OpenAI-র completions format মেনে। OpenAI-র API reference-এর সাথে 2026 সালের অক্টোবরে মিলিয়ে দেখা হয়েছে।
| Field | Type | নোট |
|---|---|---|
model | string | বাধ্যতামূলক। catalog-এর একটা id। আপনার key-র list দেখতে GET /v1/models চালান। |
prompt | string or array | OpenAI-র format-এ বাধ্যতামূলক। একটা string, বা string-এর array। token id-র array-ও এই format-এ চলে। |
max_tokens | integer | তৈরি হওয়া token-এর ওপরের সীমা। এটা দিয়ে দিন, কারণ জানতে নিচে reservation-এর কথাটা দেখুন। |
temperature, top_p | number | Sampling। OpenAI যেমন বলে, একটাই বদলান, দুটো একসাথে নয়। |
n | integer | প্রতি prompt-এ কয়টা completion চান। gateway 1 থেকে 4 পর্যন্ত নেয়, নইলে 400 invalid_request দেয়। |
stop | string or array | OpenAI-র format-এ সর্বোচ্চ 4টা stop sequence। |
stream | boolean | true দিলে Server-Sent Events আসে। |
stream_options.include_usage | boolean | stream: true-র সাথে দিলে শেষে usage-সহ একটা বাড়তি chunk আসে। |
suffix, echo, logprobs, best_of | various | OpenAI-র format-এ এগুলো আছে। model এগুলো মানবে কি না, সেটা তার provider-এর ওপর। |
seed, presence_penalty, frequency_penalty, logit_bias, user | various | যেমন পাঠানো হয় তেমনই provider-এর কাছে যায়। |
Parameter নির্ভর করে upstream model-এর ওপর
model আর n ছাড়া বাকি field gateway যাচাইও করে না, বদলায়ও না। এগুলো সরাসরি model-এর provider-এর কাছে যায়, আর provider কোনো field উপেক্ষা করতে পারে বা পুরো request ফিরিয়ে দিতে পারে। যেমন OpenAI-র নিজের docs-এ suffix শুধু একটা model-এর সাথে চলে। catalog-এ model-এর পেজ দেখুন, আর নিজে চালিয়ে পরীক্ষা করুন।
request body 10 MB পর্যন্ত হতে পারে। এর চেয়ে বড় হলে 413 request_entity_too_large আসে।
Response-এর উদাহরণ#
id আর সংখ্যাগুলো বোঝানোর জন্য দেওয়া।
{
"id": "cmpl-a1b2c3",
"object": "text_completion",
"created": 1790000000,
"model": "deepseek/deepseek-v4.1-flash",
"choices": [
{
"index": 0,
"text": " The server is rate limiting you; wait and retry.",
"finish_reason": "stop",
"logprobs": null
}
],
"usage": { "prompt_tokens": 12, "completion_tokens": 11, "total_tokens": 23 }
}তৈরি হওয়া text থাকে choices[].text-এ, chat completions-এর মতো choices[].message.content-এ নয়। model নিজে থেমে গেলে বা stop sequence-এ পৌঁছালে finish_reason হয় stop, আর max_tokens-এ ঠেকে গেলে length। body আসে provider থেকে, তাই system_fingerprint-এর মতো বাড়তি field model ভেদে আলাদা হতে পারে।
Streaming#
"stream": true দিলে response আসে Server-Sent Events হিসেবে। প্রতিটা event-এ choices[].text-এর একটা অংশ থাকে, আর stream শেষ হয় data: [DONE] দিয়ে:
data: {"id":"cmpl-a1b2c3","object":"text_completion","choices":[{"index":0,"text":" The server","finish_reason":null}]}
data: {"id":"cmpl-a1b2c3","object":"text_completion","choices":[{"index":0,"text":" is rate limiting you.","finish_reason":"stop"}]}
data: [DONE]billing-এর জন্য gateway provider-কে বলে, stream করা completion-এর শেষে যেন একটা usage chunk পাঠায়। এই chunk-এর choices array ফাঁকা থাকে আর থাকে একটা usage object, তাই আপনার stream parser যেন এটা সামলাতে পারে। disconnect, timeout আর proxy buffering streaming পেজে যেভাবে লেখা আছে সেভাবেই চলে।
Billing আর সীমা#
- হিসাব। provider-এর জানানো
prompt_tokensআরcompletion_tokensধরে, model-এর input ও output price-এ বিল হয়। provider usage না পাঠালে gateway request আর response-এর size দেখে আন্দাজ করে নেয়। - Reservation। forward করার আগে gateway request-এর সবচেয়ে খারাপ ক্ষেত্রের খরচ ধরে রাখে, আর output-এর দিকে হিসাব করে
max_tokensদিয়ে। এটা না দিলে reservation ধরে নেয় 8,192 output token, যদিও provider-এর নিজের default অনেক কম হতে পারে। তাই কোনো key-র monthly spend cap প্রায় শেষ থাকলে বা ব্যালান্স প্রায় শূন্য হলে,max_tokens-ছাড়া request ফিরে যেতে পারে, অথচ ছোটmax_tokens-সহ request ঠিকই চলে যায়। আপনার চাওয়াmax_tokensব্যালান্সে না কুলালে gateway সেটা কমিয়ে ব্যালান্সে যতটা কুলায় ততটা করে দিতে পারে। চার্জ হয় আসল usage-এর, reservation-এর নয়। - Rate limit। অন্য inference request-এর মতো completions request-ও আপনার per-minute limit আর concurrency-তে গোনা হয়। rate limits পেজ দেখুন।
- Fail করা request-এর বিল হয় না। provider 400 বা তার ওপরের status দিলে সেটা কোনো চার্জ ছাড়াই ফেরত আসে।
কোন model চলে#
gateway call-টা যেমন আছে তেমনই পাঠায়। completions request-কে chat request-এ বদলায় না, আর model সাধারণ completion পারে কি না তাও যাচাই করে না। কী ফিরে আসবে, সেটা model-এর provider-এর ওপর নির্ভর করে:
| Response | সম্ভাব্য কারণ |
|---|---|
| 200 with text | provider এই model-এর জন্য /completions চালায়। |
400 invalid_request | provider request ফিরিয়ে দিয়েছে, যেমন model শুধু chat-এর জন্য, বা কোনো field অনুমোদিত নয়। |
404 model_not_found | এই model-এর জন্য provider-এর কাছে completions route নেই। catalog-এ নেই এমন id দিলেও এটাই আসে। |
400 endpoint_not_supported_for_model | model-টা শুধু এমন provider-এর মাধ্যমে চলে যে Anthropic Messages protocol বোঝে। কিছুই পাঠানো হয়নি। |
502 upstream_unreachable | model-এর কয়েকটা provider আছে, আর প্রতিটাই fail করেছে বা request ফিরিয়ে দিয়েছে। |
upstream-এর message বদলে একটা সাধারণ message বসানো হয়, তাই কোনো failure Support-কে দেখাতে চাইলে x-tokens-request-id header-টা রেখে দিন। পুরো তালিকা errors পেজে।
Chat completions-এ চলে যাওয়া#
completions call fail করলে, বা নতুন code লিখলে, একই request chat completion হিসেবে পাঠাতে শুধু আকারটা বদলাতে হয়:
# Before: /v1/completions
resp = client.completions.create(model=model, prompt="A one-line definition of HTTP 429:", max_tokens=40)
text = resp.choices[0].text
# After: /v1/chat/completions
resp = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": "A one-line definition of HTTP 429:"}],
max_tokens=40,
)
text = resp.choices[0].message.contentcompletions model একটা text-এর জের টানে, আর chat model প্রশ্ন বা নির্দেশের উত্তর দেয়। তাই যে prompt জের টানার ওপর ভর করে ছিল সেটা নতুন করে লিখুন (যেমন "The three causes are:" হয়ে যাবে "List the three causes.")। যে feature শুধু completions-এ আছে, যেমন suffix আর echo, chat-এ তার সমতুল্য কিছু নেই।
আরও পড়ুন#
- Chat completions: নতুন কাজের জন্য যে endpoint ব্যবহার করবেন।
- Responses আর Messages: বাকি দুটো inference endpoint-এর জন্য।
- Token counting: prompt-এর size আন্দাজ করতে আর
usageপড়তে।