# درخواست‌ها

یک درخواست، یک فراخوانی از یک مدل است. این درخواست یک شناسه (`req_…`)، یک وضعیت، هزینه آن برحسب اعتبار API (1000 = 1 USD) و در صورت موفقیت، فایل‌های تولیدشده را دارد. همین شیء از همه نقطه‌های پایانی زیر و برای هر مدل برگردانده می‌شود.

## یافتن یک مدل

کاتالوگ همه ۱٬۴۹۶ مدل به‌صورت JSON عمومی است (به کلید نیاز ندارد):

```bash
curl "https://api.doitong.com/v1/models?category=text-to-video&lab=Google&limit=20"
```

| پارامتر پرس‌وجو | معنا |
|---|---|
| `q` | واژه‌هایی که باید همگی در نام، شناسه، سازنده یا برچسب‌ها ظاهر شوند؛ مثلاً `kling 3`. |
| `category` | یک شناسه دسته؛ مثلاً `text-to-video` یا `upscale`. `GET https://api.doitong.com/v1/categories` همه ۲۱ دسته را همراه تعدادشان فهرست می‌کند. |
| `lab` | سازنده مدل، بر اساس نام یا شناسه؛ مثلاً `Google` یا `black-forest-labs`. |
| `family` | یک شناسه `family` از ردیف قبلی: هر گونه از یک مدل (pro، fast، image-to-video، …). |
| `mode` | `exact` (قیمت از ورودی محاسبه می‌شود)، `measured` (بر اساس طول یا اندازه فایل‌های ورودی)، `estimate` (قیمت تخمینی برای هر اجرا) یا `metered` (بر اساس مصرف واقعی، تا سقف هر اجرا). |
| `limit`, `cursor` | اندازه صفحه (1 تا 100، پیش‌فرض 50) و `next_cursor` صفحه قبلی. |

