> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usevext.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Erros

> Um envelope único, sete famílias de tipo e o catálogo estável de códigos.

Todo erro — inclusive os que não previmos — tem a mesma forma:

```json theme={null}
{
  "error": {
    "type": "invalid_request_error",
    "code": "amount_below_minimum",
    "message": "O valor está abaixo do mínimo permitido.",
    "details": {}
  }
}
```

<Warning>
  Baseie a sua lógica no `code`. Ele é contrato e não muda. A `message` é escrita para gente ler e
  pode ser reescrita a qualquer momento — inclusive para ficar melhor. Quando isso acontece, um `if`
  que compara a mensagem para de funcionar sem avisar.
</Warning>

## As sete famílias

O `type` responde de quem é o problema e o que fazer. É por ele que você decide o comportamento;
o `code` diz qual mensagem mostrar.

| `type`                  | De quem é                 | O que fazer                                                   |
| ----------------------- | ------------------------- | ------------------------------------------------------------- |
| `authentication_error`  | Sua chave                 | Troque a chave. Não repita                                    |
| `permission_error`      | Seu escopo                | Gere uma chave com o escopo certo. Não repita                 |
| `invalid_request_error` | Sua chamada               | Corrija os dados. Repetir igual dá o mesmo erro               |
| `idempotency_error`     | Sua chave de idempotência | Chave nova, ou repita em instantes                            |
| `not_found_error`       | O recurso                 | Confira o código. Não repita                                  |
| `rate_limit_error`      | Ritmo                     | Espere o `Retry-After` e repita                               |
| `api_error`             | **Nosso**                 | Repita com a mesma `Idempotency-Key`. Não reescreva a chamada |

A divisão que importa na prática: `invalid_request_error` se corrige mudando a chamada,
`authentication_error` trocando a chave, e `api_error` é nosso — repita, não reescreva.

## `details`

`details` é sempre objeto, mesmo vazio. Em `validation_failed`, ele traz os campos recusados e as
mensagens de cada um:

```json theme={null}
{
  "error": {
    "type": "invalid_request_error",
    "code": "validation_failed",
    "message": "Alguns campos não passaram na validação.",
    "details": {
      "amount": ["O valor deve ser um inteiro em centavos (R$ 10,00 = 1000)."],
      "customer.name": ["O campo nome é obrigatório."]
    }
  }
}
```

Em `insufficient_scope`, ele traz `required_ability` e a lista de `abilities` que a chave tem.

## Catálogo de códigos

Todos são estáveis. Se um código novo aparecer, ele entra nesta tabela — nenhum destes muda de
significado.

