# Zahtjevi

Zahtjev je jedan poziv jednog modela. Ima id (`req_…`), status, cijenu u API kreditima (1000 = 1 USD) i, kada
uspije, generirane datoteke. Isti objekt vraća se sa svake krajnje točke u nastavku, za svaki model.

## Pronalaženje modela

Katalog svih 1.496 modela javni je JSON (ključ nije potreban):

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

| Parametar upita | Značenje |
|---|---|
| `q` | Riječi koje se sve moraju pojaviti u nazivu, id-u, proizvođaču ili oznakama, na primjer `kling 3`. |
| `category` | Jedan id kategorije, na primjer `text-to-video` ili `upscale`. `GET https://api.doitong.com/v1/categories` navodi svih 21 s njihovim brojevima. |
| `lab` | Proizvođač modela, prema nazivu ili id-u, na primjer `Google` ili `black-forest-labs`. |
| `family` | Id `family` iz prethodnog retka: svaka varijanta jednog modela (pro, fast, image-to-video, …). |
| `mode` | `exact` (cijena se izračunava iz ulaza), `measured` (iz duljine ili veličine ulaznih datoteka), `estimate` (procijenjena cijena po pokretanju) ili `metered` (naplaćuje se prema stvarnoj potrošnji, do najveće cijene po pokretanju). |
| `limit`, `cursor` | Veličina stranice (1 do 100, zadano 50) i `next_cursor` prethodne stranice. |

