# Mga Kahilingan

Ang isang kahilingan ay isang tawag sa isang modelo. Mayroon itong id (`req_…`), status, gastos nito sa kredito ng API (1000 = 1 USD), at kapag matagumpay, mga nabuong file. Parehong object ang ibinabalik ng bawat endpoint sa ibaba para sa bawat modelo.

## Maghanap ng modelo

Ang catalog ng lahat ng 1,496 modelo ay pampublikong JSON (walang kinakailangang key):

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

| Query parameter | Kahulugan |
|---|---|
| `q` | Mga salitang dapat lahat lumitaw sa pangalan, id, maker o tag, halimbawa `kling 3`. |
| `category` | Isang category id, halimbawa `text-to-video` o `upscale`. Inililista ng `GET https://api.doitong.com/v1/categories` ang lahat ng 21 kasama ang bilang ng mga ito. |
| `lab` | Maker ng modelo, ayon sa pangalan o id, halimbawa `Google` o `black-forest-labs`. |
| `family` | Isang `family` id mula sa naunang row: bawat variant ng isang modelo (pro, fast, image-to-video, …). |
| `mode` | `exact` (kinukuwenta ang presyo mula sa input), `measured` (mula sa haba o laki ng mga input file), `estimate` (tinatayang presyo bawat run) o `metered` (sinisingil batay sa aktuwal na paggamit, hanggang sa maximum bawat run). |
| `limit`, `cursor` | Laki ng page (1 hanggang 100, default 50) at ang `next_cursor` ng nakaraang page. |

