# Permintaan

Permintaan ialah satu panggilan bagi satu model. Ia mempunyai id (`req_…`), status, kosnya dalam kredit API (1000 = 1 USD), dan apabila berjaya, fail yang dijana. Objek yang sama dikembalikan oleh setiap endpoint di bawah, untuk setiap model.

## Cari model

Katalog semua 1,496 model ialah JSON awam (kunci tidak diperlukan):

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

| Parameter pertanyaan | Maksud |
|---|---|
| `q` | Perkataan yang semuanya mesti muncul dalam nama, id, pembuat atau tag, contohnya `kling 3`. |
| `category` | Satu id kategori, contohnya `text-to-video` atau `upscale`. `GET https://api.doitong.com/v1/categories` menyenaraikan semua 21 kategori berserta bilangannya. |
| `lab` | Pembuat model, mengikut nama atau id, contohnya `Google` atau `black-forest-labs`. |
| `family` | Id `family` daripada baris sebelumnya: setiap varian satu model (pro, fast, image-to-video, …). |
| `mode` | `exact` (harga dikira daripada input), `measured` (daripada panjang atau saiz fail input), `estimate` (anggaran harga bagi setiap proses) atau `metered` (dicaj mengikut penggunaan sebenar, sehingga maksimum bagi setiap proses). |
| `limit`, `cursor` | Saiz halaman (1 hingga 100, lalai 50) dan `next_cursor` halaman sebelumnya. |

