# Erros

Todos os endpoints falham da mesma forma: um estado HTTP e um envelope JSON.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_input",
    "message": "duration must be one of 5, 10.",
    "param": "duration",
    "details": [ { "param": "duration", "message": "duration must be one of 5, 10." } ],
    "request_id": null,
    "doc_url": "https://doitong.com/developers/docs/errors#invalid_input"
  }
}
```

| Campo | Significado |
|---|---|
| `type` | Classe geral do erro. Decida o que fazer com base neste campo. |
| `code` | Motivo exato, estável e legível por máquinas. Cada código tem uma secção abaixo; `doc_url` aponta para ela. |
| `message` | Explicação legível, segura para registar ou apresentar a um programador. |
| `param` | O parâmetro de entrada ou cabeçalho com problemas, quando aplicável. |
| `details` | Para erros de entrada, todos os problemas encontrados: `[{ "param", "message" }]`. |
| `request_id` | O pedido a que diz respeito, quando existe. |

Não é cobrado nada por uma chamada que devolva um erro. Um pedido que falhe *depois* de ser aceite mantém o estado
`failed`, contém `error: { "type", "code", "message" }` no objeto do pedido e é reembolsado automaticamente.

## Tipos

| Tipo | Estado HTTP | O que fazer |
|---|---|---|
| `invalid_request` | 400, 413 ou 422 | Corrija o pedido. Repetir a mesma chamada falha novamente. |
| `authentication_error` | 401 | Envie uma chave válida em `Authorization: Bearer <key>`. |
| `permission_error` | 403 | Use uma chave com o âmbito necessário. |
| `not_found` | 404 | Verifique o id do modelo ou do pedido. |
| `insufficient_credits` | 402 | Faça um carregamento do saldo da API (`top_up_url` no erro). |
| `budget_exceeded` | 402 | O orçamento da própria chave foi esgotado. Final: peça ao proprietário da chave para o aumentar. |
| `conflict` | 409 | O recurso não está num estado que permita esta chamada. |
| `rate_limited` | 429 | Aguarde `Retry-After` segundos e tente novamente. |
| `upstream_error` | 502 | O backend do modelo falhou. É seguro repetir com a mesma `Idempotency-Key`: será executado novamente; não foi cobrado. |
| `service_unavailable` | 503 | A API está pausada ou uma dependência está indisponível. Tente mais tarde. |
| `internal_error` | 500 | Um erro nosso. Tente novamente; se persistir, contacte o suporte com a hora e o `request_id`. |

## Códigos

### `invalid_request`

Pedido genérico malformado (400).

### `invalid_json`

O corpo não é um JSON válido (400).

### `invalid_body`

O corpo é JSON válido, mas não é um objeto; a entrada do modelo tem de ser um objeto JSON (400).

### `body_too_large`

O corpo é maior do que 16 MB (413). Carregue ficheiros grandes e passe o respetivo URL (consulte [Ficheiros](https://doitong.com/developers/docs/files)).

### `invalid_parameter`

Um parâmetro de consulta tem um valor incorreto, por exemplo `limit` fora de 1 a 100, `wait` não é um número, um
`status` ou `category` desconhecido, ou `storage` diferente de `permanent` / `temporary` (400). `param` identifica-o.

### `invalid_category`

`GET /openapi.json?category=` indica uma categoria inexistente (400). `GET https://api.doitong.com/v1/categories` apresenta-as.

### `invalid_cursor`

O `cursor` de uma chamada de listagem não pertence a esta lista (400). Comece novamente sem cursor.

### `invalid_idempotency_key`

O cabeçalho `Idempotency-Key` está vazio ou tem mais de 255 caracteres (400).

### `invalid_arguments`

Uma chamada de ferramenta MCP tem um argumento em falta ou malformado (apenas MCP). `param` identifica o argumento.

### `invalid_input`

A entrada do modelo não passa a validação (422): um parâmetro desconhecido (a mensagem sugere o nome válido mais próximo),
um parâmetro obrigatório em falta, um tipo incorreto, um valor fora da lista ou intervalo permitido, ou os nomes canónico e
nativo fornecidos com valores diferentes. `param` é o primeiro parâmetro com problemas e `details` apresenta todos.
Não é cobrado nada.

### `unsupported_file`

