# Idempotência, erros e limites

Como repetir mutações do Invoise com segurança, o que significam os códigos de erro e quais limites se aplicam.

Source: https://docs.invoise.me/pt-br/integration/idempotency-and-errors/

Se uma requisição expira, você não sabe se ela teve sucesso. Repita a mesma operação com a mesma `Idempotency-Key` para evitar criar um segundo pagamento.

## Uma chave por ação

1. Gere uma chave única antes da primeira requisição e salve-a com o seu pedido.
2. Envie-a em `Idempotency-Key` ao criar ou alterar um recurso de negócio.
3. Após um timeout, repita o mesmo método, caminho e corpo com essa chave.
4. Para uma nova ação, crie uma nova chave.

A chave deve ter conteúdo e no máximo 128 bytes. Repetir uma ação concluída retorna sua resposta salva. Alterar o corpo sob a mesma chave retorna `409 idempotency_conflict`.

Isso se aplica a mutações de negócio como faturas, lojas, chaves e webhooks. Chamadas GET somente leitura e desafios de entrada não usam esse mecanismo. Siga os requisitos de cada endpoint.

`external_id` ajuda a associar um pagamento ao seu pedido; não é uma chave de idempotência.

## Leia erros pelo código

Exemplo:

```json
{"error":{"code":"idempotency_conflict","message":"idempotency_conflict"}}
```

Use `error.code` no seu programa. Não presuma sucesso a partir do corpo da resposta sem antes verificar o status HTTP.

| Código | Próxima ação |
| --- | --- |
| `unauthorized` | Verifique a credencial, as permissões e qualquer restrição de IP. Entre novamente se a sessão expirou. |
| `mfa_required` | Complete o segundo fator da conta usando sua sessão. |
| `onboarding_required` | Complete `/onboarding` antes de operações de loja. |
| `idempotency_key_required` | Forneça uma chave salva não vazia, com no máximo 128 bytes. |
| `idempotency_conflict` | Encontre a requisição original. Não crie um novo pagamento silenciosamente. |
| `json_content_type_required` / `invalid_json` | Envie `Content-Type: application/json` e apenas campos documentados. |
| `unsupported_network` / `unsupported_asset` | Selecione uma rede e um token compatíveis. |
| `network_not_ready` / `asset_not_ready` | Aguarde a disponibilidade ou selecione outra rota pronta. |
| `amount_below_minimum` / `fee_exceeds_amount` | Verifique o valor, as casas decimais e as condições da loja. |
| `shop_archived` / `shop_not_found` | Verifique a loja e o acesso. |
| `invalid_expires_in` | Envie `1d`, `7d`, `30d`, `180d` ou `365d`, e apenas ao criar uma fatura. Depósitos não expiram. |
| `invalid_assets` / `issuance_in_group` | Envie pares distintos de `{chain_id, token}` sem `chain_id` e `token`; cancele ou pause um grupo pelo próprio `id`. Veja [vários tokens ou redes](https://docs.invoise.me/pt-br/payments/deposits-and-invoices/#ofereça-vários-tokens-ou-redes). |
| `solana_setup_required` / `tron_setup_required` | Defina primeiro o [destinatário Solana ou Tron](https://docs.invoise.me/pt-br/payments/solana-and-tron/) da loja. |
| `invoice_amount_limit` / `sandbox_amount_limit` | Reduza o valor para dentro do [limite](#limites). |
| `active_invoice_limit_reached` / `deposit_address_limit_reached` | Cancele faturas ou desative depósitos que você não precisa mais, ou peça ao Invoise para aumentar o limite. |
| `api_key_limit_reached` / `too_many_allowed_ips` / `webhook_limit_reached` | Revogue chaves não usadas, reduza a lista de IPs ou reutilize um endpoint existente. |
| `team_limit_reached` | Remova um membro ou revogue um convite pendente, ou peça ao Invoise para aumentar o limite. |
| `account_disabled` | A equipe do Invoise bloqueou a conta; o motivo está em `error.details`. Veja [contas bloqueadas](https://docs.invoise.me/pt-br/integration/team-and-access/#contas-bloqueadas). |
| `rate_limited` | Aguarde o número de segundos em `Retry-After` antes de repetir. |

## Limites

Quando uma requisição excederia um limite, o Invoise a rejeita com o corpo de erro usual e o código abaixo.

| Limite | Valor | Erro |
| --- | --- | --- |
| Valor de uma fatura | 1.000.000 tokens | `400 invoice_amount_limit` |
| Valor de uma fatura sandbox ou transferência simulada | 10.000 tokens | `400 sandbox_amount_limit` |
| Faturas ativas por lojista | 2.000 | `400 active_invoice_limit_reached` |
| Endereços de depósito ativos por lojista, por família de rede | EVM 10.000, Tron 10.000, Solana 10 | `400 deposit_address_limit_reached` |
| Chaves de API por loja que não estejam revogadas | 10 | `400 api_key_limit_reached` |
| Endereços IP ou faixas CIDR permitidos por chave | 10 | `400 too_many_allowed_ips` |
| Endpoints de webhook por loja | 10 | `400 webhook_limit_reached` |
| Membros da equipe e convites pendentes por lojista | 10 | `400 team_limit_reached` |
| Requisições por minuto | 1.200, das quais no máximo 120 não são GET | `429 rate_limited` |

Os limites de valor estão em tokens inteiros, não em unidades base. Todo token compatível é uma stablecoin em dólar, então 1.000.000 tokens equivale a cerca de $1.000.000.

Uma fatura fica ativa até ser paga, cancelada ou expirar. Uma fatura oferecida em várias redes conta uma única vez. Um endereço de depósito fica ativo até ser desativado; cada opção de rede de um depósito é um endereço separado. Sandbox e produção são contados separadamente para os dois limites. A equipe do Invoise pode alterar os limites de fatura, endereço de depósito e equipe de um lojista.

O limite de equipe se aplica tanto ao convidar quanto ao aceitar um convite. A URL de um endpoint de webhook pode ser alterada, então você pode reutilizar um endpoint em vez de adicionar outro.

As requisições são contadas por chave de API, por sessão do painel, ou por IP do cliente quando não autenticadas. Uma resposta `429` traz `Retry-After: 60`.

## Repita sem duplicar

Repita timeouts e erros temporários do servidor com a **mesma chave**, usando atrasos crescentes. Em `429`, aguarde os segundos em `Retry-After`; não envie mais requisições imediatamente. Corrija entradas inválidas e erros de acesso antes de repetir.

Para webhooks, o Invoise repete a entrega. Aceite o evento de forma durável, retorne 2xx e depois processe-o. Deduplique por `Invoise-Event-ID`.

As rotas antigas `/projects` são aliases de `/shops`, incluindo seu escopo de idempotência. Use `/shops` para novas integrações. Nomes de erro legados podem usar `project_*`.