Setiap baris mempunyai `id`, `name`, `lab`, `category`, `family`, `summary`, `tags`, `output_kind`, `docs_url` dan objek `price` (lihat [Harga](https://doitong.com/developers/docs/pricing#price-objects)). `GET https://api.doitong.com/v1/models/{model_id}` menambah JSON Schema input dan output penuh, nama parameter kanonikal, peraturan harga dan contoh input. `category` atau `mode` yang tidak dikenali ialah `400 invalid_parameter`.

## Jalankan model

```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": "..."}'
```

- Isi permintaan ialah input model, iaitu objek JSON. Setiap halaman model menyenaraikan parameternya.
- Input disemak sebelum apa-apa caj dikenakan. Input tidak sah mengembalikan `422 invalid_input` bersama `param` yang bermasalah dan tidak menelan sebarang kos.
- `?wait=N` (sehingga 20 saat) menahan panggilan sehingga permintaan selesai atau masa tamat.
- `?webhook_url=https://…` menghantar POST bertandatangan ke URL tersebut apabila permintaan selesai (lihat [Webhook](https://doitong.com/developers/docs/webhooks)).
- `?storage=permanent` atau `?storage=temporary` memilih tempoh fail output disimpan; jika tiada, tetapan akaun digunakan (lihat [Lokasi fail](#storage)).

Respons ialah `202 Accepted` semasa permintaan masih diproses, dan `200 OK` apabila ia selesai dalam tempoh menunggu (atau apabila ia ialah main semula, lihat di bawah). Pengepala `Location` dan `Doitong-Request-Id` membawa URL dan id permintaan.

## Status

Kitar hayat permintaan: `queued` → `running` → `succeeded` | `failed` | `canceled` (akhir; yang gagal dan dibatalkan akan dikembalikan kreditnya).

| Status | Maksud | Akhir |
|---|---|---|
| `queued` | Diterima dan dicaj, menunggu pekerja. `queue_position` mungkin menunjukkan kedudukan dalam barisan. | tidak |
| `running` | Model sedang menjana. | tidak |
| `succeeded` | Selesai. `outputs` menyenaraikan fail. | ya |
| `failed` | Model atau had menghentikannya. `error` menyatakan sebabnya. Kredit API dipulangkan. | ya |
| `canceled` | Dibatalkan sebelum menghasilkan hasil. Kredit API dipulangkan. | ya |

Permintaan yang berjalan lebih lama daripada had masanya gagal dengan kod `timeout` dan bayaran balik diberikan: 15 minit untuk imej, 60 minit untuk video, 30 minit untuk audio dan semua yang lain.

## Objek permintaan

```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` adalah sama untuk setiap model: satu entri bagi setiap fail yang dijana dengan `type` (`image`, `video`, `audio`, `file` atau `3d`), `url` pada storan kami, `content_type` dan, apabila diketahui, `file_size`, `width`, `height`, `duration`.
- `output` ialah objek hasil model itu sendiri (medannya disenaraikan pada setiap halaman model) dengan URL yang sama.
- `storage` menyatakan cara fail disimpan: `mode` (`permanent` atau `temporary`), `bytes` yang disimpan, `expires_at` (apabila fail sementara dipadamkan, `null` untuk fail kekal) dan `expired` (`true` setelah fail tiada lagi).
- `cost.credits` ialah harga panggilan dalam kredit API (`cost.usd` dalam USD), `cost.charged` ialah jumlah yang didebitkan daripada baki API, dan `cost.refunded` ialah jumlah yang dipulangkan. Untuk model `metered`, `cost.credits` ialah maksimum yang ditahan pada permulaan (`cost.held`); apabila proses berjaya, `cost.settled` menyatakan jumlah penggunaan dan baki maksimum berada dalam `cost.refunded` (lihat [Dicaj mengikut penggunaan](https://doitong.com/developers/docs/pricing#metered)).
- Apabila permintaan gagal, `error` ialah `{ "type": …, "code": …, "message": … }`.

## Baca permintaan

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

- `?wait=N` (sehingga 20 saat) melakukan long-poll: panggilan dikembalikan sebaik sahaja permintaan selesai, atau selepas N saat dengan keadaan semasa. Mengulanginya ialah cara paling mudah untuk menunggu hasil.
- `?logs=1` menambah baris log kemajuan model (50 yang terakhir) sebagai `logs`.

Anda hanya boleh membaca permintaan akaun sendiri; sebarang id lain ialah `404 request_not_found`.

## Senaraikan permintaan

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

Terbaharu dahulu. `limit` ialah 1 hingga 100 (lalai 20), manakala `status` dan `model` menapis hasil. Respons ialah `{ "object": "list", "data": [ … ], "has_more": true, "next_cursor": "req_…" }`; hantarkan `cursor=<next_cursor>` untuk halaman seterusnya.

## Batalkan permintaan

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

- Dibatalkan sebelum model bermula: status menjadi `canceled`, kredit API dipulangkan dan anda mendapat `200`.
- Sudah menjana: pembatalan dihantar kepada model dan anda mendapat `202` dengan `"cancel_requested": true`. Jika model tetap selesai, permintaan berjaya seperti biasa dan dicaj.
- Sudah selesai: `409 not_cancelable` (permintaan yang sudah `canceled` hanya mengembalikan `200`).

## Padam fail permintaan

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

Memadamkan salinan fail output permintaan dalam storan kami sekarang dan menghentikan caj storannya. Respons ialah objek permintaan dengan `storage.expired: true`; URLnya kekal dalam rekod tetapi tidak lagi berfungsi. Memanggilnya sekali lagi tidak mengubah apa-apa (`200`). Permintaan yang masih `queued` atau `running` belum mempunyai fail: `409 request_active`. Memerlukan `models:run`.

## Idempotensi: cuba semula tanpa membayar dua kali

Rangkaian boleh gagal. Untuk mencuba semula proses dengan selamat, hantar pengepala `Idempotency-Key` (sebarang rentetan sehingga 255 aksara, unik bagi setiap operasi, contohnya id pesanan anda sendiri):

- Kunci dan isi yang sama seperti sebelumnya: anda mendapat semula permintaan asal (`200`, pengepala `Idempotent-Replayed: true`) dan tiada caj tambahan dikenakan.
- Kunci dan isi yang sama selepas proses yang gagal sebelum mencapai model (`upstream_error` atau `internal_error` semasa penghantaran, `insufficient_credits`, `budget_exceeded`, `too_many_inflight`): tiada apa-apa dihasilkan dan tiada caj dikenakan, jadi percubaan semula menjalankan model sekali lagi dan bukannya mengembalikan kegagalan.
- Kunci yang sama dengan isi berbeza: `409 idempotency_mismatch`.
- Kunci dikhususkan kepada kunci API yang menghantarnya.

## Lokasi fail

Setiap fail output disalin ke storan kami sebelum permintaan ditandai `succeeded`, jadi URL dalam `outputs` berada pada hos kami sendiri dan anda boleh memautkannya secara terus. Anda boleh memilih tempoh penyimpanannya:

| Mod | Tempoh | Harga |
|---|---|---|
| `permanent` (lalai) | Sehingga anda memadamkannya | 100 kredit API ($0.10) setiap GB sebulan, dicaj setiap hari daripada baki API |
| `temporary` | 7 hari, kemudian dipadamkan | Percuma |

- Tetapan akaun menentukan pilihan untuk permintaan baharu: suis "Simpan fail selama-lamanya" dalam [papan pemuka](https://doitong.com/developers/dashboard#balance), atau `PATCH https://api.doitong.com/v1/account/storage` dengan `{"mode": "temporary"}`. `GET https://api.doitong.com/v1/account` memaparkannya di bawah `storage`, bersama bait yang anda simpan dan anggaran bulanan.
- `?storage=permanent|temporary` semasa menjalankan proses (argumen `storage` bagi alat MCP `run`) mengatasinya untuk proses tersebut.
- Menukar tetapan tidak pernah menyentuh fail yang telah anda miliki; padamkannya dengan [`DELETE /requests/{id}/files`](#delete-files).
- Apabila baki API tidak dapat membayar storan, tiada caj dikenakan dan anda akan menerima e-mel: tambah nilai dalam tempoh 30 hari, atau fail yang disimpan menjadi sementara dan dipadamkan 7 hari kemudian.

Dalam keadaan jarang berlaku apabila salinan kami gagal, entri mempunyai `"stored": false` dan URL ialah URL asal yang berjangka pendek: muat turunnya dengan segera.