Svaki redak ima `id`, `name`, `lab`, `category`, `family`, `summary`, `tags`, `output_kind`, `docs_url` i objekt
`price` (pogledajte [Cijene](https://doitong.com/developers/docs/pricing#price-objects)). `GET https://api.doitong.com/v1/models/{model_id}` dodaje
potpunu JSON shemu ulaza i izlaza, kanonske nazive parametara, pravila cijena i primjer ulaza. Nepoznata vrijednost
`category` ili `mode` vraća `400 invalid_parameter`.

## Pokretanje modela

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

- Tijelo je ulaz modela, JSON objekt. Svaka stranica modela navodi njegove parametre.
- Ulaz se provjerava prije naplate. Nevažeći ulaz vraća `422 invalid_input` s problematičnim
  `param`, bez troška.
- `?wait=N` (do 20 sekundi) zadržava poziv dok se zahtjev ne dovrši ili dok vrijeme ne istekne.
- `?webhook_url=https://…` šalje potpisani `POST` na taj URL kada se zahtjev dovrši (pogledajte [Webhookove](https://doitong.com/developers/docs/webhooks)).
- `?storage=permanent` ili `?storage=temporary` odabire koliko se dugo izlazne datoteke čuvaju; bez toga primjenjuje se
  postavka računa (pogledajte [Gdje se datoteke čuvaju](#storage)).

Odgovor je `202 Accepted` dok se zahtjev još obrađuje, a `200 OK` kada je dovršen unutar vremena čekanja (ili
kada je ponovljena isporuka, pogledajte u nastavku). Zaglavlja `Location` i `Doitong-Request-Id` sadrže URL i id zahtjeva.

## Statusi

Životni ciklus zahtjeva: `queued` → `running` → `succeeded` | `failed` | `canceled` (završeno; neuspjeli i otkazani zahtjevi se refundiraju).

| Status | Značenje | Konačan |
|---|---|---|
| `queued` | Prihvaćen i naplaćen, čeka radnika. `queue_position` može prikazati mjesto u redu. | ne |
| `running` | Model generira. | ne |
| `succeeded` | Dovršeno. `outputs` navodi datoteke. | da |
| `failed` | Model ili ograničenje zaustavili su ga. `error` navodi razlog. API krediti vraćaju se. | da |
| `canceled` | Otkazano prije stvaranja rezultata. API krediti vraćaju se. | da |

Zahtjev koji traje dulje od vremenskog ograničenja ne uspijeva s kodom `timeout`, a sredstva se vraćaju: 15 minuta za slike,
60 minuta za video, 30 minuta za audio i sve ostalo.

## Objekt zahtjeva

```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` je isti za svaki model: po jedan zapis za svaku generiranu datoteku s `type` (`image`, `video`, `audio`,
  `file` ili `3d`), `url` na našoj pohrani, `content_type` i, kada su poznati, `file_size`, `width`, `height`,
  `duration`.
- `output` je vlastiti objekt rezultata modela (njegova polja navedena su na svakoj stranici modela) s istim URL-ovima.
- `storage` navodi kako se datoteke čuvaju: `mode` (`permanent` ili `temporary`), pohranjene `bytes`, `expires_at` (kada
  se privremena datoteka briše, `null` za trajne) i `expired` (`true` kada datoteke nestanu).
- `cost.credits` je cijena poziva u API kreditima (`cost.usd` u USD), `cost.charged` iznos terećen sa stanja API-ja,
  a `cost.refunded` vraćeni iznos. Za model `metered`, `cost.credits` je najveći iznos zadržan na početku
  (`cost.held`); kada pokretanje uspije, `cost.settled` navodi stvarnu potrošnju, a ostatak najvećeg iznosa nalazi se u
  `cost.refunded` (pogledajte [Naplaćivanje prema potrošnji](https://doitong.com/developers/docs/pricing#metered)).
- Kada zahtjev ne uspije, `error` je `{ "type": …, "code": …, "message": … }`.

## Čitanje zahtjeva

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

- `?wait=N` (do 20 sekundi) provodi dugo čekanje: poziv se vraća čim zahtjev dobije konačni status ili nakon N sekundi s
  trenutačnim stanjem. Ponavljanje ovog poziva najjednostavniji je način čekanja rezultata.
- `?logs=1` dodaje retke dnevnika napretka modela (posljednjih 50) kao `logs`.

Možete čitati samo zahtjeve vlastitog računa; bilo koji drugi id je `404 request_not_found`.

## Popis zahtjeva

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

Najnoviji su prvi. `limit` je 1 do 100 (zadano 20), a `status` i `model` služe za filtriranje. Odgovor je
`{ "object": "list", "data": [ … ], "has_more": true, "next_cursor": "req_…" }`; za sljedeću stranicu proslijedite
`cursor=<next_cursor>`.

## Otkazivanje zahtjeva

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

- Otkazano prije početka modela: status postaje `canceled`, API krediti vraćaju se i dobivate `200`.
- Već se generira: otkazivanje se prosljeđuje i dobivate `202` s `"cancel_requested": true`. Ako model ipak
  završi, zahtjev normalno uspijeva i naplaćuje se.
- Već ima konačni status: `409 not_cancelable` (zahtjev koji je već `canceled` jednostavno vraća `200`).

## Brisanje datoteka zahtjeva

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

Odmah briše naše kopije izlaznih datoteka zahtjeva i zaustavlja naplatu njihove pohrane. Odgovor je objekt zahtjeva
sa `storage.expired: true`; njegovi URL-ovi ostaju u zapisu, ali više ne rade. Ponovni poziv ne mijenja ništa
(`200`). Zahtjev koji je još `queued` ili `running` još nema datoteke: `409 request_active`. Potreban je `models:run`.

## Idempotentnost: ponovni pokušaj bez dvostruke naplate

Mreže otkazuju. Za siguran ponovni pokušaj pošaljite zaglavlje `Idempotency-Key` (bilo koji niz do 255 znakova, jedinstven po
operaciji, na primjer vlastiti id narudžbe):

- Isti ključ i isto tijelo kao prije: dobivate izvorni zahtjev (`200`, zaglavlje
  `Idempotent-Replayed: true`), a ništa se ponovno ne naplaćuje.
- Isti ključ i tijelo nakon pokretanja koje nije uspjelo prije dolaska do modela (`upstream_error` ili `internal_error` pri
  slanju, `insufficient_credits`, `budget_exceeded`, `too_many_inflight`): ništa nije proizvedeno i ništa se ne
  naplaćuje, pa se pri ponovnom pokušaju model ponovno pokreće umjesto vraćanja pogreške.
- Isti ključ s drugačijim tijelom: `409 idempotency_mismatch`.
- Ključevi su vezani uz API ključ koji ih je poslao.

## Gdje se datoteke čuvaju

Svaka izlazna datoteka kopira se u našu pohranu prije nego što se zahtjev označi kao `succeeded`, pa su URL-ovi u
`outputs` na našim poslužiteljima i možete ih izravno povezati. Koliko dugo ostaju odabirete sami:

| Način | Trajanje | Cijena |
|---|---|---|
| `permanent` (zadano) | Dok ih ne izbrišete | 100 API kredita (0,10 $) po GB mjesečno, naplaćuje se dnevno sa stanja API-ja |
| `temporary` | 7 dana, zatim se brišu | Besplatno |

- Postavka računa odlučuje za nove zahtjeve: prekidač "Čuvaj datoteke zauvijek" na
  [nadzornoj ploči](https://doitong.com/developers/dashboard#balance) ili `PATCH https://api.doitong.com/v1/account/storage` s
  `{"mode": "temporary"}`. `GET https://api.doitong.com/v1/account` prikazuje je pod `storage`, zajedno s količinom koju čuvate i
  mjesečnom procjenom.
- `?storage=permanent|temporary` pri pokretanju (argument `storage` alata `run` za MCP) nadjačava je za to pokretanje.
- Promjena postavke nikada ne utječe na datoteke koje već imate; izbrišite ih pomoću
  [`DELETE /requests/{id}/files`](#delete-files).
- Kada stanje API-ja ne može platiti pohranu, ništa se ne naplaćuje i dobivate e-poruku: nadoplatite u roku od
  30 dana ili će čuvane datoteke postati privremene i biti izbrisane 7 dana poslije.

U rijetkom slučaju da naša kopija ne uspije, zapis ima `"stored": false`, a URL je izvorni, kratkotrajan URL:
preuzmite datoteku što prije.