May `id`, `name`, `lab`, `category`, `family`, `summary`, `tags`, `output_kind`, `docs_url` at object na `price` ang bawat row (tingnan ang [Pagpepresyo](https://doitong.com/developers/docs/pricing#price-objects)). Idinaragdag ng `GET https://api.doitong.com/v1/models/{model_id}` ang buong input at output JSON Schema, mga canonical na pangalan ng parameter, mga panuntunan sa presyo at halimbawang input. Ang hindi kilalang `category` o `mode` ay `400 invalid_parameter`.

## Magpatakbo ng modelo

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

- Ang body ay input ng modelo, isang JSON object. Inililista ng page ng bawat modelo ang mga parameter nito.
- Sinusuri ang input bago maningil. Ang hindi wastong input ay nagbabalik ng `422 invalid_input` kasama ang maling `param`, at walang gastos.
- Pinananatili ng `?wait=N` (hanggang 20 segundo) ang tawag hanggang matapos ang kahilingan o maubos ang oras.
- Nagpapadala ang `?webhook_url=https://…` ng pirmadong POST sa URL na iyon kapag natapos ang kahilingan (tingnan ang [Webhooks](https://doitong.com/developers/docs/webhooks)).
- Pinipili ng `?storage=permanent` o `?storage=temporary` kung gaano katagal pananatilihin ang mga output file; kung wala ito, gagamitin ang setting ng account (tingnan ang [Kung saan inilalagay ang mga file](#storage)).

Ang response ay `202 Accepted` habang pinoproseso pa ang kahilingan, at `200 OK` kapag natapos ito sa loob ng wait (o kapag replay ito, tingnan sa ibaba). Nasa `Location` at `Doitong-Request-Id` headers ang URL at id ng kahilingan.

## Mga status

Lifecycle ng kahilingan: `queued` → `running` → `succeeded` | `failed` | `canceled` (final; nire-refund ang mga nabigo at nakansela).

| Status | Kahulugan | Final |
|---|---|---|
| `queued` | Tinanggap at siningil, naghihintay ng worker. Maaaring ipakita ng `queue_position` ang puwesto sa pila. | no |
| `running` | Bumubuo ang modelo. | no |
| `succeeded` | Tapos na. Inililista ng `outputs` ang mga file. | yes |
| `failed` | Pinahinto ito ng modelo o limit. Sinasabi ng `error` kung bakit. Ibinabalik ang kredito ng API. | yes |
| `canceled` | Kinansela bago makagawa ng resulta. Ibinabalik ang kredito ng API. | yes |

Ang kahilingang lumampas sa takdang oras ay mabibigo na may code na `timeout` at mare-refund: 15 minuto para sa mga larawan, 60 minuto para sa video, 30 minuto para sa audio at lahat ng iba pa.

## Ang object ng kahilingan

```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"
  }
}
```

- Pareho ang `outputs` para sa bawat modelo: isang entry bawat nabuong file na may `type` (`image`, `video`, `audio`, `file` o `3d`), `url` sa aming storage, `content_type` at, kapag alam, `file_size`, `width`, `height`, `duration`.
- Ang `output` ay sariling result object ng modelo (nakalista ang mga field nito sa page ng bawat modelo) na may parehong mga URL.
- Sinasabi ng `storage` kung paano pinananatili ang mga file: `mode` (`permanent` o `temporary`), naka-store na `bytes`, `expires_at` (kapag dine-delete ang temporary file, `null` para sa permanent) at `expired` (`true` kapag wala na ang mga file).
- Ang `cost.credits` ay presyo ng tawag sa kredito ng API (`cost.usd` sa USD), ang `cost.charged` ay halagang ibinawas sa balanse ng API, at ang `cost.refunded` ay halagang ibinalik. Para sa `metered` na modelo, ang `cost.credits` ay maximum na hinold sa simula (`cost.held`); kapag matagumpay ang run, sinasabi ng `cost.settled` kung magkano ang aktuwal na paggamit at nasa `cost.refunded` ang natitirang bahagi ng maximum (tingnan ang [Sinisingil batay sa paggamit](https://doitong.com/developers/docs/pricing#metered)).
- Kapag nabigo ang kahilingan, ang `error` ay `{ "type": …, "code": …, "message": … }`.

## Magbasa ng kahilingan

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

- Ang `?wait=N` (hanggang 20 segundo) ay long-poll: nagbabalik ang tawag sa sandaling final na ang kahilingan, o pagkatapos ng N segundo kasama ang kasalukuyang estado. Ang pag-loop dito ang pinakasimpleng paraan para maghintay ng resulta.
- Idinaragdag ng `?logs=1` ang mga linya ng progress log ng modelo (ang huling 50) bilang `logs`.

Mababasa mo lamang ang mga kahilingan ng sarili mong account; ang ibang id ay `404 request_not_found`.

## Maglista ng mga kahilingan

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

Pinakabago muna. Ang `limit` ay 1 hanggang 100 (default 20), at nagfi-filter ang `status` at `model`. Ang response ay `{ "object": "list", "data": [ … ], "has_more": true, "next_cursor": "req_…" }`; ipasa ang `cursor=<next_cursor>` para sa susunod na page.

## Kanselahin ang kahilingan

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

- Kinansela bago nagsimula ang modelo: nagiging `canceled` ang status, ibinabalik ang kredito ng API, at makakakuha ka ng `200`.
- Bumubuo na: ipinapasa ang pagkansela at makakakuha ka ng `202` na may `"cancel_requested": true`. Kung matatapos pa rin ang modelo, normal na magtatagumpay at sisingilin ang kahilingan.
- Final na: `409 not_cancelable` (ang kahilingang `canceled` na ay nagbabalik lang ng `200`).

## I-delete ang mga file ng kahilingan

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

Dine-delete agad ang aming mga kopya ng output file ng kahilingan at itinitigil ang singil sa storage. Ang response ay ang object ng kahilingan na may `storage.expired: true`; mananatili sa record ang mga URL pero hindi na gagana. Walang mababago sa muling pagtawag (`200`). Ang kahiyang `queued` o `running` pa ay wala pang file: `409 request_active`. Kailangan ang `models:run`.

## Idempotency: muling subukan nang hindi makalawang beses magbayad

Nabibigo ang mga network. Para ligtas na muling subukan ang isang run, magpadala ng `Idempotency-Key` header (anumang string na hanggang 255 character, natatangi bawat operation, halimbawa sarili mong order id):

- Parehong key at parehong body gaya ng dati: ibinabalik ang orihinal na kahilingan (`200`, header na `Idempotent-Replayed: true`), at hindi na muling sisingilin.
- Parehong key at body pagkatapos ng run na nabigo bago umabot sa modelo (`upstream_error` o `internal_error` sa submit, `insufficient_credits`, `budget_exceeded`, `too_many_inflight`): walang ginawa at walang siningil, kaya muling tatakbo ang modelo sa halip na ibalik ang failure.
- Parehong key pero ibang body: `409 idempotency_mismatch`.
- Sakop ang mga key ng API key na nagpadala sa mga ito.

## Kung saan inilalagay ang mga file

Kinokopya ang bawat output file sa aming storage bago markahang `succeeded` ang kahilingan, kaya nasa sarili naming host ang mga URL sa `outputs` at maaari mong direktang i-link ang mga ito. Ikaw ang pumipili kung gaano katagal mananatili ang mga ito:

| Mode | Gaano katagal | Presyo |
|---|---|---|
| `permanent` (default) | Hanggang i-delete mo ang mga ito | 100 kredito ng API ($0.10) bawat GB bawat buwan, araw-araw na sinisingil mula sa balanse ng API |
| `temporary` | 7 araw, saka dine-delete | Libre |

- Ang setting ng account ang ginagamit para sa mga bagong kahilingan: ang switch na "Itago ang mga file habambuhay" sa [dashboard](https://doitong.com/developers/dashboard#balance), o `PATCH https://api.doitong.com/v1/account/storage` na may `{"mode": "temporary"}`. Ipinapakita ito ng `GET https://api.doitong.com/v1/account` sa ilalim ng `storage`, kasama ang mga byte na pinananatili mo at buwanang tantiya.
- Ino-override ito ng `?storage=permanent|temporary` sa isang run (ang `storage` argument ng MCP `run` tool) para sa run na iyon.
- Hindi kailanman naaapektuhan ng pagbabago ng setting ang mga file na mayroon ka na; i-delete ang mga iyon gamit ang [`DELETE /requests/{id}/files`](#delete-files).
- Kapag hindi kayang bayaran ng balanse ng API ang storage, walang sisingilin at makakatanggap ka ng email: magdagdag ng balanse sa loob ng 30 araw, kung hindi magiging temporary ang mga file at made-delete pagkalipas ng 7 araw.

Sa pambihirang pagkakataong mabigo ang pagkopya namin, magiging `"stored": false` ang entry at ang URL ay ang orihinal na panandaliang URL: i-download ito agad.