| `code`                        | HTTP | `type`                  | O que fazer                                                                |
| ----------------------------- | ---- | ----------------------- | -------------------------------------------------------------------------- |
| `missing_api_key`             | 401  | `authentication_error`  | Envie `Authorization: Bearer sk_…`                                         |
| `invalid_api_key`             | 401  | `authentication_error`  | Confira se copiou a chave inteira e o ambiente certo                       |
| `revoked_api_key`             | 401  | `authentication_error`  | A chave existiu e foi desligada. Gere outra em **Desenvolvedores**         |
| `expired_api_key`             | 401  | `authentication_error`  | Gere outra em **Desenvolvedores**                                          |
| `insufficient_scope`          | 403  | `permission_error`      | A chave é válida, falta o escopo. `details.required_ability` diz qual      |
| `resource_not_found`          | 404  | `not_found_error`       | O recurso não existe — ou é de outra conta                                 |
| `idempotency_key_too_long`    | 400  | `invalid_request_error` | Encurte a chave para 255 caracteres                                        |
| `idempotency_key_reused`      | 409  | `idempotency_error`     | A chave já foi usada com outro corpo. Use uma chave nova                   |
| `idempotency_key_in_progress` | 409  | `idempotency_error`     | A primeira ainda está em voo. Repita em instantes                          |
| `validation_failed`           | 422  | `invalid_request_error` | `details` traz campo → mensagens. Corrija e reenvie                        |
| `amount_below_minimum`        | 422  | `invalid_request_error` | Valor abaixo do mínimo permitido                                           |
| `amount_above_maximum`        | 422  | `invalid_request_error` | Valor acima do máximo permitido                                            |
| `items_do_not_match_amount`   | 422  | `invalid_request_error` | A soma de `quantity * amount` dos itens tem que bater com `amount`         |
| `seller_not_approved`         | 422  | `invalid_request_error` | Nada na chamada resolve. O caminho é o painel                              |
| `provider_rejected`           | 422  | `invalid_request_error` | Confira os dados do comprador e o valor                                    |
| `charge_not_refundable`       | 422  | `invalid_request_error` | Só cobrança paga é estornável                                              |
| `exceeds_remaining`           | 422  | `invalid_request_error` | Peça no máximo o saldo estornável, ou omita `amount`                       |
| `refund_window_closed`        | 422  | `invalid_request_error` | Passaram-se 90 dias desde o pagamento. Não há retentativa                  |
| `refund_disabled`             | 422  | `invalid_request_error` | Estorno não habilitado para a conta. Fale com o suporte                    |
| `too_many_requests`           | 429  | `rate_limit_error`      | Espere o `Retry-After` e repita                                            |
| `provider_rate_limited`       | 429  | `rate_limit_error`      | Limite do provedor. Repita com backoff                                     |
| `internal_error`              | 500  | `api_error`             | Repita **com a mesma `Idempotency-Key`**                                   |
| `provider_unavailable`        | 502  | `api_error`             | Repita **com a mesma `Idempotency-Key`** — a cobrança pode ter sido criada |
| `platform_unavailable`        | 503  | `api_error`             | É problema nosso. Repita depois; nada na chamada resolve                   |

## Tratando na prática

<CodeGroup>
  ```php PHP theme={null}
  $erro = $resposta->json('error');

  match ($erro['type']) {
      'api_error', 'rate_limit_error' => $this->repetir($chaveIdempotencia),
      'authentication_error', 'permission_error' => $this->alertarOperacao($erro['code']),
      default => $this->registrarFalhaDoPedido($erro['code'], $erro['details']),
  };
  ```

  ```javascript JavaScript theme={null}
  const { error } = await resposta.json();

  switch (error.type) {
    case 'api_error':
    case 'rate_limit_error':
      return repetir(chaveIdempotencia);
    case 'authentication_error':
    case 'permission_error':
      return alertarOperacao(error.code);
    default:
      return registrarFalhaDoPedido(error.code, error.details);
  }
  ```

  ```python Python theme={null}
  erro = resposta.json()["error"]

  if erro["type"] in ("api_error", "rate_limit_error"):
      repetir(chave_idempotencia)
  elif erro["type"] in ("authentication_error", "permission_error"):
      alertar_operacao(erro["code"])
  else:
      registrar_falha_do_pedido(erro["code"], erro["details"])
  ```
</CodeGroup>

<Note>
  Registre `code`, `type` e o horário da chamada no seu log. São esses três que permitem localizar a
  requisição do nosso lado quando você abre um chamado.
</Note>

## Veja também

<CardGroup cols={2}>
  <Card title="Repetir com segurança" icon="repeat" href="/receitas/repetir-com-seguranca">
    A matriz de qual código merece retry.
  </Card>

  <Card title="Limites de requisição" icon="gauge" href="/essenciais/limites-de-taxa">
    Como não chegar no `429`.
  </Card>
</CardGroup>

***

Ficou algo de fora? Escreva para [suporte@usevext.com](mailto:suporte@usevext.com). Se o assunto for
uma chamada específica, informe o horário dela; se for uma entrega de webhook, informe o
`X-Vext-Delivery` — é por ele que localizamos a tentativa, a resposta do seu servidor e o horário.
