Chat Completions
POST /v1/chat/completions — پارامترها، شکل پاسخ و stream.
https://iranrouter.com/v1/chat/completionsمسیر اصلی. سازگار با OpenAI، پس شکل درخواست و پاسخ همان است که SDKها انتظار دارند.
پارامترها
| نام | نوع | توضیح |
|---|---|---|
model | string | الزامی. شناسهٔ مدل یا نام مستعار؛ یا @preset/شناسه؛ یا iranrouter/auto:cheap | balanced | best (پایینتر). |
models | array | مدلهای جایگزین. اگر model نتواند جواب دهد و هنوز چیزی فرستاده نشده باشد، بعدی امتحان میشود؛ هر مدل درخواست خودش است با هزینهٔ خودش. زنجیره رویهمرفته حداکثر سه مدل است، خودِ model هم حساب میشود؛ بقیه نادیده گرفته میشوند. هدر X-IranRouter-Model-Used و فیلد model در پاسخ میگویند کدام جواب داد؛ هدر X-IranRouter-Models-Tried مدلهایی را که کنار رفتند با کد خطایشان فهرست میکند (slug:code) و در آخر مدلی را که این پاسخ از آن است — اگر همه شکست خوردند، آخرین مدل امتحانشده که خطایش همین پاسخ است. در صفحهٔ مصرف کل زنجیره یک درخواست است؛ مدلهای ردشده زیر آن باز میشوند و در آمار خطا شمرده نمیشوند. |
messages | array | الزامی. پیامها با نقش system / user / assistant / tool. |
max_tokens | int | سقف توکن خروجی. روی مبلغ رزروشده اثر مستقیم دارد — واقعبینانه ببندید. |
max_completion_tokens | int | معادل max_tokens برای کلاینتهای جدیدتر؛ هر دو خوانده میشوند. |
stream | bool | پاسخ جریانی SSE. |
temperature | number | تصادفیبودن خروجی. |
top_p | number | نمونهبرداری هستهای. |
tools | array | تعریف ابزارها. schema آنها هم توکن ورودی حساب میشود. |
tool_choice | string|object | اجبار یا آزادگذاشتن انتخاب ابزار. |
response_format | object | خروجی ساختاریافته / JSON. |
stop | string|array | دنبالههای توقف. |
seed | int | برای تکرارپذیری، اگر مدل پشتیبانی کند. |
مسیریاب خودکار (iranrouter/auto)
سه شناسهٔ ثابت: iranrouter/auto:cheap، iranrouter/auto:balanced و iranrouter/auto:best (iranrouter/auto بدون tier همان balanced است). هر کدام زنجیرهای از حداکثر سه مدل است که ما نگه میداریم و بهمرور بهروز میکنیم؛ درخواست شما مثل یک زنجیرهٔ models اجرا میشود: مدل اول، و اگر نتوانست جواب دهد یا کلید، پلن یا guardrail شما اجازهٔ آن مدل را نداشت، بعدی. هزینه، همیشه قیمت مدلی است که جواب داد و در X-IranRouter-Model-Used، فیلد model پاسخ و صفحهٔ مصرف نامش میآید؛ برای خود tier قیمتی وجود ندارد. tierها در GET /v1/models فهرست میشوند، بدون قیمت. tierای که فعلاً مدلی ندارد ۴۰۴ model_not_found میگیرد. اگر مدل خودتان را جلوی tier بگذارید (model خودتان و tier در models)، سقف سه مدل جای دو مدلِ tier را میگذارد و رد شدنِ مدل خودتان همچنان ۴۰۳ است. در یک حلقهٔ ابزار، مدلی که نوبت اول را جواب داد نوبتهای بعد را هم میگیرد. اگر میخواهید خودتان مدلها را انتخاب کنید، از models یا یک preset استفاده کنید.
Idempotency-Key
روی درخواست غیرجریانی، یک هدر Idempotency-Key (تا ۲۰۰ کاراکتر) تلاش دوباره را از حافظه پاسخ میدهد و هرگز دوبار شارژ نمیکند. پاسخ بازپخششده هدر x-idempotent-replay: true دارد. اگر درخواست اصلی هنوز در حال اجرا باشد ۴۰۹ با کد idempotency_in_flight میگیرید، و اگر پاسخ اصلی برای ذخیره خیلی بزرگ بوده باشد ۴۰۹ با کد idempotency_completed_unreplayable. روی stream نادیده گرفته میشود.
گفتگو و برنامه (session_id، X-Title)
یک session_id در بدنه، یا هدر x-session-id (تا ۲۵۶ کاراکتر)، نوبتهای یک گفتگو را یکی میکند: روی یک مسیر میمانند تا کش پرامپت گرم بماند و هزینهٔ پیشوند تکراری کم شود، و در گزارش مصرف با همان شناسه پیدا میشوند. اگر نفرستید، بهترتیب prompt_cache_key، سپس user (یا metadata.user_id)، و در نهایت اثرانگشتی از شروع گفتگو بهکار میرود؛ هدر پاسخ X-IranRouter-Session میگوید کدام. session_id و prompt_cache_key همانطور که فرستادهاید ذخیره میشوند تا نشست خودتان را پیدا کنید — دادهٔ شخصی در آنها نگذارید؛ user و اثرانگشت فقط بهصورت hash کلیددار ذخیره میشوند. مقدار هیچکدام از این فیلدها به بالادست نمیرود؛ بالادست فقط یک کلید مبهم میبیند که بین مشتریها مشترک نیست.
هدرهای X-Title و HTTP-Referer برنامهٔ شما را نامگذاری میکنند تا مصرف را به تفکیک برنامه ببینید. از Referer فقط origin نگه داشته میشود.
ترجیح مسیر (provider)
یک object به نام provider در بدنه ترتیب یا محدودیت مسیرهای بالادستی را تعیین میکند. این قابلیت به پلن بستگی دارد: بدون آن، فیلد بیصدا نادیده گرفته میشود و پاسخ هدر X-IranRouter-Provider-Prefs را با توضیح دارد؛ با آن، مقدار نامعتبر ۴۰۰ با کد invalid_provider_prefs میگیرد. فیلد هرگز به بالادست فرستاده نمیشود.
پاسخ
{
"id": "chatcmpl-...",
"object": "chat.completion",
"created": 1767000000,
"model": "openai/gpt-4o-mini",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "..." },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 24,
"completion_tokens": 108,
"total_tokens": 132,
"prompt_tokens_details": { "cached_tokens": 0 },
"completion_tokens_details": { "reasoning_tokens": 0 },
"cost_rial": 1840
}
}فیلد usage.cost_rial مبلغ نهایی همین درخواست به ریال است. شمارشهای جزئی هم با نامهای خود OpenAI میآیند — prompt_tokens_details.cached_tokens (و cache_write_tokens، audio_tokens، image_tokens وقتی هست) و completion_tokens_details.reasoning_tokens (و audio_tokens، image_tokens) — و هم با نامهای تخت ما: cached_input_tokens، cache_write_tokens، reasoning_tokens و مانند آن. در stream همین object روی آخرین chunk میآید.
پاسخ غیرجریانی tool_calls, logprobs, refusal و n>1 را کامل برمیگرداند.
نمونهٔ کامل
curl https://iranrouter.com/v1/chat/completions \ -H "Authorization: Bearer ir-..." \ -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-4o-mini", "messages": [ {"role": "system", "content": "You answer in Persian."}, {"role": "user", "content": "پایتخت ایران کجاست؟"} ], "max_tokens": 200, "temperature": 0.4 }'
پلاگینها و transform
دو فیلد اختیاری، با همان نامهایی که کلاینتهای OpenRouter میفرستند. هر دو را خودِ ما اجرا میکنیم؛ نام ناشناخته ۴۰۰ میگیرد تا پلاگینی که کاری نمیکند با پلاگین خراب اشتباه نشود.
| فیلد | چه میکند |
|---|---|
transforms: ["middle-out"] | اگر گفتگو در پنجرهٔ context مدل جا نشود، پیامها از وسط حذف میشوند تا جا شود: system prompt و آخرین نوبت همیشه میمانند؛ اولین پیام کاربر هم میماند و اگر خودش جا نشود از وسطِ متنش کوتاه میشود. یک tool call هیچوقت از نتیجهاش جدا نمیشود و چیزی که فرستاده میشود همیشه با نوبت کاربر شروع میشود. هدر X-IranRouter-Transform میگوید چند پیام حذف شد. بدون این فیلد، درخواستی که متنش حتی با خوشبینانهترین شمارش در پنجره جا نمیشود، پیش از هر رزرو ۴۰۰ context_length_exceeded میگیرد؛ در زنجیرهٔ models مدل بعدی امتحان میشود. |
plugins: [{"id": "response-healing"}] | فقط پاسخ غیر-stream (و دورهای یک حلقهٔ ابزار، که همیشه غیر-streamاند) و فقط وقتی response_format از نوع json_object یا json_schema است. حصار ```json، متن اضافهٔ دور JSON و ویرگول آخر برداشته میشود. پاسخی که max_tokens وسطش بریده تا آخرین عنصرِ کامل عقب میرود و بسته میشود: مقدار نیمهکاره هرگز نگه داشته یا حدس زده نمیشود، و finish_reason همان length میماند. با schema تطبیق داده نمیشود. چیزی که نشود صادقانه ترمیمش کرد، همانطور که هست برمیگردد. رایگان است. |
plugins: [{"id": "file-parser"}] | هر PDF داخل گفتگو (تا ۴ فایل؛ چه با file_id چه data URI) پیش از رسیدن به مدل با OCR به متن markdown تبدیل میشود. مدل OCR را اپراتور انتخاب میکند و از فهرست مدلهای مجاز کلید و پلن شما مستثناست. کل درخواست یکبار در RPM شمرده میشود، نه یکبار برای هر PDF؛ ولی هر PDF قیمت صفحهای و سطر مصرف خودش را دارد. ردهای قطعی (مدل غیرمجاز، سقف RPM) پیش از OCR بررسی میشوند و چیزی خرج نمیکنند؛ ولی اگر نوبت chat بعد از OCR رد شود — متن سند از پنجرهٔ مدل بزرگتر است، یا کیف پول یا بودجه برای خود chat کافی نیست — هزینهٔ OCR گرفته شده است. پلن رایگان سقف روزانهٔ صفحه دارد (به وقت تهران): بعد از آن ۴۲۹ با کد file_parser_daily_pages و Retry-After تا نیمهشب. guardrail محتوایی سازمان روی متن سند هم اعمال میشود. با pdf.engine برابر native فایل دستنخورده به مدل میرسد. |