# Pyynnöt

Pyyntö on yksi yhden mallin kutsu. Sillä on tunnus (`req_…`), tila, hinta API-krediitteinä (1000 = 1 USD) ja onnistuessaan luodut tiedostot. Sama objekti palautetaan jokaisesta alla olevasta päätepisteestä jokaiselle mallille.

## Mallin etsiminen

Kaikkien 1 496 mallin luettelo on julkista JSON-dataa (avainta ei tarvita):

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

| Kyselyparametri | Merkitys |
|---|---|
| `q` | Kaikkien sanojen on esiinnyttävä nimessä, tunnuksessa, valmistajassa tai tunnisteissa, esimerkiksi `kling 3`. |
| `category` | Yksi luokan tunnus, esimerkiksi `text-to-video` tai `upscale`. `GET https://api.doitong.com/v1/categories` luettelee kaikki 21 luokkaa määrineen. |
| `lab` | Mallin valmistaja nimen tai tunnuksen perusteella, esimerkiksi `Google` tai `black-forest-labs`. |
| `family` | Edellisen rivin `family`-tunnus: yhden mallin kaikki versiot (pro, fast, image-to-video, …). |
| `mode` | `exact` (hinta lasketaan syötteen perusteella), `measured` (syötetiedostojen pituuden tai koon perusteella), `estimate` (arvioitu hinta ajoa kohti) tai `metered` (veloitus todellisen käytön mukaan, enintään ajoa kohti määritettyyn enimmäismäärään asti). |
| `limit`, `cursor` | Sivun koko (1–100, oletus 50) ja edellisen sivun `next_cursor`. |

