# Erros

> A estrutura do erro, cada código de erro e como repetir com segurança.

Erros usam códigos HTTP normais e um corpo JSON com um `code` estável que você pode verificar no seu código, e um `message` escrito para pessoas.

```json
{
  "error": {
    "code": "validation_error",
    "message": "Some fields are invalid.",
    "issues": [
      {
        "path": "products.0.listPrice",
        "message": "Too small: expected number to be >=0"
      }
    ]
  }
}
```

`issues` existe apenas para `validation_error`. Cada problema tem `path` apontando para o campo, com posições de lista contadas a partir de 0.

## Códigos de erro

| Status | Código                | O que aconteceu                                                                                              | O que fazer                                                                            |
| ------ | --------------------- | ------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------- |
| 400    | `validation_error`    | Um parâmetro de consulta ou campo do corpo está faltando ou inválido.                                        | Corrija os campos listados em `issues`.                                                |
| 400    | `invalid_json`        | O corpo não é JSON válido.                                                                                   | Envie JSON com `Content-Type: application/json`.                                       |
| 400    | `invalid_request`     | A solicitação é válida, mas não é permitida no momento, por exemplo, marcando um novo pedido como concluído. | Leia `message`; não tente novamente sem alterações.                                    |
| 401    | `unauthorized`        | Chave de API ausente, desconhecida ou revogada.                                                              | Verifique o cabeçalho `Authorization: Bearer` e que a chave ainda está ativa.          |
| 401    | `key_owner_removed`   | A pessoa que criou a chave saiu do workspace.                                                                | Crie uma nova chave a partir de alguém que ainda tenha acesso.                         |
| 403    | `insufficient_scope`  | Uma chave somente leitura tentou gravar.                                                                     | Use uma chave de Leitura e Gravação.                                                   |
| 403    | `read_only`           | Gravações via API estão indisponíveis na atual entidade Free do workspace.                                   | O proprietário gerencia o plano no site. As chaves existentes ainda leem.              |
| 403    | `forbidden`           | A pessoa que criou a chave não tem permissão para fazer isso.                                                | Pergunte ao proprietário do workspace, ou crie uma chave de alguém com essa permissão. |
| 403    | `workspace_suspended` | TradeCatalog suspendeu o workspace. O proprietário foi notificado sobre o motivo.                            | As chaves funcionam novamente quando a suspensão é levantada.                          |
| 404    | `not_found`           | Nenhum endpoint, produto, cliente, pedido ou alteração de preço neste workspace.                             | Verifique o id, SKU ou código da conta.                                                |
| 405    | `method_not_allowed`  | O caminho existe, mas não com este método.                                                                   | Use um método do cabeçalho `Allow`.                                                    |
| 429    | `rate_limited`        | Mais de 120 solicitações por minuto com esta chave.                                                          | Espere `Retry-After` segundos (60), depois tente novamente.                            |
| 500    | `internal_error`      | Algo deu errado do nosso lado.                                                                               | Tente novamente com backoff. Se continuar acontecendo, entre em contato com o suporte. |

IDs de outro workspace sempre retornam `404 not_found`, nunca dados de terceiros.

## Tentativa de novo

Tente novamente as respostas `429` e `5xx` com backoff. Não tente novamente outras respostas `4xx`: elas falharão da mesma forma.

Todas as gravações da API são seguras para repetir: `PUT` corresponde às linhas pelo SKU ou código de conta, e `PATCH /orders/{id}` falha com `invalid_request` se o pedido já tiver avançado. Assim, uma nova tentativa após um timeout de rede não duplicará nada.

```js
async function api(path, init = {}, attempt = 0) {
  const res = await fetch(`https://tradecatalog.app/api/v1${path}`, {
    ...init,
    headers: {
      Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}`,
      'Content-Type': 'application/json',
      ...init.headers,
    },
  })
  if ((res.status === 429 || res.status >= 500) && attempt < 5) {
    const wait = Number(res.headers.get('Retry-After')) || 2 ** attempt
    await new Promise((resolve) => setTimeout(resolve, wait * 1000))
    return api(path, init, attempt + 1)
  }
  const body = await res.json()
  if (!res.ok) {
    const error = new Error(`${body.error.code}: ${body.error.message}`)
    error.status = res.status
    error.code = body.error.code
    error.issues = body.error.issues
    throw error
  }
  return body
}
```

## Mensagens comuns

| Requisição                                         | Status e mensagem                                              |
| -------------------------------------------------- | -------------------------------------------------------------- |
| `GET /prices` com SKU desconhecido                 | `404` “Nenhum produto com SKU HX-9999”                         |
| Qualquer endpoint com cliente desconhecido         | `404` “Cliente OAK99 não encontrado”                           |
| `PATCH /orders/{id}` novo → concluído              | `400` “Um pedido recebido não pode ser marcado como concluído” |
| `PATCH /orders/{id}` para cancelado sem observação | `400` “Forneça um motivo para o cancelamento”                  |
| `PUT /products` com o mesmo SKU duas vezes         | `400` erro de validação “SKU duplicado hx-8510”                |
