# Como tratar erros

# Como tratar erros

:::note
A **lista completa** de códigos vive na [Referência da API](/referencia), gerada a partir do
próprio serviço. Esta página explica como tratá-los — de propósito ela não repete a lista, porque
uma segunda cópia divergiria da primeira.
:::

## A regra de ouro

**Confira `success`, não o status HTTP.**

Vários desfechos de falha chegam com **HTTP 200 e `success: false`**. Se o seu código faz
`if (response.ok)`, ele vai tratar como sucesso uma consulta que não trouxe dado nenhum.

```js
const r = await fetch(url, opcoes).then((x) => x.json())

if (!r.success) {
  // r.code diz o que aconteceu. Ramifique AQUI.
  switch (r.code) {
    case 'INSUFFICIENT_BALANCE':
    case 'CREDIT_LIMIT_EXCEEDED':
      return avisarFinanceiro(r)
    case 'PROVIDER_TIMEOUT':
    case 'PROVIDER_DOWN':
      return reenfileirar(r)          // não cobrou, ou foi estornado
    case 'MISSING_REQUIRED_FIELDS':
    case 'INVALID_DOCUMENT':
      return corrigirEntrada(r)       // não cobrou
    default:
      return registrar(r)
  }
}
```

**Ramifique no `code`, nunca na mensagem.** O `code` é contrato; o texto de `error` pode mudar.

## Isso cobrou?

| Situação | Cobrou? |
| --- | --- |
| `success: false` por entrada inválida ou produto não habilitado | **Não.** A validação roda antes da cobrança. |
| `PROVIDER_TIMEOUT`, `NETWORK_ERROR` | Cobrou e **foi estornado**. |
| `status: "failed"` no `GET /status` | Se houve cobrança, o campo `refunded` mostra o estorno. |
| `success: true` | Cobrou. |

Na dúvida, `GET /balance` responde o saldo atual, e não cobra.

## Os quatro que enganam

**`NOT_ALLOWLISTED`, `NO_PROVIDER`, `PROVIDER_DOWN`, `PROVIDER_TIMEOUT`** chegam com **HTTP 200**.
São exatamente os que um `if (response.ok)` deixa passar. É por eles que a regra de ouro existe.

## Credencial

`MISSING_API_KEY`, `INVALID_API_KEY_FORMAT`, `INVALID_API_KEY` e `API_KEY_EXPIRED` são as respostas
de credencial. Uma diferença que vale conhecer: no **`GET /status`**, "header ausente" e "formato
inválido" chegam fundidos num único `INVALID_API_KEY`, enquanto nos outros endpoints vêm separados.

:::caution[Um caso conhecido, e datado]
Hoje, no **`GET /lookup`**, uma falha interna nossa pode chegar até você como
`401 "API key inválida"` em vez de um erro de servidor.

Se o `GET /lookup` responder 401 e a **mesma chave funcionar em outro endpoint** (`GET /balance`,
por exemplo), a sua credencial está boa — o problema é nosso. Não a rotacione por causa disso.

Documentado em 2026-08-23. É um comportamento que pretendemos corrigir; enquanto não corrigimos,
preferimos que você saiba.
:::

## Sobre limites

Não há limite por minuto no contrato desta API, e nenhum código de erro de cota. **O saldo da
carteira é o limite**: não há franquia nem teto além dele.

A camada de borda pode recusar tráfego em volume anormal, com `502` e
`code: "UPSTREAM_UNAVAILABLE"` — isso é indisponibilidade temporária, não cota, e a resposta certa
é repetir com um intervalo.