Jokaisella rivillä on `id`, `name`, `lab`, `category`, `family`, `summary`, `tags`, `output_kind`, `docs_url` ja `price`-objekti (katso [Hinnoittelu](https://doitong.com/developers/docs/pricing#price-objects)). `GET https://api.doitong.com/v1/models/{model_id}` lisää täydellisen syötteen ja tulosteen JSON Scheman, kanoniset parametrien nimet, hintasäännöt ja esimerkkisyötteen. Tuntematon `category` tai `mode` palauttaa virheen `400 invalid_parameter`.

## Mallin suorittaminen

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

- Runko on mallin syöte, JSON-objekti. Jokaisella mallisivulla luetellaan sen parametrit.
- Syöte tarkistetaan ennen veloitusta. Virheellinen syöte palauttaa `422 invalid_input` -virheen ja ilmoittaa ongelmallisen `param`-parametrin, eikä siitä veloiteta.
- `?wait=N` (enintään 20 sekuntia) pitää kutsun avoinna, kunnes pyyntö valmistuu tai aika loppuu.
- `?webhook_url=https://…` lähettää allekirjoitetun POST-pyynnön kyseiseen URL-osoitteeseen, kun pyyntö valmistuu (katso [Webhookit](https://doitong.com/developers/docs/webhooks)).
- `?storage=permanent` tai `?storage=temporary` määrittää, kuinka kauan tulostetiedostoja säilytetään; ilman tätä käytetään tilin asetusta (katso [Tiedostojen sijainti](#storage)).

Vastaus on `202 Accepted`, kun pyyntö on vielä käynnissä, ja `200 OK`, kun se valmistui odotusajan kuluessa (tai kyseessä on uudelleentoisto, katso alla). `Location`- ja `Doitong-Request-Id`-otsakkeet sisältävät pyynnön URL-osoitteen ja tunnuksen.

## Tilat

Pyynnön elinkaari: `queued` → `running` → `succeeded` | `failed` | `canceled` (lopullinen; epäonnistuneet ja perutut hyvitetään).

| Tila | Merkitys | Lopullinen |
|---|---|---|
| `queued` | Hyväksytty ja veloitettu, odottaa työntekijää. `queue_position` voi näyttää paikan jonossa. | ei |
| `running` | Malli generoi tulostetta. | ei |
| `succeeded` | Valmis. `outputs` luettelee tiedostot. | kyllä |
| `failed` | Malli tai rajoitus keskeytti sen. `error` kertoo syyn. API-krediitit hyvitetään. | kyllä |
| `canceled` | Peruutettu ennen tuloksen tuottamista. API-krediitit hyvitetään. | kyllä |

Aikarajan ylittävä pyyntö epäonnistuu koodilla `timeout`, ja se hyvitetään: kuville 15 minuuttia, videolle 60 minuuttia, äänelle ja kaikelle muulle 30 minuuttia.

## Pyyntöobjekti

```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` on sama jokaiselle mallille: yksi merkintä kutakin luotua tiedostoa kohti, ja siinä ovat `type` (`image`, `video`, `audio`, `file` tai `3d`), tallennustilamme `url`, `content_type` sekä tunnettaessa `file_size`, `width`, `height` ja `duration`.
- `output` on mallin oma tulosobjekti (sen kentät luetellaan kullakin mallisivulla), jossa ovat samat URL-osoitteet.
- `storage` kertoo, miten tiedostot säilytetään: `mode` (`permanent` tai `temporary`), tallennettujen tavujen määrä `bytes`, `expires_at` (milloin väliaikainen tiedosto poistetaan, pysyville tiedostoille `null`) ja `expired` (`true`, kun tiedostot ovat poistuneet).
- `cost.credits` on kutsun hinta API-krediitteinä (`cost.usd` USD-valuuttana), `cost.charged` API-saldosta veloitettu määrä ja `cost.refunded` takaisin hyvitetty määrä. `metered`-mallilla `cost.credits` on alussa varattu enimmäismäärä (`cost.held`); kun ajo onnistuu, `cost.settled` kertoo käytetyn määrän ja enimmäismäärän loppuosa on `cost.refunded`-kentässä (katso [Käytön mukaan veloitettavat](https://doitong.com/developers/docs/pricing#metered)).
- Kun pyyntö epäonnistuu, `error` on `{ "type": …, "code": …, "message": … }`.

## Pyynnön lukeminen

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

- `?wait=N` (enintään 20 sekuntia) tekee pitkän kyselyn: kutsu palautuu heti, kun pyyntö on lopullisessa tilassa, tai N sekunnin kuluttua nykyisen tilan kanssa. Kutsun toistaminen tällä tavalla on yksinkertaisin tapa odottaa tulosta.
- `?logs=1` lisää mallin etenemislokin rivit (viimeiset 50) `logs`-kenttään.

Voit lukea vain oman tilisi pyyntöjä; mikä tahansa muu tunnus palauttaa `404 request_not_found`.

## Pyyntöjen luettelo

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

Uusimmat ensin. `limit` on 1–100 (oletus 20), ja `status` sekä `model` suodattavat tuloksia. Vastaus on `{ "object": "list", "data": [ … ], "has_more": true, "next_cursor": "req_…" }`; välitä `cursor=<next_cursor>` seuraavaa sivua varten.

## Pyynnön peruuttaminen

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

- Ennen mallin käynnistymistä peruutettu: tilaksi tulee `canceled`, API-krediitit hyvitetään ja saat vastauksen `200`.
- Jos generointi on jo käynnissä: peruutus välitetään eteenpäin ja saat vastauksen `202` sekä `"cancel_requested": true`. Jos malli valmistuu silti, pyyntö onnistuu normaalisti ja siitä veloitetaan.
- Jos pyyntö on jo lopullisessa tilassa: `409 not_cancelable` (jo `canceled`-tilassa oleva pyyntö palauttaa yksinkertaisesti `200`).

## Pyynnön tiedostojen poistaminen

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

Poistaa pyyntöön liittyvät tulostetiedostojen kopiot nyt ja lopettaa niiden tallennusveloituksen. Vastaus on pyyntöobjekti, jossa on `storage.expired: true`; sen URL-osoitteet säilyvät tietueessa, mutta eivät enää toimi. Kutsun toistaminen ei muuta mitään (`200`). Vielä `queued`- tai `running`-tilassa olevalla pyynnöllä ei ole tiedostoja: `409 request_active`. Edellyttää käyttöoikeutta `models:run`.

## Idempotenssi: yritä uudelleen ilman kaksinkertaista veloitusta

Verkot voivat kaatua. Lähetä ajo turvallisesti uudelleen välittämällä `Idempotency-Key`-otsake (mikä tahansa enintään 255 merkin merkkijono, yksilöllinen operaatiota kohti, esimerkiksi oma tilausnumerosi):

- Sama avain ja sama runko kuin aiemmin: saat alkuperäisen pyynnön takaisin (`200`, otsake `Idempotent-Replayed: true`), eikä uudelleen veloiteta.
- Sama avain ja runko ajon jälkeen, joka epäonnistui ennen mallin saavuttamista (`upstream_error` tai `internal_error` lähetyksen yhteydessä, `insufficient_credits`, `budget_exceeded`, `too_many_inflight`): mitään ei tuotettu eikä veloitettu, joten uudelleenyritys suorittaa mallin uudelleen epäonnistuneen vastauksen palauttamisen sijaan.
- Sama avain eri rungon kanssa: `409 idempotency_mismatch`.
- Avaimet koskevat niitä lähettänyttä API-avainta.

## Tiedostojen sijainti

Jokainen tulostetiedosto kopioidaan tallennustilaamme ennen kuin pyyntö merkitään `succeeded`-tilaan, joten `outputs`-kentän URL-osoitteet ovat omilla palvelimillamme ja voit linkittää niihin suoraan. Säilytyksen kesto on sinun valintasi:

| Tila | Kesto | Hinta |
|---|---|---|
| `permanent` (oletus) | Kunnes poistat ne | 100 API-krediittiä (0,10 $) gigatavua kohti kuukaudessa, veloitetaan päivittäin API-saldosta |
| `temporary` | 7 päivää, minkä jälkeen poistetaan | Maksuton |

- Tilin asetus määrittää uusien pyyntöjen säilytyksen: "Säilytä tiedostot ikuisesti"-kytkin [hallintapaneelissa](https://doitong.com/developers/dashboard#balance) tai `PATCH https://api.doitong.com/v1/account/storage` määrityksellä `{"mode": "temporary"}`. `GET https://api.doitong.com/v1/account` näyttää asetuksen `storage`-kentässä säilyttämiesi tavujen määrän ja kuukausiarvion kanssa.
- Ajon `?storage=permanent|temporary` (MCP:n `run`-työkalun `storage`-argumentti) ohittaa asetuksen kyseisen ajon osalta.
- Asetuksen muuttaminen ei koskaan vaikuta jo olemassa oleviin tiedostoihin; poista ne komennolla [`DELETE /requests/{id}/files`](#delete-files).
- Jos API-saldo ei riitä tallennustilaan, mitään ei veloiteta ja saat sähköpostin: lisää saldoa 30 päivän kuluessa, tai säilytettävät tiedostot muutetaan väliaikaisiksi ja poistetaan 7 päivää myöhemmin.

Harvinaisessa tapauksessa, jossa kopiointi epäonnistuu, merkinnässä on `"stored": false` ja URL-osoite on alkuperäinen, lyhytkestoinen osoite: lataa tiedosto pian.
