نخستین فراخوانی شما
یک نشانی پایه (base URL) و یک کلید. هر چیز دیگری در این صفحه اختیاری است.
درگاه با HTTP API شرکت OpenAI کار میکند. یک کلاینت موجود با تغییر دو خط به آن وصل میشود: نشانی پایه و کلید. هیچ چیز دیگری در کد شما تغییر نمیکند، و شکل پاسخ همان است که SDK شما از قبل پردازش میکند.
curl -s https://gateway.vatan.one/v1/chat/completions \
-H "authorization: Bearer $VATAN_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "anthropic/claude-sonnet-5",
"messages": [{ "role": "user", "content": "Say hello" }]
}'در کنسول: یک کلید بسازید
احراز هویت
یک کلید حامل (bearer)، و بودجه، محدودیت نرخ و فهرست نشانیهای مجازی که با خود دارد.
هر درخواست به `authorization: Bearer <key>` نیاز دارد. کلید بهصورت sha256 ذخیره میشود و هیچ راهی برای بازگرداندن مقدار آن نیست، بنابراین کلیدی که گم کردهاید جایگزین میشود، نه بازیابی.
کلید فقط یک اعتبارنامه نیست. بودجهای که اجازهی خرجکردنش را دارد، سقف نرخ درخواست خودش و در صورت نیاز فهرستی از نشانیهایی که میتوان از آنها با آن کار کرد را همراه دارد. اینها چیزهایی هستند که پیش از آنکه هیچ مدلی درخواست را ببیند، آن را رد میکنند.
یک فضای کاری میتواند کلیدهای زیادی داشته باشد، هر کدام با بودجهی خودش، تا یک اپ نتواند سهم اپ دیگر را خرج کند.
| همراه کلید | کاری که انجام میدهد |
|---|
| بودجه | سقفی به دلار، برای کل عمر کلید یا برای هر ماه تقویمی. پس از گذشتن از آن، کلید رد میشود و بقیهی فضای کاری به کار ادامه میدهد. |
|---|
| سقف نرخ درخواست | درخواستها و توکنها در دقیقه، برای هر کلید. درخواستهای ناگهانی و انبوه با 429 رد میشوند، نه اینکه در صف بمانند. |
|---|
| فهرست نشانیهای مجاز | بازههای CIDR که کلید میتواند از آنها استفاده شود. خالی یعنی از هر جا. |
|---|
| تیم | کدام افراد در فضای کاری میتوانند آن را ببینند و از آن هزینه کنند. |
|---|
در کنسول: کلیدها
نقاط پایانی
آنچه درگاه ارائه میکند، و ساختاری که هر کدام با آن کار میکند.
نه نقطهی پایانی ترافیک زنده میپذیرند؛ تکمیل گفتوگو (chat completions) را میتوان بهصورت دستهای هم اجرا کرد. دو نقطهی پایانی دیگر امکان میدهند کلاینتهای ارائهدهندگان دیگر بدون تغییر کار کنند.
| نقطهی پایانی | چیست |
|---|
| POST /v1/chat/completions | تکمیلها، با استریم یا بدون آن، همراه با ابزارها. نقطهی پایانیای که بیشتر فراخوانیکنندگان استفاده میکنند و پیشفرض برای یک دسته. |
|---|
| POST /v1/embeddings | بردار برای متن. یک رشته یا آرایهای از رشتهها میگیرد. |
|---|
| POST /v1/decisions | یک انتخاب نوعدار: بله یا نه، یکی از یک مجموعه، یا یک امتیاز. |
|---|
| POST /v1/images/generations | تصویرها. بسته به مدل، یک URL یا base64 برمیگرداند. |
|---|
| POST /v1/audio/speech | تبدیل متن به گفتار. بایتهای صوتی برمیگرداند. |
|---|
| POST /v1/audio/transcriptions | تبدیل گفتار به متن، بهصورت multipart، فایلها تا 25 MB. |
|---|
| WSS /v1/realtime | گفتوگوی صوتی زنده از طریق WebSocket، با openai/gpt-realtime یا openai/gpt-realtime-mini. بخش «صدای بیدرنگ» در پایین را ببینید. |
|---|
| POST /v1/videos | یک کار ساخت ویدیو را آغاز میکند. وضعیت را با GET /v1/videos/{id} بررسی کنید، سپس بایتها را از GET /v1/videos/{id}/content بگیرید. |
|---|
| POST /v1/3d | یک کار سهبعدی را شروع میکند. با GET /v1/3d/{id} وضعیت را بپرسید، سپس فایل مدل را با GET /v1/3d/{id}/content?format=glb بگیرید. |
|---|
| POST /v1/training | روی یک مجموعهداده آموزش میدهد. نخست dry_run را بفرستید تا قیمت دقیق را بگیرید، سپس max_usd را دستکم برابر آن بفرستید. وضعیت را با GET /v1/training/{id} بپرسید و فایل آموزشدیده را با GET /v1/training/{id}/content بگیرید. |
|---|
| POST /v1/messages | قالب خود Anthropic، برای کلاینتی که با آن کار میکند. همچنین /v1/messages/count_tokens. |
|---|
| POST /v1/responses | Responses API شرکت OpenAI. Codex به همین نیاز دارد و هیچ جایگزینی ندارد. |
|---|
| POST /v1beta/models/{model}:generateContent | قالب خود گوگل، برای کلاینتی که به آن صحبت میکند. همچنین :streamGenerateContent و :countTokens و :batchEmbedContents و :predictLongRunning و :batchGenerateContent و /upload/v1beta/files. |
|---|
| GET /v1/models | کاتالوگ، در قالب OpenAI یا، برای کلاینت Anthropic، در قالب Anthropic. `attachments` فهرست چیزهایی است که مدلهای چت علاوه بر متن میخوانند؛ `attachments_unknown` مواردی که تأیید نشدهاند. قیمتها بهازای هر توکن هستند، در pricing.input_usd_per_token و pricing.output_usd_per_token. |
|---|
در کنسول: مرور کاتالوگ
صدای بیدرنگ
گفتوگوی صوتی زنده با مدلهای بیدرنگ OpenAI از طریق WebSocket، برای همهی فضاهای کاری فعال است.
با `wss://` به `/v1/realtime?model=openai/gpt-realtime-mini` وصل شوید و کلیدتان را بهصورت توکن Bearer بفرستید، یا از مرورگر در زیرپروتکل `openai-insecure-api-key.<key>`.
رویدادها بدون تغییر رد میشوند، پس SDKهای بیدرنگ OpenAI با عوض کردن نشانی پایه کار میکنند.
هزینهٔ هر پاسخ وقتی تمام شد کسر میشود. پیش از آن، هزینهٔ حدود پنج دقیقه استفاده از موجودی کنار گذاشته میشود و اگر نشود، نشست بسته میشود.
هر نشست حداکثر 30 دقیقه است و هر کلید حداکثر 5 نشست دارد.
برای داشتن گفتههای تماسگیرنده بهصورت متن، `audio.input.transcription` را در `session.update` تنظیم کنید و یکی از `openai/gpt-4o-mini-transcribe` (پیشفرض)، `openai/gpt-4o-transcribe`، `openai/gpt-transcribe` یا `openai/whisper-1` را نام ببرید.
هر رونوشت جداگانه حساب میشود: روی gpt-4o-mini-transcribe برای هر توکن ورودی $0.0000013125 و برای هر توکن خروجی $0.00000525، روی gpt-4o-transcribe دو برابر آن، و برای هر ثانیه روی gpt-transcribe $0.00007875 و روی whisper-1 $0.000105.
بهروزرسانی درگاه نشستها را با کد 1012 میبندد. دوباره وصل شوید: فقط پاسخهای تمامشده هزینه دارند.
| قیمت هر توکن | gpt-realtime and gpt-realtime-mini |
|---|
| صدای ورودی، کششده | $0.0000336 و $0.0000105؛ کششده $0.00000042 و $0.000000315. |
|---|
| صدای خروجی | $0.0000672 و $0.000021. |
|---|
| متن ورودی، کششده | $0.0000042 و $0.00000063؛ کششده $0.00000042 و $0.000000063. |
|---|
| متن خروجی | $0.0000168 و $0.00000252. |
|---|
| تصویر ورودی | $0.00000525 و $0.00000084. |
|---|
باز کردن یک نشست، پایتون
from openai import باز کردنهوش مصنوعی client = باز کردنهوش مصنوعی(api_key=VATAN_API_KEY, base_url="https://gateway.vatan.one/v1")
with client.realtime.connect(model="openai/gpt-realtime-mini") as conn:
conn.session.update(session={"type": "realtime", "output_modalities": ["audio"]})
conn.response.create()
for event in conn:
if event.type == "response.done":
breakکلاینتهایی که بدون تغییر کار میکنند
آنچه یک تغییر دوخطی به شما میدهد، و تنها کلاینتی که به یک نقطهی پایانی خاص نیاز دارد.
SDKهای OpenAI، SDKهای Anthropic، SDK گوگل GenAI، Claude Code، Codex و n8n همگی فقط با یک نشانی پایه و یک کلید با این درگاه کار میکنند. Codex تنها موردی است که الزام سخت دارد: فقط `/v1/responses` را پشتیبانی میکند و هیچ چیز دیگری را.
OpenAI SDK، TypeScript
const client = new باز کردنهوش مصنوعی({
baseURL: 'https://gateway.vatan.one/v1',
apiKey: process.env.VATAN_API_KEY,
})Anthropic SDK، یا Claude Code
export ANTHROPIC_BASE_URL="https://gateway.vatan.one"
export ANTHROPIC_AUTH_TOKEN="$VATAN_API_KEY"
در کنسول: برنامهتان را متصل کنید
SDK گوگل GenAI
`google-genai` از این دروازه چه کارهایی میتواند انجام دهد و چه کارهایی نمیتواند.
تنها تغییر، آدرس پایه است، چون SDK کلید را از پیش در `x-goog-api-key` میفرستد. تکمیل متن، استریم، گفتوگو، فراخوانی ابزار، خروجی ساختیافته، تصویر در هر دو جهت، امبدینگ، فایلها، دستهها و ویدیو همگی کار میکنند.
دستهها همان قواعد هر دستهی دیگری اینجا را دارند. شناسهی مدل باید به `:batch` ختم شود.
هر فراخوانی از این در، دقیقاً مثل همان درخواست از `/v1/chat/completions` اندازهگیری میشود و از بودجه کم میشود. این یک ترجمه است، نه خط لولهی دوم.
هرچه این در نتواند ترجمه کند با نامش رد میشود و هرگز خاموشانه حذف نمیشود. متن رد میگوید بهجایش از چه استفاده کنید.
| ارائه نشد | به جای آن از چه چیزی استفاده کنید |
|---|
| کش کردن زمینه (cachedContents) | کش خود وطن، در بخش دروازه، کش. کش گوگل متعلق به همان پروژهای است که ساختهاش، و همهی فضاهای کاری اینجا یک پروژه را مشترکاً دارند. |
|---|
| تنظیم دقیق مدل (tunedModels) | مدلهای منتشرشده، فهرستشده در GET /v1beta/models. |
|---|
| توکنهای موقت (auth_tokens) | یک کلید با بودجه و محدودیت نرخ خودش. اینها برای Live API هستند که به اتصال بیدرنگ نیاز دارد. |
|---|
| انبارهای جستوجوی فایل | دانش وطن، روی /v1/knowledge در کنترلپلین. |
|---|
| ایجنتها، محیطها، اعتبارنامهها، تریگرها | ایجنتها و وبهوکهای خود وطن، که از کنسول اجرا میشوند. |
|---|
| حذف یک مدل یا یک دسته | ۴۰۵. دسته نگه داشته میشود تا ردیف مصرفش همچنان خوانده شود. |
|---|
| topK | `topP`. ارائهدهندههای پشت این درگاه top_p میگیرند نه top_k. |
|---|
| Logprobs روی مدلهای Gemini | هیچ. `responseLogprobs` و `logprobs` را بردارید. |
|---|
| speechConfig و audioTimestamp | نقطههای پایانی صوت: /v1/audio/speech و /v1/audio/transcriptions. |
|---|
| mediaResolution و routingConfig | مسیریابی از آنِ وطن است. نام مدلی را که میخواهید بگویید، یا از یک مسیر استفاده کنید. |
|---|
google-genai، پایتون
import os
from google import genai
client = genai.Client(
api_key=os.environ["VATAN_API_KEY"],
http_options={"base_url": "https://gateway.vatan.one"},
)google-genai، نامگذاری، نگهداشتن و سپس حذف
from google.genai import types
short = genai.Client(
api_key=os.environ["VATAN_API_KEY"],
http_options={
"base_url": "https://gateway.vatan.one",
"headers": {"x-vatan-expires-after": "3600"},
},
)
short.files.upload(
file="batch.jsonl",
config=types.UploadFileConfig(display_name="nightly-2026-09-27", mime_type="application/jsonl"),
)
files = list(client.files.list(config=types.ListFilesConfig(page_size=100)))
for f in files:
if f.display_name.startswith("nightly-"):
client.files.delete(name=f.name)در کنسول: برنامهتان را متصل کنید
خروجی ساختارمند
گرفتن JSONی که با شِمایی که خودتان نوشتهاید بخواند، از هر دو در.
روی سیم OpenAI این `response_format` است، با `json_schema` یا `json_object`. همهی ارائهدهندهها اینجا رعایتش میکنند، و هرجا چنین فیلدی نداشته باشند شبیهسازی میشود.
Google دو فیلد شِما دارد و یکی نیستند. `responseJsonSchema` کل JSON Schema را میگیرد. `responseSchema` زیرمجموعهی کوچکترِ OpenAPI را میگیرد.
خروجی `model_json_schema()` در Pydantic کل JSON Schema است، پس در `responseJsonSchema` میرود. مدلهای تودرتو کار میکنند: `$defs` و `$ref` همانطور که نوشتهاید میمانند.
فرستادن هر دو رد میشود، و شِما در کنار `responseMimeType`ی که با آن در تضاد باشد هم رد میشود. اینها جایگزین یکدیگرند و وطن بهجای شما انتخاب نمیکند.
| فیلد | آنچه لازم است |
|---|
| responseJsonSchema | کل JSON Schema، همراه با $defs و $ref. همان چیزی که model_json_schema() در Pydantic میدهد. |
|---|
| responseSchema | زیرمجموعهی OpenAPI متعلق به Google. همراه با responseJsonSchema رد میشود. |
|---|
| responseMimeType | application/json یا text/plain. اگر با شِمایی که فرستادهاید در تضاد باشد رد میشود. |
|---|
| response_format | املای سیم OpenAI، با json_schema یا json_object. روی همهی ارائهدهندهها سرو میشود. |
|---|
google-genai، یک مدل تودرتوی Pydantic
from pydantic import BaseModel
class نشانی(BaseModel):
street: str
city: str
class CompanyInfo(BaseModel):
name: str
address: نشانی tags: list[str]
answer = client.models.generate_content(
model="google/gemini-3.5-flash",
contents="Acme Ltd, 1 High Street, London. Tags: retail, uk.",
config={
"max_output_tokens": 2000,
"response_mime_type": "application/json",
"response_json_schema": CompanyInfo.model_json_schema(),
},
)
print(CompanyInfo.model_validate_json(answer.text))اندیشیدن
اینکه از یک مدل استدلالی بخواهید چقدر بیندیشد، و ببینید چه هزینهای داشت.
مدلهای Gemini بهطور پیشفرض میاندیشند و شما میتوانید اندازهاش را تعیین کنید. یک بودجه به توکن بفرستید، یا سطحی مانند «LOW». نه هر دو. فیلدها در پایین آمدهاند.
اندیشیدن با `max_output_tokens` کراندار میشود، پس کرانی که میگذارید کل پاسخ را با اندیشهها محدود میکند. همین است که هزینهی یک دسته را قابل بررسی میکند.
توکنهای اندیشه بهعنوان خروجی محاسبه میشوند، در همهی ارائهدهندهها. یک مدل استدلالی میتواند بسیار بیشتر از پاسخی که میخوانید، صرف اندیشیدن کند.
در درِ Google این دو شمارش جدا هستند و مجموع، جمعشان است. روی سیم OpenAI اندیشیدن درون `completion_tokens` مینشیند، چه جریانی بگیرید چه نه.
همان سیم، این تنظیمها را در `vatan_google` میبرد که فقط مدلهای Google میپذیرندش. هر مدل دیگری بهجای نادیدهگرفتن این فیلد، درخواست را رد میکند.
| فیلد | کاری که انجام میدهد |
|---|
| thinkingBudget | یک عدد صحیح از توکنها. صفر اندیشیدن را خاموش میکند. همراه با thinkingLevel رد میشود. |
|---|
| thinkingLevel | واژهای مانند LOW یا HIGH که بدون تغییر به Google میرود. همراه با thinkingBudget رد میشود. |
|---|
| includeThoughts | استدلال را در بخشی جدا با نشان `thought` برمیگرداند. بخش پاسخ دستنخورده میماند. |
|---|
| vatan_google | همان سه مورد روی سیم OpenAI، با نامهای thinking_budget و thinking_level و include_thoughts. |
|---|
| thoughtsTokenCount | توکنهای اندیشیدن در درِ Google. با نرخ خروجی محاسبه میشوند. |
|---|
| completion_tokens_details.reasoning_tokens | همان عدد روی سیم OpenAI، شمردهشده درون completion_tokens. |
|---|
google-genai، یک سطح و اندیشهها
answer = client.models.generate_content(
model="google/gemini-3.5-flash",
contents="Which is heavier, a kilo of steel or a kilo of feathers?",
config={
"max_output_tokens": 2000,
"thinking_config": {"thinking_level": "LOW", "include_thoughts": True},
},
)
for part in answer.candidates[0].content.parts:
print("thought" if part.thought else "answer", part.text)
print(answer.usage_metadata.thoughts_token_count, "tokens of thinking")همان درخواست روی سیم OpenAI
curl -s https://gateway.vatan.one/v1/chat/completions \
-H "authorization: Bearer $VATAN_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "google/gemini-3.5-flash",
"messages": [{ "role": "user", "content": "Which is heavier?" }],
"max_tokens": 2000,
"vatan_google": { "thinking_level": "LOW" }
}'مسیرها و جایگزینها
نردبانی از مدلها زیر یک نام، تا قطعی یک ارائهدهنده به جای خطا فقط پاسخی کندتر باشد.
مسیر یک نام و یک فهرست مرتب از مدلهاست. نام مسیر را جایی بفرستید که شناسهی مدل قرار میگیرد، و درگاه مدلها را به ترتیب امتحان میکند تا یکی پاسخ دهد. پاسخ نشان میدهد کدام مدل پاسخ داد و کدامها امتحان شدند.
برای استفاده از مسیر، لازم نیست چیزی در کد شما تغییر کند: نام مسیر در فیلد `model` قرار میگیرد.
یا `model: "auto"` را بفرستید تا درگاه برای هر درخواست از میان مجموعهی کوچکی از مدلهای بررسیشده انتخاب کند. بهطور پیشفرض یک مدل سریع پاسخ میدهد. مدل قویتر به کار واقعی، استدلال، ابزارهای متعدد یا زمینهی طولانی پاسخ میدهد. هزینهی مدلی را میپردازید که پاسخ داده است، با قیمت خود آن.
گزینهی «خودکار» فقط برای چت است. همهی نقاط پایانی دیگر با 400 و `auto_chat_only` پاسخ میدهند. برای اینکه در طول یک کار یک مدل ثابت بماند، شناسهی `x-vatan-model` را در فراخوانیهای بعدی بفرستید. `auto` نمیتواند نام مسیر باشد.
curl -s https://gateway.vatan.one/v1/chat/completions \
-H "authorization: Bearer $VATAN_API_KEY" \
-H "content-type: application/json" \
-d '{"model": "cheap-summariser", "messages": [{"role":"user","content":"..."}]}'
درخواستmodel: "cheap-summariser"نام مسیر، جایی که شناسهی مدل قرار میگیرد اولبدون پاسخgoogle/gemini-3.1-flash بعدیاین یکی پاسخ میدهدanthropic/claude-haiku-4.5 پاسخ میگویدکدام مسیر، چه چیزهایی امتحان شد، کدام پاسخ دادx-vatan-route, x-vatan-route-tried, x-vatan-model یا model: "auto"بهطور پیشفرض یک مدل سریعمدلی قویتر برای کار، استدلال، ابزارهای زیاد یا زمینهی طولانی؛ فقط برای چت Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
در کنسول: مسیرها
پرامپتهای ذخیرهشده
پرامپتی که اینجا نگه داشته میشود و با نامش به آن ارجاع داده میشود، پس تغییر آن به معنای استقرار دوباره نیست.
بهجای پیامهایی که قرار بود در ابتدا بیایند، `prompt: "name"` یا `prompt: "name@3"` را بفرستید. هر نسخه پس از نوشته شدن تغییرناپذیر است، بنابراین ارجاعی که به نسخهی مشخصی سنجاق شده نمیتواند زیر پای یک یکپارچهسازی در حال اجرا تغییر کند؛ نام بدون نسخه از آخرین نسخه پیروی میکند.
curl -s https://gateway.vatan.one/v1/chat/completions \
-H "authorization: Bearer $VATAN_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "anthropic/claude-sonnet-5",
"prompt": "summarise@3",
"messages": [{ "role": "user", "content": "The text to summarise" }]
}'در کنسول: پرامپتها
کش
پرسشی یکسان که از پاسخ قبلی پاسخ داده میشود، و پرسشی تقریباً یکسان اگر آن را بخواهید.
خاموش است مگر اینکه فضای کاری آن را روشن کند. کش دقیق برای درخواستی که بایت به بایت یکسان باشد پاسخ ذخیرهشده را برمیگرداند. کش معنایی برای درخواستی که به اندازهی کافی نزدیک باشد پاسخی برمیگرداند، و پاسخ نشان میدهد چقدر نزدیک بوده است.
یک درخواست تکی میتواند با `x-vatan-cache: no-store` از کش خارج شود؛ این راه گریز برای همان یک فراخوانی است که باید تازه باشد.
کش فضای کاری، خاموش مگر اینکه روشنش کنید دقیقبایت به بایتهمان درخواست، دوباره معناییبه اندازهی کافی نزدیکپاسخ میگوید چقدر نزدیک تطابقپاسخ ذخیرهشدهبدون هزینه بدون تطابقمدل پاسخ میدهد انصراف یک درخواستx-vatan-cache: no-storeبرای فراخوانیای که باید تازه باشد Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
در کنسول: کش
سقف روزانه برای هر یک از کاربران شما
یک کلید به همهٔ کاربران شما خدمت میدهد، و یکی از آنها نمیتواند سهم بقیه را خرج کند.
`user` را در بدنه بفرستید: شناسهٔ خودتان برای آن شخص، همانطور که API اوپنایآی دارد. فقط حرف، رقم و `_ . : | -`، دستبالا 64 نویسه. نام یا نشانی ایمیل نفرستید. چیزی که شناسه نباشد مثل قبل به ارائهدهنده داده میشود و سنجیده نمیشود.
همراهش `x-vatan-user-daily-limit-usd: 0.50` را بفرستید. وقتی آن کاربر امروز به اندازهٔ سقف خرج کرده باشد، درخواست با 429 رد میشود و `error.type` آن `user_limit_exhausted` است. `spent_usd`، `limit_usd` و `resets_at` را همراه دارد. روز، روز UTC است.
سقف با هر درخواست میآید، پس کاربر رایگان و کاربر پولی میتوانند سقفهای متفاوت داشته باشند. درخواست بدون این سرآیند سقف کاربری ندارد. سرآیند بدون `user` قابلاستفاده یک 400 است، نه درخواستی که بدون بررسی پاسخ داده شود.
روی گردشکار هم یکسان کار میکند و همهٔ فراخوانیهای مدلِ آن اجرا شمرده میشود. درخواستهایی که هنوز در جریاناند شمرده نشدهاند، پس ممکن است کاربر کمی از سقف بگذرد. `GET /v1/usage/users/{user}` میگوید امروز چقدر خرج کرده است.
curl -s https://gateway.vatan.one/v1/chat/completions \
-H "authorization: Bearer $VATAN_API_KEY" \
-H "content-type: application/json" \
-H "x-vatan-user-daily-limit-usd: 0.50" \
-d '{
"model": "anthropic/claude-sonnet-5",
"user": "u_18273",
"messages": [{ "role": "user", "content": "Say hello" }]
}'
curl -s https://gateway.vatan.one/v1/usage/users/u_18273 \
-H "authorization: Bearer $VATAN_API_KEY"در کنسول: مصرف
دستهها
فهرستی از درخواستها که ما اجرا میکنیم، بدون اتصالی که باز نگه دارید و بدون حلقهای از خودتان که باید درست پیادهاش کنید.
فقط شناسهی مدلی که به `:batch` ختم شود میتواند در دسته اجرا شود، با قیمت دستهای خود ارائهدهنده. هر شناسهی دیگری هنگام ساختن دسته رد میشود.
درخواستها را تا سقف 25 MB در بدنه بفرستید، یا بهصورت فایل (در ادامه).
یک دسته (batch) یک مدل را روی یک نقطهی پایانی اجرا میکند و هزینهاش به حساب کلیدی نوشته میشود که آن را ساخته است. درخواستی که `max_tokens` ندارد با بیشینهی خروجی خود مدل اجرا میشود، به اندازهی جایی که پرامپت آن باقی میگذارد.
هر شناسهی `:batch` فقط متن میپذیرد. درخواستی که تصویر، صدا یا فایل همراه داشته باشد، هنگام ساخت دسته رد میشود.
بدترین حالت با موجودی و بودجههای شما سنجیده میشود و تا زمان کسر هزینه نگه داشته میشود. دستهای که به دلیل پول رد شود هرگز ارسال نمیشود.
پس از توقف، وضعیت `cancelling` است تا ارائهدهنده دسته را پایان دهد. فقط هزینهی درخواستهای تمامشده محاسبه میشود. Google ممکن است باز هم آن را تمام کند و هزینهی کامل را محاسبه کند. OpenRouter نمیتواند دسته را متوقف کند.
برای اینکه از پایان یک دسته باخبر شوید، یک وبهوک را برای `batch.finished` ثبت کنید.
| نقطهی پایانی | حداکثر در هر دسته |
|---|
| /v1/chat/completions | 10,000 درخواست |
|---|
curl -s https://gateway.vatan.one/v1/batches \
-H "authorization: Bearer $VATAN_API_KEY" \
-H "content-type: application/json" \
-d '{"model": "openrouter/openai/gpt-5.6-luna:batch", "requests": [
{"messages": [{"role": "user", "content": "Classify this"}], "max_tokens": 200}
]}'
curl -s https://gateway.vatan.one/v1/batches/$BATCH_ID -H "authorization: Bearer $VATAN_API_KEY"
curl -s "https://gateway.vatan.one/v1/batches?limit=50" -H "authorization: Bearer $VATAN_API_KEY"
curl -s -X POST https://gateway.vatan.one/v1/batches/$BATCH_ID/cancel -H "authorization: Bearer $VATAN_API_KEY"
curl -s https://gateway.vatan.one/v1/batches/$BATCH_ID/items/0/content -H "authorization: Bearer $VATAN_API_KEY" -o item-0.jsonدر کنسول: دستهها
دسته از روی فایل
یک فایل از درخواستها بارگذاری کنید، آن را بهصورت دسته اجرا کنید و پاسخها را بهصورت فایل دانلود کنید.
SDKهای OpenAI با این نشانی پایه و یک کلید Vatan بدون تغییر کار میکنند.
فایل یا JSONL است، هر خط یک درخواست، یا یک آرایهی JSON از درخواستها. نخستین نویسهی آن تعیین میکند، هرگز نامش.
هر درخواست یا قالب OpenAI (`custom_id`، `method`، `url`، `body`) است یا خودِ بدنه، که `custom_id` آن جایگاهش است و شمارش از 0 شروع میشود.
با `POST /files` بارگذاری کنید، سپس با `POST /batches` و `input_file_id` دسته را بسازید. درخواست نادرست پیش از ارسال هر چیزی با `line` یا در آرایه با `position` رد میشود.
وقتی `status` به پایان رسید، `output_file_id` و `error_file_id` را با `GET /files/{id}/content` دانلود کنید. اگر چیزی ناموفق نبوده باشد، فایل خطا خالی است.
دانلودها JSONL هستند که SDKها آن را میخوانند. `?format=json` یک آرایهی JSON میدهد؛ `?format=jsonl` آرایهی بارگذاریشده را به خطها تبدیل میکند.
`DELETE /files/{id}` فایل ورودی را حذف میکند. فایلهای خروجی و خطا بخشی از دستهاند و باقی میمانند.
`completion_window` باید "24h" باشد. مهلتی که در پاسخ نشان داده میشود مهلت خود مدل است و ممکن است طولانیتر باشد.
فایلی که از درِ Google بارگذاری شود بهجایش شکل Gemini دارد: `key` و `request`، با `contents` و `generation_config`. نام مدل یکبار روی خودِ کار میآید.
سطری به شکل Gemini که `max_output_tokens` ندارد، با بیشینهی خروجی خود مدل اجرا میشود، به اندازهی جایی که پرامپت آن باقی میگذارد.
بارگذاری ردشده یکسره دور ریخته میشود. چیزی ذخیره و چیزی محاسبه نمیشود، پس خطی را که متن رد نام میبرد درست کنید و فایل را دوباره بفرستید.
| محدودیت | مقدار |
|---|
| یک فایل | تا 2,000 MB، و 100,000 خط |
|---|
| یک ردیف هزینه | تا 5 MB |
|---|
| یک دسته | درخواستها تا حجم 25 MB، از فایل یا از فهرست |
|---|
| یک دستهی Google از یک فایل | تا 180 MB و 20,000 درخواست، با یک قالب خروجی در هر دسته |
|---|
| /v1/chat/completions | تا 10,000 درخواست در یک دسته |
|---|
| مدت نگهداری | 30 روز، مگر اینکه expires_after را کمتر تعیین کنید یا فایل را حذف کنید |
|---|
| برای هر فضای کاری | 25 گیگابایت و 1,000 فایل، و 500 بارگذاری در ساعت |
|---|
requests.jsonl، هر خط یک درخواست
{"custom_id": "review-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "openrouter/openai/gpt-5.6-luna:batch", "messages": [{"role": "user", "content": "Classify: great product"}], "max_tokens": 200}}
{"model": "openrouter/openai/gpt-5.6-luna:batch", "messages": [{"role": "user", "content": "Classify: arrived broken"}], "max_tokens": 200}requests.json، همان دو درخواست بهصورت یک آرایه
[
{"custom_id": "review-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "openrouter/openai/gpt-5.6-luna:batch", "messages": [{"role": "user", "content": "Classify: great product"}], "max_tokens": 200}},
{"model": "openrouter/openai/gpt-5.6-luna:batch", "messages": [{"role": "user", "content": "Classify: arrived broken"}], "max_tokens": 200}
]requests.jsonl، شکل google-genai
{"key": "acme", "request": {"system_instruction": {"parts": [{"text": "Extract the company."}]}, "contents": [{"role": "user", "parts": [{"text": "Acme Ltd, 1 High Street, London."}]}], "generation_config": {"max_output_tokens": 2000, "response_mime_type": "application/json", "response_json_schema": {"type": "object", "properties": {"name": {"type": "string"}}, "required": ["name"]}, "thinking_config": {"thinking_level": "LOW"}}}}Python
import os، ساعت from openai import باز کردنهوش مصنوعی client = باز کردنهوش مصنوعی(base_url="https://gateway.vatan.one/v1", api_key=os.environ["VATAN_API_KEY"])
upload = client.files.create(file=open("requests.jsonl", "rb"), purpose="batch")
batch = client.batches.create(
input_file_id=upload.id,
endpoint="/v1/chat/completions",
completion_window="24h",
)
while batch.status not in ("completed", "failed", "expired", "cancelled"):
time.sleep(30)
batch = client.batches.retrieve(batch.id)
if batch.output_file_id:
open("output.jsonl", "w").write(client.files.content(batch.output_file_id).text)
if batch.error_file_id:
open("errors.jsonl", "w").write(client.files.content(batch.error_file_id).text)
client.files.delete(upload.id)TypeScript
import fs from 'node:fs'
import باز کردنهوش مصنوعی from 'openai'
const client = new باز کردنهوش مصنوعی({ baseURL: 'https://gateway.vatan.one/v1', apiKey: process.env.VATAN_API_KEY })
const upload = await client.files.create({ file: fs.createReadStream('requests.jsonl'), purpose: 'batch' })
let batch = await client.batches.create({
input_file_id: upload.id,
endpoint: '/v1/chat/completions',
completion_window: '24h',
})
while (!['completed', 'failed', 'expired', 'cancelled'].includes(batch.status)) {
await new قول((r) => setTimeout(r, 30_000))
batch = await client.batches.retrieve(batch.id)
}
if (batch.output_file_id) {
fs.writeFileSync('output.jsonl', await (await client.files.content(batch.output_file_id)).text())
}
if (batch.error_file_id) {
fs.writeFileSync('errors.jsonl', await (await client.files.content(batch.error_file_id)).text())
}
await client.files.delete(upload.id)همین کار با curl
curl -s https://gateway.vatan.one/v1/files -H "authorization: Bearer $VATAN_API_KEY" \
-F purpose=batch -F file=@requests.jsonl
curl -s https://gateway.vatan.one/v1/batches -H "authorization: Bearer $VATAN_API_KEY" \
-H "content-type: application/json" \
-d '{"input_file_id": "file-7d0c1f7e-...", "endpoint": "/v1/chat/completions", "completion_window": "24h"}'
curl -s https://gateway.vatan.one/v1/files/$OUTPUT_FILE_ID/content -H "authorization: Bearer $VATAN_API_KEY" -o output.jsonl
curl -s "https://gateway.vatan.one/v1/files/$OUTPUT_FILE_ID/content?format=json" -H "authorization: Bearer $VATAN_API_KEY" -o output.json
curl -s -X DELETE https://gateway.vatan.one/v1/files/file-7d0c1f7e-... -H "authorization: Bearer $VATAN_API_KEY"در کنسول: دستهها
وضعیتهای دسته
آنچه `status` در هر مرحله میگوید، با همان واژههایی که SDKهای OpenAI انتظار دارند.
`legacy_status` واژهی قدیمیتر را نگه میدارد: queued، running، done، failed یا cancelled.
| status | معنای آن |
|---|
| validating | پذیرفته شده یا در حال ارسال. هنوز هزینهای گرفته نشده است. |
|---|
| in_progress | نزد ارائهدهنده. |
|---|
| finalizing | در حال جمعآوری پاسخها و محاسبهی هزینه. |
|---|
| completed | هر درخواست پاسخ داد یا ناموفق بود. فایلها آمادهاند. |
|---|
| failed | بهطور کامل پایان یافت. `errors` دلیلش را میگوید. |
|---|
| expired | مهلت تمام شد. فقط هزینهی درخواستهای تمامشده گرفته میشود. |
|---|
| cancelling | درخواست توقف داده شده، هنوز پایان نیافته. |
|---|
| cancelled | متوقف شد. هزینهی درخواستهای تمامشده محاسبه میشود. |
|---|
validatingپذیرفته شده یا در حال ارسال؛ هنوز هزینهای گرفته نشده in_progressنزد ارائهدهنده finalizingدر حال جمعآوری پاسخها و هزینه completedهمهی درخواستها پاسخ گرفته یا شکست خوردهاند؛ فایلها آمادهاند failedبهطور کامل پایان یافته؛ errors دلیلش را میگوید expiredمهلت تمام شد؛ فقط درخواستهای تمامشده هزینه دارند cancellingتوقف درخواست شده، هنوز پایان نیافته cancelledمتوقف شد؛ درخواستهای تمامشده هزینه دارند legacy_status واژهی قدیمیتر را نگه میدارد: queued، running، done، failed یا cancelled.
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
در کنسول: دستهها
دلایل رد دسته
هر دلیل ردی که ساختن یک دسته ممکن است با آن پاسخ دهد، با همان عبارتی که به کار میبرد.
رد پیش از آنکه کاری در صف قرار گیرد میرسد و هزینهای گرفته نمیشود.
ردِ مربوط به یک درخواست، جایگاه آن را نام میبرد و در فایل JSONL شمارهی `line` آن را هم.
| کد | معنای آن |
|---|
| input_missing | Send either a درخواست array or an input_file_id. |
|---|
| input_mixed | Send a درخواست array or an input_file_id, not both. |
|---|
| model_required | model is required with a درخواست array. A batch runs one model. |
|---|
| invalid_request | {param} cannot be "{value}". See the docs for GET /v1/batches. |
|---|
| endpoint_not_batchable | "{endpoint}" cannot run as a batch. The batch endpoints are listed in the docs under Limits. |
|---|
| endpoint_not_discounted | {model} runs at the batch price only on {endpoints}. Use {base} to run this endpoint at the live price. |
|---|
| model_not_batch | {model} cannot be used in a batch. Only model ids ending :batch can. |
|---|
| model_not_batchable | {model} cannot run at a batch price. Use {base} to run this batch at the live price. |
|---|
| model_mismatch | درخواست {n} names {line_model}, and this batch runs {model}. A batch runs one model. |
|---|
| url_mismatch | درخواست {n} is for {url}, and this batch runs {endpoint}. A batch runs one endpoint. |
|---|
| method_invalid | درخواست {n} has method {method}. A batch request is always POST. |
|---|
| too_many_requests_in_batch | A batch against {endpoint} holds at most {max} درخواست. This one has {count}. Split it. |
|---|
| item_too_large | درخواست {n} is {size} MB. One request can be at most 5 MB. Send large media as an https link. |
|---|
| batch_too_large | This batch is {size} MB, and a list batch can be at most {max} MB. Split it into smaller batches. Or: This request is over 26 MB, and the درخواست list can be at most 25 MB. Split it into smaller batches. |
|---|
| custom_id_invalid | درخواست {n} has a custom_id Vatan cannot use. Use 1 to 64 letters, digits, underscores, dashes, dots or colons. |
|---|
| custom_id_duplicate | custom_id "{id}" appears at درخواست {a} and {b}. Each custom_id must be unique in a batch. |
|---|
| output_bound_required | درخواست {n} has no max_tokens, and Vatan does not know the most {model} can write. Set max_tokens, so the worst-case cost can be checked first. Or: Request {n} is about {tokens} prompt tokens, which leaves under {floor} tokens of the {window}-token window on {model} for an answer. Shorten it, or set max_tokens. Or: Request {n} sets {field} to something other than a whole number above 0. Set a positive whole number. |
|---|
| stream_not_allowed | درخواست {n} sets stream. A batch cannot stream. Remove it and read the result from the batch. |
|---|
| n_not_allowed | درخواست {n} asks for {k} answers. A batch request returns one. Send the request more than once instead. |
|---|
| field_not_allowed | درخواست {n} sets {field}, which {provider} cannot take in a batch. {reason} Remove it. Or: Request {n} sets a thinking budget of 0, and {model} cannot switch thinking off. Set a budget above 0 or a thinking level, or remove the budget. Or: This batch sets service_tier, which a batch cannot take. The batch price is the tier, and it is chosen by the :batch model id. Remove it. |
|---|
| hosted_tool_not_allowed | درخواست {n} uses {tool}. The provider charges per use, so the cost cannot be checked first. Remove it, or send this request live. |
|---|
| provider_reference_not_allowed | درخواست {n} points at a provider file or cache by id. Those are shared across Vatan's customers. Send the content as base64 or an https link. |
|---|
| media_not_supported | درخواست {n} carries {kind}, and {model} takes text only in a batch. |
|---|
| output_format_mixed | درخواست {n} asks for {format}, and request {first} asks for {first_format}. {model} takes one output format per batch. Send one batch per format. Or: Request {n} has a different JSON schema from request {first}, and the order of its properties counts. {model} takes one schema per batch. Send one batch per schema. |
|---|
| too_many_parts | This file would run as {parts} separate batches, and one batch is cut into at most {max}. Each output format and schema runs separately. Use fewer formats, or split the file. |
|---|
| reasoning_unbounded | درخواست {n} does not bound reasoning. On {model}, max_tokens does not limit reasoning. Set reasoning_effort, so the worst case can be checked. |
|---|
| prompt_too_long_for_batch | درخواست {n} is about {tokens} prompt tokens. {model} charges more above {threshold}, so a batch takes at most {limit}. Send it live. |
|---|
| completion_window_invalid | completion_window must be "24h". The batch still runs to the model's own window, which is {window}. |
|---|
| metadata_invalid | metadata takes up to 16 keys. Keys can be 64 characters and values 512. |
|---|
| key_required | keyId is required. A batch runs as one of your keys and bills to it. |
|---|
| insufficient_credit | This batch could cost up to {ceiling} and your available balance is {balance}, so it is {short} short and was not created. Nothing was charged. The estimate is a worst case: it assumes every request uses its full output allowance, so the real charge is usually lower. Top up at least {short}, send fewer درخواست, or set a lower max_tokens. |
|---|
| group_budget_exhausted | This batch could cost up to {ceiling} and {team} has {left} left of its budget of {budget}, so it is {over} over and was not created. Nothing was charged. What is left already excludes money set aside for درخواست still running. An owner, or anyone with Manage people, can raise the team's budget by more than {over}. Or move this key out of the team, or send a smaller batch. |
|---|
| budget_exhausted | This batch could cost up to {ceiling} and this key has {left} left of its budget of {budget}, so it is {over} over and was not created. Nothing was charged. What is left already excludes money set aside for درخواست still running. An owner, or anyone with Manage keys, can raise this key's budget by more than {over}. Or use another key, or send a smaller batch. |
|---|
| provider_not_configured | {model} is not available on this deployment right now. Try again later, or send the درخواست live with {base}. |
|---|
| no_such_key | That key does not exist on this account, or it is revoked. |
|---|
| no_such_file | No file with that id exists in this workspace. |
|---|
| file_not_batch_input | {file} is a batch output file. Create a batch from a file you uploaded with purpose batch. |
|---|
| admission_unavailable | Your balance and budgets could not be checked just now, so the batch was not created. Nothing was charged. Try again shortly. |
|---|
| file_purpose_invalid | purpose must be "batch". Vatan stores files for batches only. |
|---|
| file_expires_after_invalid | expires_after must use anchor "created_at" and between 3600 and 2592000 seconds. |
|---|
| file_missing | Send the file as a multipart field named file. |
|---|
| file_empty | This file has no درخواست in it. Nothing was stored. |
|---|
| file_too_large | This file is over 2000 MB. Split it into smaller files, one per batch. |
|---|
| file_not_jsonl | Line {n} is not a JSON object. Each line must be one request, as JSON. Nothing was stored, so send the whole file again once that line is fixed. |
|---|
| file_line_too_large | خط {n} is {size} MB. One line can be at most 5 MB. Nothing was stored, so send the whole file again once that line is fixed. Or: Request {n} is {size} MB. One request can be at most 5 MB. Nothing was stored, so send the whole file again once it is fixed. |
|---|
| file_too_many_lines | This file has {count} lines. A file holds at most 100,000 درخواست. Nothing was stored, so split it and upload again. Or: This file has {count} requests. A file holds at most 100,000 requests. Nothing was stored, so split it and upload again. |
|---|
| file_request_not_object | درخواست {n} is not a JSON object. Each element of the array must be one request. Nothing was stored, so send the whole file again once it is fixed. |
|---|
| file_not_json_array | This JSON array ends before its closing ]. Upload the whole file again. Or: This file has more after the closing ] of its JSON array. Remove it and upload again. Or: This JSON array has a comma or bracket out of place at request {n}. Fix it and upload again. |
|---|
| file_not_utf8 | This file is not UTF-8 text, from byte {offset}. Save it as UTF-8 and upload it again. |
|---|
| file_storage_full | This workspace stores {used} of its 25 GB of files. Delete files you no longer need, then upload again. Or: This workspace has {files} of 1,000 files, the most it can keep. The limit is the number of files, not their size. Delete a file you no longer need to free a slot, then upload again. Or: This workspace has {files} of 1,000 files and stores {used} of its 25 GB, so both limits are reached. Delete files you no longer need, then upload again. |
|---|
| file_upload_rate_limited | This workspace has uploaded 500 files in the last hour. Try again after {time}. |
|---|
| file_storage_unavailable | File storage is not available right now. Nothing was stored. Send the درخواست as a list, or try again later. |
|---|
| no_such_batch | No batch with that id exists in this workspace. |
|---|
| cannot_cancel | This batch will finish and be charged. It is already with {provider}, which offers no way to stop a batch once it has it. Or: این دسته همین حالا در حال ارسال به ارائهدهنده است. یک دقیقهی دیگر، پس از رسیدن آن، دوباره تلاش کنید. |
|---|
| already_finished | This batch is already {status}, so there is nothing left to stop. |
|---|
| results_not_ready | This batch is still {status}. Its results are ready when it finishes. |
|---|
| no_such_result | No stored file at position {n} of that batch. Files a batch produces are kept for 7 days after it finishes. |
|---|
| file_not_deletable | Output files are part of the batch record, so they cannot be deleted on their own. |
|---|
| missing_api_key | Send your API key in the authorization header, as Bearer followed by the key. |
|---|
| invalid_api_key | This API key does not exist or was revoked. Use a live key from the console. |
|---|
| file_service_unreachable | Files could not be reached just now. Try again shortly. After a failed upload, list your files first, in case it arrived. |
|---|
در کنسول: دستهها
گردشکارها
گردشکاری که در کنسول رسم کردهاید، از درون محصول خودتان و با همان کلید فراخوانی میشود.
دو راه ورود، هر دو روی همین میزبان. بهعنوان مدل: `model: "workflow/<slug>"` را به `/chat/completions` بفرستید. آخرین پیام کاربر پرسش است و نوبتهای پیش از آن تاریخچه؛ پیام سیستمی نادیده گرفته میشود، چون آنچه به گردشکار گفته میشود روی بوم آن کشیده شده است. پاسخ بهصورت یک پاسخ تکمیل گفتوگو (chat completion) با دو فیلد اضافه برمیگردد: `citations`، یعنی اسنادی که پشت آن هستند، و `workflow_run`، یعنی شناسهی آن و هزینهاش.
بهصورت اجرا: `POST /workflows/{slug-or-id}/runs` با `{"input", "history", "wait"}`. با `wait: true` پاسخ تا پایان اجرا، حداکثر تا سقف زمانی خود گردشکار، منتظر میماند و `output`، `citations`، `spentUsd` و `id` اجرا را برمیگرداند. بدون آن، کد 202 و شناسه را دریافت میکنید و `GET /workflows/runs/{id}` آن را میخواند. اجرایی که تا پایان زمان انتظار تمام نشده باشد هم با 202 پاسخ میدهد.
کلیدی که فراخوانی میکند همان کلیدی است که هزینه را میپردازد. فهرست IPهای مجاز، بودجه و سقف نرخ درخواست آن مانند هر درخواست دیگری اعمال میشوند، و هر فراخوانی مدل درون اجرا روی همان کلید اندازهگیری میشود. اجراها در بخش کارها با نام کلید فهرست میشوند.
با `stream: true` تکهها از شکل تکمیل گفتوگو (chat completion) پیروی میکنند، اما کل پاسخ پس از پایان اجرا در یک تکه میرسد و تا آن زمان هر پانزده ثانیه یک توضیح برای زنده نگه داشتن اتصال (keep-alive) فرستاده میشود. استریم توکنبهتوکن یک گردشکار هنوز ارائه نمیشود.
هر اجرا میتواند فایل همراه داشته باشد: پیام صوتی، ویدیو، عکس، PDF یا فایل Word. در حالت اجرا، `files` را اضافه کنید: فهرستی از `{"name", "type", "data"}` با فایل بهصورت base64 یا data URL، یا `{"url"}` برای فایلی که وطن خودش دریافت میکند. در حالت مدل، بخشهای `image_url`، `input_audio` یا `file` را در آخرین پیام کاربر بگذارید. تا 10 فایل و 25 MB در هر اجرا. گردشکار آنها را با بلوکهای «تبدیل گفتار به متن»، «تماشای یک ویدیو» و «خواندن سند» میخواند، و هر فایل با پایان اجرا پاک میشود.
فراخوانی API درون یک گردشکار، اعتبارنامههایش را در هدری میفرستد که بهصورت `{{secrets.NAME}}` نوشته میشود. مقدار را یک بار در تنظیمات گردشکار تعیین میکنید؛ این مقدار رمزنگاری میشود، دیگر هرگز نمایش داده نمیشود و هرگز در مراحل یک اجرا نوشته نمیشود، حتی وقتی طرف مقابل آن را بازتاب دهد.
curl -s https://gateway.vatan.one/v1/workflows/ask-gazar-dev/runs \
-H "authorization: Bearer $VATAN_API_KEY" \
-H "content-type: application/json" \
-d '{"input": "How would you design a URL shortener?", "wait": true}'
import باز کردنهوش مصنوعی from 'openai'
const client = new باز کردنهوش مصنوعی({ baseURL: 'https://gateway.vatan.one/v1', apiKey: process.env.VATAN_API_KEY })
const answer = await client.chat.completions.create({
model: 'workflow/ask-gazar-dev',
messages: [{ role: 'user', content: 'How would you design a URL shortener?' }],
})
console.log(answer.choices[0].message.content)کلید شماکلیدی که فراخوانی میکند، هزینه را میپردازدفهرست IPهای مجاز، بودجه و سقف نرخ درخواست آن اعمال میشود بهصورت مدلPOST /chat/completionsmodel: "workflow/<slug>" بهصورت اجراشروع یک اجراPOST /workflows/{slug-or-id}/runs گردشکارهمانطور که در کنسول کشیده شده اجرا میشود پاسخ بهصورتیک تکمیل گفتوگو (chat completion)همراه با citations و workflow_run wait: trueoutput, citations, spentUsd, id 202 و شناسهبا GET /workflows/runs/{id} خوانده میشود Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
در کنسول: گردشکارها
محافظهای گردش کار
آنچه یک گردش کار در ورود و خروج بررسی میکند.
آنها را در تنظیمات گردش کار، بخش محافظها، تنظیم کنید. اولی و آخری همیشه اعمال میشوند؛ بقیه در ابتدا خاموشاند.
| محافظ | کاری که انجام میدهد |
|---|
| طولانیترین پیام | پیام بلندتر به ویجت یا کانال، پیش از اجرای هر مرحلهای رد میشود. |
|---|
| بررسی دور زدن دستورالعمل | یک مدل تصمیمگیری اول هر پیام را میسنجد. اگر به اندازه کافی مطمئن باشد، پیام رد فرستاده میشود. |
|---|
| رمزها و کلیدها | مقدار رمزها و متنهای شبیه کلید حذف میشوند. نقل دستورالعملهای خودش رد میشود. |
|---|
| پیوندهای مجاز | پیوند به سایتهای دیگر حذف میشود، یا پاسخ رد میشود. |
|---|
| طولانیترین پاسخ | پاسخ بلندتر در مرز یک واژه کوتاه میشود. |
|---|
| پاسخهای خراب | پاسخ خراب یا تکراری رد میشود. |
|---|
| سقف مقدار | هر مقداری که به یک API یا ابزار فرستاده میشود کوتاه میشود. |
|---|
| سرآیندهای ایمیل | متن بازدیدکننده هرگز فرستنده، گیرنده یا موضوع را پر نمیکند. |
|---|
اگر پذیرفته شودمراحل گردشکار آنچه مراحل به بیرون میفرستند «طولانیترین پیام» و «سرآیندهای ایمیل» همیشه اعمال میشوند. بقیه در ابتدا خاموشاند؛ آنها را در تنظیمات گردشکار، زیر «محافظها» تنظیم کنید.
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
در کنسول: گردشکارها
خطاها
ساختار، و اینکه هر وضعیت در اینجا واقعاً چه معنایی دارد.
رد درخواست بهصورت JSON با یک شیء `error` برمیگردد که یک `message` و یک `type` دارد، یعنی همان شکلی که کلاینت OpenAI از قبل مدیریت میکند. هر رد اندازهگیری میشود و در صفحهی مصرف شما دیده میشود: یک یکپارچهسازی که کاملاً خراب است نباید شبیه یکپارچهسازی بیکار به نظر برسد.
| وضعیت | معنای آن در اینجا |
|---|
| 400 | خود درخواست. مدلی که وجود ندارد، مسیری که هیچ مدل قابلارائهای روی آن نیست، یا بدنهای که نقطهی پایانی نمیپذیرد. پیام، نام فیلد مربوط را ذکر میکند. |
|---|
| 400 auto | auto_chat_only: مقدار auto به نقطهی پایانیای غیر از چت فرستاده شده است. auto_unservable: هیچ مدلی که Auto مجاز به انتخابش است نمیتواند این درخواست را انجام دهد. |
|---|
| 401 | کلید. وجود ندارد، نامعتبر است، ابطال شده یا منقضی شده است. نوع: authentication_error. |
|---|
| 402 | پول. موجودی تمام شده، یا بودجهی یک کلید یا تیم تمام شده است. خطا بدون تغییر از همان بررسیای که آن را ایجاد کرده به شما میرسد. |
|---|
| 404 | چیزی که در مسیر نشانی نام برده شده، برای این فضای کاری وجود ندارد. |
|---|
| 429 | سقف نرخ درخواست، مال شما یا مال ارائهدهنده. نوع rate_limit_error. |
|---|
| 502 / 503 | ارائهدهنده، یا مدلی که این استقرار هیچ اعتبارنامهای برای آن ندارد. |
|---|
| 504 | ارائهدهنده بیش از حد طول کشید و از درخواست صرفنظر شد. |
|---|
در کنسول: درخواستها
هزینهها
قیمت چگونه تعیین میشود، و چه چیزی جلوی یک حلقهی مهارنشده را میگیرد.
هر درخواست بهازای هر توکن و با نرخ کاتالوگ برای آن مدل محاسبه میشود.
سه چیز هزینه را محدود میکنند و پیش از ارسال درخواست بررسی میشوند: موجودی فضای کاری، بودجهی کلید و بودجهی تیم. هر کدام از آنها میتواند با 402 درخواست را رد کند و بقیهی فضای کاری به کار خود ادامه میدهد.
هر سه تأیید شوندبه ارائهدهنده فرستاده میشود 402، اگر یکی تمام شده باشدردشدهبقیهی فضای کاری به کار ادامه میدهد محاسبه بهازای هر توکنبا نرخ کاتالوگ برای آن مدل Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
در کنسول: مصرف و هزینه
وبهوکها
به شما خبر داده میشود، بدون نیاز به پرسوجوی مکرر، برای معدود رویدادهایی که ارزش خبر دادن دارند.
فضای کاری یک نشانی و رویدادهایی را که میخواهد ثبت میکند. ارسالها امضا میشوند و هر تلاش ثبت میشود، بنابراین نقطهی پایانیای که خطا میدهد دیده میشود و بیصدا نمیماند.
رویدادهای گفتگو شناسهها را میبرند و متن پیام را فقط وقتی که وبهوک آن را بخواهد.
در کنسول: وبهوکها
کانالها
ربات خودتان در تلگرام، بله، Slack، Microsoft Teams، واتساپ، اینستاگرام یا مسنجر، که یک گردشکار یا عامل به آن پاسخ میدهد. برای هر حساب جداگانه روشن میشود.
هر کانال رباتی را که مال شماست به فضای کاریتان وصل میکند. گردشکار یا عاملی که انتخاب میکنید به هر پیام پاسخ میدهد.
بهطور پیشفرض فقط به اعضا پاسخ میدهد. هر نفر حسابش را با یک کد یکبارمصرف پیوند میدهد و کلیدی را انتخاب میکند که هزینهی پرسشهایش از آن کم شود.
کانال تلگرام، بله، واتساپ، اینستاگرام یا مسنجر میتواند بهجای آن به همه پاسخ دهد، با هزینه از یک کلیدی که انتخاب میکنید. اسلک و تیمز فقط به اعضا پاسخ میدهند.
ربات عمومی سقف هزینهی روزانه از ۰٫۰۱ تا ۱٬۰۰۰ دلار و سقف روزانه برای هر نفر دارد که پیشفرض آن ۳۰ است. با رسیدن به هر کدام، یک بار به فرستنده گفته میشود.
پیامهای بلندتر از ۴٬۰۹۶ نویسه پذیرفته نمیشوند. فقط ربات عمومی تلگرام در گروهها پاسخ میدهد، با سقف روزانه برای هر گروه.
در واتساپ، اینستاگرام و مسنجر، Meta پاسخ را فقط تا 24 ساعت پس از آخرین پیام آن فرد مجاز میداند. به پیامهایی که دیرتر برسند پاسخ داده نمیشود.
کانال هزینهی جداگانه، هزینهی هر کاربر یا اشتراک ندارد: فقط توکنهای مدلی را میپردازید که هر پاسخ مصرف میکند.
قیمتهای خود Meta روی حساب Meta شما اعمال میشود. Meta برای هر پاسخ واتساپی که میرساند هزینه میگیرد، و یک پاسخ بلند ممکن است چند پیام باشد.
اینستاگرام و مسنجر فقط پس از App Review در Meta به افراد بیرون از تیم شما میرسند.
| برنامه | آنچه شما فراهم میکنید |
|---|
| تلگرام | توکن ربات از @BotFather. |
|---|
| بله | توکن ربات از @botfather در بله. |
|---|
| Slack | توکن ربات و Signing secret. نشانی وطن را بهعنوان Request URL بچسبانید. |
|---|
| Microsoft Teams | App ID و password یک Azure Bot. نشانی وطن را بهعنوان Messaging endpoint آن بچسبانید. |
|---|
| WhatsApp | اپ Meta خودتان و شمارهای مخصوص همین کار، در یک کسبوکار تأییدشده با روش پرداخت: یک access token، شناسهی شماره تلفن و app secret. |
|---|
| اینستاگرام | اپ Meta خودتان و یک حساب حرفهای: توکن Unified login، شناسهی حساب و app secret. |
|---|
| مسنجر | اپ Meta خودتان و یک صفحهی فیسبوک: توکن دسترسی صفحه، شناسهی صفحه و app secret. |
|---|
در کنسول: کانالها
MCP وطن
به یک دستیار برنامهنویسی اجازه دهید با سه ابزار در فضای کاری شما کار کند. فقط یکبار در مرورگر وارد میشوید.
MCP وطن یک سرور MCP راهدور در https://mcp.vatan.one/mcp است. با Claude Code، Codex، Cursor و اتصالهای Claude.ai کار میکند.
برای اتصال، سرور را اضافه کنید. کلاینت شما مرورگر را باز میکند. در وطن وارد شوید یا همانجا حساب بسازید. انتخاب کنید چه چیزی مجاز باشد و تمام. کلیدی برای کپی کردن نیست.
سه ابزار دارد. `search` عملیات کل API وطن را پیدا میکند و میگوید هر کدام چه مجوزی لازم دارد. `execute` یک قطعه کوتاه JavaScript را در یک محیط جدا روی کلاینت `vatan` اجرا میکند: vatan.get، vatan.post، vatan.put، vatan.patch، vatan.delete و vatan.request. `access` میگوید کلید شما چه کارهایی میتواند بکند.
هنگام اجازه دادن به برنامه دامنهها را انتخاب میکنید: خواندن، نوشتن، هزینه و مخرب. خواندن و نوشتن پیشفرضاند. هزینه و مخرب را باید خودتان فعال کنید.
برنامه بهجای شما کار میکند. هر درخواست از مجوزهای امروز شما استفاده میکند، محدود به دامنههایی که اجازه دادید. اگر دسترسی شما برداشته شود، برنامه هم آن را از دست میدهد.
درخواستهای مخرب و هزینهدار به `confirm: true` نیاز دارند. با `dryRun` فهرست درخواستهایی که اجرا میشد را بدون اجرا ببینید.
محدودیت هر اجرا: حدود ۲۰ ثانیه و ۵۰ فراخوانی API.
هرگز نمیتواند کلید دیگری با همان قدرت بسازد، وارد شود، گذرواژه یا نشستها را تغییر دهد، روش پرداخت را عوض کند، اعتبار شارژ کند، حساب را حذف کند یا به مسیرهای اپراتور برسد. این کارها فقط در کنسول انجام میشوند.
فراخوانیهای MCP رایگان است. هر چیزی که به درگاه مدل برسد، طبق معمول محاسبه میشود.
دسترسی تا ۳۰ روز خودش تمدید میشود. پس از ۳۰ روز استفادهنکردن، پس از قطع اتصال، یا برای فضای کاری دیگر دوباره وارد شوید.
برای متوقف کردن یک برنامه، در کنسول بخش کلیدهای MCP را باز کنید و آن را زیر «برنامههای متصل» قطع کنید. فوراً متوقف میشود.
یک خطر میماند. کلاینتی که به دسترسی شما و یک ابزار وب دسترسی دارد را میتوان قانع کرد که دادههای فضای کاری را به صفحهای که خوانده بفرستد. در محیطهای نامطمئن فقط دامنه خواندن را بدهید.
برای اسکریپتها و CI که مرورگری در کار نیست، بهجای آن یک کلید بسازید. به مجوز keys.manage نیاز دارید. رمز را همان لحظه کپی کنید: فقط یک بار نشان داده میشود. با vmcp_ شروع میشود. آن را در هدر Authorization بهصورت Bearer بفرستید. یک کلید همان دسترسیها و همان محدودیتهای یک برنامهٔ متصل را دارد.
Claude Code
claude mcp add --transport http vatan https://mcp.vatan.one/mcp
Codex
codex mcp add vatan --url https://mcp.vatan.one/mcp
Cursor (فایل mcp.json) و Claude.ai (تنظیمات، اتصالها، افزودن اتصال سفارشی)
{ "mcpServers": { "vatan": { "url": "https://mcp.vatan.one/mcp" } } }اسکریپت و CI: کلید در هدر
claude mcp add --transport http vatan https://mcp.vatan.one/mcp \
--header "Authorization: Bearer vmcp_..."
مثال کامل: فهرست کلیدها و سپس مصرف ۷ روز هر کلید، در یک execute
const keys = await vatan.get('/v1/keys')
const usage = await vatan.get('/v1/usage/by/key?days=7')
return keys.data.map((k) => ({
name: k.name,
prefix: k.prefix,
usage: usage.data.find((u) => u.name === k.name) ?? null,
}))در کنسول: کلیدهای MCP
کاری که کلید API نمیتواند انجام دهد
مرز میان هزینهکردن و مدیریت، و اینکه چرا همانجا کشیده شده است.
کلید درگاه به استنتاج و صف دستهای دسترسی دارد. نمیتواند کلیدها، افراد، بودجهها، صورتحساب یا فضای کاری را بخواند یا تغییر دهد، چون همهی کلیدهای موجود کلید درگاه هستند: روزی که این مرز کوتاه بیاید، هزاران اعتبارنامهی خرجکردن به اعتبارنامهی مدیریتی تبدیل میشوند.
مدیریت را یک نفر در کنسول انجام میدهد، یا با یک کلید مدیریت، که یک اعتبارنامهی جداگانه با فهرست صریح خودش از چیزهایی است که اجازهی دسترسی به آنها را دارد.
در کنسول: افراد و مجوزها