هر ردیف شامل `id`، `name`، `lab`، `category`، `family`، `summary`، `tags`، `output_kind`، `docs_url` و یک شیء `price` است (به [قیمت‌گذاری](https://doitong.com/developers/docs/pricing#price-objects) مراجعه کنید). `GET https://api.doitong.com/v1/models/{model_id}` طرح‌واره کامل JSON ورودی و خروجی، نام‌های استاندارد پارامترها، قوانین قیمت‌گذاری و نمونه ورودی را اضافه می‌کند. `category` یا `mode` ناشناخته، `400 invalid_parameter` است.

## اجرای یک مدل

```bash
curl -X POST "https://api.doitong.com/v1/run/{model_id}?wait=20" \
  -H "Authorization: Bearer $DOITONG_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1842-cover" \
  -d '{"prompt": "..."}'
```

- بدنه، ورودی مدل و یک شیء JSON است. پارامترهای هر مدل در صفحه آن فهرست شده‌اند.
- ورودی پیش از هرگونه دریافت هزینه بررسی می‌شود. ورودی نامعتبر `422 invalid_input` را همراه `param` مشکل‌دار برمی‌گرداند و هزینه‌ای ندارد.
- `?wait=N` (تا 20 ثانیه) فراخوانی را تا پایان درخواست یا اتمام زمان منتظر نگه می‌دارد.
- `?webhook_url=https://…` پس از پایان درخواست، یک `POST` امضاشده به آن نشانی می‌فرستد (به [وب‌هوک‌ها](https://doitong.com/developers/docs/webhooks) مراجعه کنید).
- `?storage=permanent` یا `?storage=temporary` مدت نگهداری فایل‌های خروجی را انتخاب می‌کند؛ در صورت نبود آن، تنظیم حساب اعمال می‌شود (به [محل نگهداری فایل‌ها](#storage) مراجعه کنید).

پاسخ تا زمانی که درخواست در حال اجراست `202 Accepted` و وقتی در محدوده زمان انتظار تمام شود `200 OK` است (یا وقتی بازپخش باشد؛ پایین‌تر را ببینید). هدرهای `Location` و `Doitong-Request-Id` نشانی و شناسه درخواست را حمل می‌کنند.

## وضعیت‌ها

چرخه عمر درخواست: `queued` → `running` → `succeeded` | `failed` | `canceled` (نهایی؛ درخواست‌های ناموفق و لغوشده بازپرداخت می‌شوند).

| وضعیت | معنا | نهایی |
|---|---|---|
| `queued` | پذیرفته و هزینه دریافت شده و منتظر پردازشگر است. `queue_position` ممکن است جایگاه در صف را نشان دهد. | خیر |
| `running` | مدل در حال تولید است. | خیر |
| `succeeded` | تمام شد. `outputs` فایل‌ها را فهرست می‌کند. | بله |
| `failed` | مدل یا یک محدودیت آن را متوقف کرده است. `error` دلیل را می‌گوید. اعتبار API بازپرداخت می‌شود. | بله |
| `canceled` | پیش از تولید نتیجه لغو شد. اعتبار API بازپرداخت می‌شود. | بله |

درخواستی که بیشتر از محدودیت زمانی اجرا شود، با کد `timeout` ناموفق می‌شود و هزینه‌اش بازپرداخت می‌شود: برای تصویر 15 دقیقه، برای ویدیو 60 دقیقه، برای صوت و همه موارد دیگر 30 دقیقه.

## شیء درخواست

```json
{
  "id": "req_8k2m4q7x1z9c3v5b6n0p2r4t",
  "object": "request",
  "model": "flux/schnell",
  "status": "succeeded",
  "created_at": "2026-10-20T12:00:00Z",
  "started_at": "2026-10-20T12:00:01Z",
  "completed_at": "2026-10-20T12:00:02Z",
  "queue_position": null,
  "cost": { "credits": 3, "usd": "0.003", "charged": 3, "refunded": 0 },
  "input": { "prompt": "..." },
  "output": { "images": [ { "url": "https://content.doitong.com/dev-api/…/0-output.jpeg", "width": 1024, "height": 768 } ] },
  "outputs": [
    { "type": "image", "url": "https://content.doitong.com/dev-api/…/0-output.jpeg", "content_type": "image/jpeg",
      "width": 1024, "height": 768, "file_size": 183920, "stored": true }
  ],
  "error": null,
  "metrics": { "inference_seconds": 1.2 },
  "storage": { "mode": "permanent", "bytes": 183920, "expires_at": null, "expired": false },
  "urls": {
    "self": "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t",
    "cancel": "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t/cancel"
  }
}
```

- `outputs` برای همه مدل‌ها یکسان است: برای هر فایل تولیدشده یک ورودی با `type` (`image`، `video`، `audio`، `file` یا `3d`)، یک `url` در فضای ذخیره‌سازی ما، `content_type` و در صورت معلوم بودن `file_size`، `width`، `height` و `duration`.
- `output` شیء نتیجه مخصوص مدل است (فیلدهای آن در صفحه هر مدل فهرست شده‌اند) و همان URLها را دارد.
- `storage` نحوه نگهداری فایل‌ها را مشخص می‌کند: `mode` (`permanent` یا `temporary`)، `bytes` ذخیره‌شده، `expires_at` (زمان حذف فایل موقت، و برای فایل دائمی `null`) و `expired` (پس از حذف فایل‌ها `true`).
- `cost.credits` قیمت فراخوانی برحسب اعتبار API است (`cost.usd` برحسب USD)، `cost.charged` مبلغ کسرشده از موجودی API و `cost.refunded` مبلغ بازگشتی است. برای مدل `metered`، `cost.credits` حداکثر مبلغ نگه‌داشته‌شده در آغاز است (`cost.held`)؛ پس از موفقیت اجرا، `cost.settled` مصرف واقعی و باقی‌مانده حداکثر در `cost.refunded` قرار می‌گیرد (به [دریافت هزینه بر اساس مصرف](https://doitong.com/developers/docs/pricing#metered) مراجعه کنید).
- هنگام ناموفق‌شدن درخواست، `error` برابر `{ "type": …, "code": …, "message": … }` است.

## خواندن یک درخواست

```bash
curl "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t?wait=20" \
  -H "Authorization: Bearer $DOITONG_API_KEY"
```

- `?wait=N` (تا 20 ثانیه) به‌صورت long-poll عمل می‌کند: فراخوانی به‌محض نهایی‌شدن درخواست یا پس از N ثانیه با وضعیت فعلی برمی‌گردد. حلقه‌زدن روی آن ساده‌ترین روش انتظار برای نتیجه است.
- `?logs=1` خطوط گزارش پیشرفت مدل (50 خط آخر) را به‌عنوان `logs` اضافه می‌کند.

فقط می‌توانید درخواست‌های حساب خودتان را بخوانید؛ هر شناسه دیگر `404 request_not_found` است.

## فهرست درخواست‌ها

```bash
curl "https://api.doitong.com/v1/requests?limit=20&status=succeeded&model=flux/schnell" \
  -H "Authorization: Bearer $DOITONG_API_KEY"
```

جدیدترین مورد ابتدا می‌آید. `limit` بین 1 تا 100 است (پیش‌فرض 20) و `status` و `model` فیلتر می‌کنند. پاسخ `{ "object": "list", "data": [ … ], "has_more": true, "next_cursor": "req_…" }` است؛ برای صفحه بعد `cursor=<next_cursor>` را ارسال کنید.

## لغو یک درخواست

```bash
curl -X POST "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t/cancel" \
  -H "Authorization: Bearer $DOITONG_API_KEY"
```

- لغوشده پیش از شروع مدل: وضعیت به `canceled` تبدیل می‌شود، اعتبار API بازپرداخت می‌شود و `200` دریافت می‌کنید.
- در حال تولید: درخواست لغو ارسال می‌شود و `202` همراه `"cancel_requested": true` دریافت می‌کنید. اگر مدل بااین‌حال تمام شود، درخواست عادی موفق و هزینه‌دار خواهد بود.
- از پیش نهایی‌شده: `409 not_cancelable` (درخواستی که از قبل `canceled` است، فقط `200` برمی‌گرداند).

## حذف فایل‌های یک درخواست

```bash
curl -X DELETE "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t/files" \
  -H "Authorization: Bearer $DOITONG_API_KEY"
```

نسخه‌های ما از فایل‌های خروجی درخواست را اکنون حذف می‌کند و هزینه فضای ذخیره‌سازی آن‌ها را متوقف می‌سازد. پاسخ، شیء درخواست با `storage.expired: true` است؛ URLها در سابقه باقی می‌مانند اما دیگر کار نمی‌کنند. اجرای دوباره تغییری ایجاد نمی‌کند (`200`). درخواست `queued` یا `running` هنوز فایلی ندارد: `409 request_active`. به `models:run` نیاز دارد.

## همسانی: تلاش مجدد بدون پرداخت دوباره

شبکه‌ها دچار خطا می‌شوند. برای تلاش مجدد امن، هدر `Idempotency-Key` را ارسال کنید (هر رشته تا 255 نویسه، یکتا برای هر عملیات؛ مثلاً شناسه سفارش خودتان):

- همان کلید و همان بدنه قبلی: درخواست اصلی را دریافت می‌کنید (`200`، هدر `Idempotent-Replayed: true`) و دوباره هزینه‌ای دریافت نمی‌شود.
- همان کلید و بدنه پس از اجرایی که پیش از رسیدن به مدل ناموفق شده است (`upstream_error` یا `internal_error` هنگام ارسال، `insufficient_credits`، `budget_exceeded`، `too_many_inflight`): چیزی تولید نشده و هزینه‌ای دریافت نشده است؛ بنابراین تلاش مجدد مدل را دوباره اجرا می‌کند، نه اینکه خطا را برگرداند.
- همان کلید با بدنه متفاوت: `409 idempotency_mismatch`.
- کلیدها به کلید API ارسال‌کننده محدود هستند.

## محل نگهداری فایل‌ها

هر فایل خروجی پیش از علامت‌گذاری درخواست به‌عنوان `succeeded` در فضای ذخیره‌سازی ما کپی می‌شود؛ بنابراین URLهای `outputs` روی میزبان‌های خودمان هستند و می‌توانید مستقیماً به آن‌ها پیوند دهید. مدت نگهداری به انتخاب شماست:

| حالت | مدت | قیمت |
|---|---|---|
| `permanent` (پیش‌فرض) | تا زمان حذف | ۱۰۰ اعتبار API (⁨‎$۰٫۱۰⁩) برای هر GB در ماه، با کسر روزانه از موجودی API |
| `temporary` | ۷ روز، سپس حذف | رایگان |

- تنظیم حساب برای درخواست‌های جدید تعیین‌کننده است: کلید «فایل‌ها برای همیشه نگه داشته شوند» در [داشبورد](https://doitong.com/developers/dashboard#balance)، یا `PATCH https://api.doitong.com/v1/account/storage` با `{"mode": "temporary"}`. `GET https://api.doitong.com/v1/account` آن را زیر `storage`، همراه بایت‌های نگهداری‌شده و برآورد ماهانه نشان می‌دهد.
- `?storage=permanent|temporary` هنگام اجرا (پارامتر `storage` ابزار `run` در MCP) آن را برای همان اجرا لغو می‌کند.
- تغییر تنظیم هرگز فایل‌های موجود را تغییر نمی‌دهد؛ آن‌ها را با [`DELETE /requests/{id}/files`](#delete-files) حذف کنید.
- وقتی موجودی API نتواند هزینه فضای ذخیره‌سازی را پرداخت کند، هزینه‌ای دریافت نمی‌شود و ایمیلی دریافت می‌کنید: ظرف ۳۰ روز موجودی را افزایش دهید؛ در غیر این صورت فایل‌های نگهداری‌شده موقت می‌شوند و ۷ روز بعد حذف خواهند شد.

در موارد نادرِ ناموفق‌بودن کپی ما، ورودی دارای `"stored": false` است و URL همان URL اصلی و کوتاه‌مدت است: آن را به‌سرعت بارگیری کنید.
