# Richieste

Una richiesta è una chiamata a un modello. Ha un id (`req_…`), uno stato, il relativo costo in crediti API (1000 = 1 USD) e, quando
va a buon fine, i file generati. Lo stesso oggetto viene restituito da ogni endpoint qui sotto, per ogni modello.

## Trovare un modello

Il catalogo di tutti i 1496 modelli è un JSON pubblico (non serve una chiave):

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

| Parametro di query | Significato |
|---|---|
| `q` | Parole che devono comparire tutte nel nome, nell'id, nel produttore o nei tag, ad esempio `kling 3`. |
| `category` | Un id di categoria, ad esempio `text-to-video` o `upscale`. `GET https://api.doitong.com/v1/categories` elenca tutte le 21 categorie con i relativi conteggi. |
| `lab` | Il produttore del modello, per nome o id, ad esempio `Google` o `black-forest-labs`. |
| `family` | Un id `family` di una riga precedente: ogni variante di un modello (pro, fast, image-to-video, …). |
| `mode` | `exact` (il prezzo viene calcolato dall'input), `measured` (dalla durata o dalle dimensioni dei file di input), `estimate` (un prezzo stimato per esecuzione) o `metered` (addebitato in base all'utilizzo effettivo, fino a un massimo per esecuzione). |
| `limit`, `cursor` | Dimensione della pagina (da 1 a 100, predefinito 50) e `next_cursor` della pagina precedente. |