Um ficheiro tem um tipo que não aceitamos (422), por exemplo uma extensão não suportada ou um `content_type`
que não corresponde à extensão.

### `invalid_webhook_url`

`webhook_url` não é um URL público `https://` (422). Endereços privados, locais e `http://` simples são recusados.

### `missing_api_key`

O endpoint precisa de uma chave de API e nenhuma foi enviada (401).

### `invalid_api_key`

A chave é desconhecida, foi revogada ou expirou (401).

### `insufficient_scope`

A chave não tem o âmbito necessário para esta chamada (403), por exemplo `models:run` para executar, ou `models:read` para ler
pedidos e o saldo. Consulte [Autenticação](https://doitong.com/developers/docs/authentication#scopes).

### `account_disabled`

A conta está encerrada ou suspensa (403). As respetivas chaves já não funcionam.

### `not_found`

O caminho não existe (404).

### `model_not_found`

Não existe nenhum modelo público com este id (404). Liste os modelos com `GET https://api.doitong.com/v1/models`.

### `request_not_found`

Não existe na sua conta nenhum pedido com este id (404). Os pedidos de outras contas nunca são visíveis.

### `insufficient_credits`

O **saldo da API** da conta (créditos de API, 1000 créditos da API = 1 $ — não os créditos das aplicações Doitong) não cobre o
preço desta chamada (402). A resposta é enviada antes de qualquer cobrança. O erro contém `top_up_url`; adicione dinheiro
em [https://doitong.com/developers/dashboard#balance](https://doitong.com/developers/dashboard#balance) e tente novamente.

```json
{ "error": { "type": "insufficient_credits", "code": "insufficient_credits",
             "message": "This request costs 560 API credits ($0.56); the API balance is 120 API credits ($0.12). Top up at https://doitong.com/developers/dashboard#balance",
             "top_up_url": "https://doitong.com/developers/dashboard#balance", "doc_url": "https://doitong.com/developers/docs/errors#insufficient_credits" } }
```

### `budget_exceeded`

A chamada excederia o próprio orçamento da chave de API em créditos de API (402). O orçamento é definido pelo proprietário
da chave; repetir não ajuda até que este o aumente.

### `conflict`

A chamada entra em conflito com o estado atual do recurso (409).

### `idempotency_mismatch`

A `Idempotency-Key` já foi usada com um corpo diferente (409). Use uma chave nova para uma operação nova.

### `idempotency_in_progress`

Está a ser criado um pedido com a mesma `Idempotency-Key` (409). Tente novamente dentro de instantes para o obter.

### `request_active`

O pedido ainda está `queued` ou `running`, pelo que ainda não tem ficheiros para eliminar (409). Elimine-os quando terminar.

### `not_cancelable`

O pedido já está `succeeded` ou `failed` e não pode ser cancelado (409).

### `rate_limited`

A chave fez demasiados pedidos na janela atual (429). Consulte os cabeçalhos `X-RateLimit-*` e `Retry-After`.

### `too_many_inflight`

A conta já tem 10 pedidos `queued` ou `running` (429). Inicie o próximo quando um deles terminar.

### `upstream_error`

O backend do modelo recusou ou não conseguiu processar o pedido (502 durante a execução, ou `failed` com este código no pedido). Os créditos de API são reembolsados. Se o próprio backend rejeitar a entrada, a chamada devolve `422 invalid_input` com a respetiva mensagem.

### `upstream_lost`

O backend do modelo já não conhece o pedido, pelo que nunca chegará um resultado. Termina como `failed` com este código
(tipo `upstream_error`) e é reembolsado. Execute-o novamente.

### `timeout`

O pedido excedeu o limite (15 minutos para imagens, 60 para vídeo, 30 nos restantes casos) e foi interrompido. Termina como
`failed` com este código e é reembolsado.

### `service_unavailable`

A API está temporariamente pausada ou uma dependência, como os carregamentos de ficheiros, está indisponível (503). Tente mais tarde.

### `internal_error`

Ocorreu uma falha do nosso lado (500). Tente novamente; se persistir, contacte o suporte.

### `charge_failed`

Não foi possível cobrar a conta devido a um problema interno (500). O pedido é marcado como `failed`; nada foi debitado. Tente novamente.

### `pricing_unavailable`

O preço do modelo não está configurado, pelo que não pode ser apresentado nem executado neste momento (500).