Ogni riga contiene `id`, `name`, `lab`, `category`, `family`, `summary`, `tags`, `output_kind`, `docs_url` e un oggetto
`price` (vedi [Prezzi](https://doitong.com/developers/docs/pricing#price-objects)). `GET https://api.doitong.com/v1/models/{model_id}` aggiunge lo
JSON Schema completo dell'input e dell'output, i nomi canonici dei parametri, le regole di prezzo e un esempio di input. Una
`category` o un `mode` sconosciuti restituiscono `400 invalid_parameter`.

## Eseguire un modello

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

- Il corpo è l'input del modello, un oggetto JSON. Ogni pagina del modello elenca i relativi parametri.
- L'input viene verificato prima di qualsiasi addebito. Un input non valido restituisce `422 invalid_input` con il
  `param` responsabile e non costa nulla.
- `?wait=N` (fino a 20 secondi) mantiene la chiamata in attesa finché la richiesta non termina o il tempo non scade.
- `?webhook_url=https://…` invia un `POST` firmato a quell'URL quando la richiesta termina (vedi [Webhook](https://doitong.com/developers/docs/webhooks)).
- `?storage=permanent` o `?storage=temporary` sceglie per quanto tempo conservare i file di output; senza questo parametro si applica
  l'impostazione dell'account (vedi [Dove vengono conservati i file](#storage)).

La risposta è `202 Accepted` mentre la richiesta è ancora in esecuzione e `200 OK` quando è terminata entro il tempo di attesa (o
quando è una riproduzione, vedi sotto). Gli header `Location` e `Doitong-Request-Id` contengono l'URL e l'id della richiesta.

## Stati

Ciclo di vita della richiesta: `queued` → `running` → `succeeded` | `failed` | `canceled` (finale; gli elementi non riusciti e annullati vengono rimborsati).

| Stato | Significato | Finale |
|---|---|---|
| `queued` | Accettata e addebitata, in attesa di un worker. `queue_position` può mostrare la posizione in coda. | no |
| `running` | Il modello sta generando. | no |
| `succeeded` | Completata. `outputs` elenca i file. | sì |
| `failed` | Il modello o un limite l'ha interrotta. `error` indica il motivo. I crediti API vengono rimborsati. | sì |
| `canceled` | Annullata prima di produrre un risultato. I crediti API vengono rimborsati. | sì |

Una richiesta che supera il limite di tempo termina con il codice `timeout` e viene rimborsata: 15 minuti per le immagini,
60 minuti per i video, 30 minuti per l'audio e tutto il resto.

## L'oggetto richiesta

```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` è uguale per ogni modello: una voce per ogni file generato con `type` (`image`, `video`, `audio`,
  `file` o `3d`), un `url` sulla nostra archiviazione, `content_type` e, quando noti, `file_size`, `width`, `height`,
  `duration`.
- `output` è l'oggetto risultato del modello (i relativi campi sono elencati in ogni pagina del modello) con gli stessi URL.
- `storage` indica come vengono conservati i file: `mode` (`permanent` o `temporary`), `bytes` archiviati, `expires_at` (quando un
  file temporaneo viene eliminato, `null` per quelli permanenti) e `expired` (`true` una volta eliminati i file).
- `cost.credits` è il prezzo della chiamata in crediti API (`cost.usd` in USD), `cost.charged` è quanto è stato addebitato dal
  saldo API, `cost.refunded` è quanto è stato restituito. Per un modello `metered`, `cost.credits` è il massimo trattenuto all'inizio
  (`cost.held`); quando l'esecuzione va a buon fine, `cost.settled` indica il costo effettivo dell'utilizzo e il resto del massimo è
  in `cost.refunded` (vedi [Addebito in base all'utilizzo](https://doitong.com/developers/docs/pricing#metered)).
- Quando una richiesta non va a buon fine, `error` è `{ "type": …, "code": …, "message": … }`.

## Leggere una richiesta

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

- `?wait=N` (fino a 20 secondi) esegue un long polling: la chiamata restituisce il risultato non appena la richiesta è finale oppure
  dopo N secondi con lo stato corrente. Ripetere questa chiamata è il modo più semplice per attendere un risultato.
- `?logs=1` aggiunge le righe del log di avanzamento del modello (le ultime 50) come `logs`.

Puoi leggere solo le richieste del tuo account; qualsiasi altro id restituisce `404 request_not_found`.

## Elencare le richieste

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

Dalla più recente alla meno recente. `limit` va da 1 a 100 (predefinito 20), mentre `status` e `model` filtrano i risultati. La risposta è
`{ "object": "list", "data": [ … ], "has_more": true, "next_cursor": "req_…" }`; passa `cursor=<next_cursor>` per
la pagina successiva.

## Annullare una richiesta

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

- Annullata prima dell'avvio del modello: lo stato diventa `canceled`, i crediti API vengono rimborsati e ricevi `200`.
- Già in fase di generazione: l'annullamento viene inoltrato e ricevi `202` con `"cancel_requested": true`. Se il modello
  termina comunque, la richiesta va a buon fine normalmente e viene addebitata.
- Già finale: `409 not_cancelable` (una richiesta già `canceled` restituisce semplicemente `200`).

## Eliminare i file di una richiesta

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

Elimina subito le nostre copie dei file di output della richiesta e interrompe il relativo addebito di archiviazione. La risposta è l'oggetto
richiesta con `storage.expired: true`; gli URL restano nel record ma non funzionano più. Chiamare di nuovo l'endpoint non cambia nulla
(`200`). Una richiesta ancora `queued` o `running` non ha file: `409 request_active`. Richiede `models:run`.

## Idempotenza: riprovare senza pagare due volte

Le reti possono interrompersi. Per riprovare un'esecuzione in sicurezza, invia un header `Idempotency-Key` (una stringa qualsiasi di massimo
255 caratteri, univoca per operazione, ad esempio il tuo id dell'ordine):

- Stessa chiave e stesso corpo di prima: ricevi di nuovo la richiesta originale (`200`, header
  `Idempotent-Replayed: true`) e non viene effettuato un nuovo addebito.
- Stessa chiave e corpo dopo un'esecuzione non riuscita prima di raggiungere il modello (`upstream_error` o `internal_error` all'invio,
  `insufficient_credits`, `budget_exceeded`, `too_many_inflight`): non è stato prodotto nulla e non è stato addebitato nulla, quindi il
  nuovo tentativo esegue di nuovo il modello invece di restituire l'errore.
- Stessa chiave con un corpo diverso: `409 idempotency_mismatch`.
- Le chiavi sono associate alla chiave API che le ha inviate.

## Dove vengono conservati i file

Ogni file di output viene copiato nella nostra archiviazione prima che la richiesta venga contrassegnata come `succeeded`, quindi gli URL in
`outputs` si trovano sui nostri host e puoi collegarti direttamente a essi. La durata di conservazione dipende da te:

| Modalità | Durata | Prezzo |
|---|---|---|
| `permanent` (predefinito) | Fino a quando li elimini | 100 crediti API (0,10 $) per GB al mese, addebitati ogni giorno dal saldo API |
| `temporary` | 7 giorni, poi eliminati | Gratuito |

- L'impostazione dell'account decide il comportamento per le nuove richieste: l'interruttore "Conserva i file per sempre" nella
  [dashboard](https://doitong.com/developers/dashboard#balance) oppure `PATCH https://api.doitong.com/v1/account/storage` con
  `{"mode": "temporary"}`. `GET https://api.doitong.com/v1/account` la mostra sotto `storage`, insieme ai byte conservati e alla
  stima mensile.
- `?storage=permanent|temporary` durante un'esecuzione (l'argomento `storage` dello strumento MCP `run`) sostituisce l'impostazione per quella esecuzione.
- Modificare l'impostazione non tocca mai i file già presenti; eliminali con
  [`DELETE /requests/{id}/files`](#delete-files).
- Quando il saldo API non può pagare l'archiviazione, non viene addebitato nulla e ricevi un'email: effettua una ricarica entro
  30 giorni, altrimenti i file conservati diventano temporanei e vengono eliminati 7 giorni dopo.

Nel raro caso in cui la nostra copia non riesca, la voce contiene `"stored": false` e l'URL è quello originale, con durata limitata:
downloadalo presto.
