# FINAUTON B2B — Catálogo de erros (REST `/v1` e conexão hospedada)

Envelope único:

```json
{ "error": { "code": "PROVIDER_NOT_GRANTED", "message": "…", "requestId": "req_…" } }
```

`404` significa **inexistente OU fora do seu escopo** (indistinguíveis de propósito). Mensagens nunca citam chave, segredo, token ou endereço completo. Guarde o `requestId` para suporte.

Legenda: **Retry?** S = pode repetir (mesma `Idempotency-Key` quando a rota exigir); N = não adianta repetir sem mudar algo; T = repetir depois de um tempo.

## Autenticação e limites

| HTTP | code | Significado | Retry? | Ação do parceiro |
|---|---|---|---|---|
| 401 | `B2B_CREDENTIAL_INVALID` | Credencial ausente, errada, revogada ou rotacionada sem janela | N | Conferir `clientId`/`clientSecret`; pedir nova credencial ao FINAUTON |
| 403 | `PRINCIPAL_NOT_ACTIVE` | Parceiro suspenso/revogado | N | Falar com o FINAUTON |
| 429 | `RATE_LIMITED` | Limite por parceiro (`requestsPerMinute`/`ordersPerMinute`) | T | Esperar a próxima janela de 1 min; backoff exponencial |
| 429 | `TOO_MANY_REQUESTS` | Limite da página de conexão (por IP) | T | Aguardar alguns minutos |

## Escopo, identidade e tenant

| HTTP | code | Significado | Retry? | Ação |
|---|---|---|---|---|
| 404 | `NOT_FOUND` | Cliente/tenant/sessão/pagamento inexistente ou de outro parceiro | N | Conferir `externalUserId`/ids |
| 403 | `OWNER_NOT_ALLOWED` | Cliente não pertence ao parceiro, ou suspenso numa operação de escrita | N | Conferir id; reativar se for o caso |
| 403 | `SCOPE_FIELD_REJECTED` | Corpo trouxe campo controlado pela plataforma (`principalId`, `allowedProviders`, `riskEnvelope`, `builder*`, `beneficiary`, `performanceFeePercent`, `carryPolicy`, `performancePeriod`, `subscriptionMonthlyUsd`, `paymentRecipient`, `obligationStatus`…) | N | Remover o campo |
| 400 | `TENANT_REQUIRED` | Parceiro antigo com vários tenants: `tenantId` obrigatório (ou recurso só de cliente de tenant). Parceiro com contrato único não recebe este erro | N | Informar `tenantId` |
| 409 | `TENANT_MISMATCH` | `externalUserId` já existe em outro tenant do parceiro | N | Usar outro id ou o tenant original |
| 403 | `TENANT_NOT_ACTIVE` | Tenant suspenso | N | Falar com o FINAUTON |
| 403 | `CLIENT_SUSPENDED` | Ação exige cliente ativo (ex.: nova conexão) | N | `POST …/reactivate` |
| 403 | `B2B_ACCESS_SUSPENDED` | Cliente, tenant ou parceiro suspenso | N | Reativar / falar com o FINAUTON |

## Grants e risco

| HTTP | code | Significado | Retry? | Ação |
|---|---|---|---|---|
| 403 | `GRANT_ESCALATION` | Pedido fora do grant recebido (estratégia/provider/capability) | N | Restringir ao concedido |
| 403 | `PROVIDER_NOT_ALLOWED` | Provider fora do contrato do parceiro (ou indisponível na plataforma embarcada) | N | Usar um provider do contrato (`GET /v1/tenants`) |
| 403 | `PROVIDER_NOT_GRANTED` | Provider fora do grant efetivo (parceiro ∩ tenant ∩ restrição) | N | Usar provider concedido |
| 403 | `STRATEGY_NOT_AVAILABLE` | Estratégia não publicada | N | Usar `GET /v1/strategies` |
| 403 | `STRATEGY_NOT_GRANTED` | Estratégia fora do grant efetivo do cliente | N | Selecionar estratégia concedida |
| 403/422 | `RISK_ENVELOPE_EXCEEDED` | Número acima do envelope efetivo | N | Reduzir |
| 403 | `PAPER_NOT_GRANTED` | PAPER não é oferecido no B2B | N | Usar `mode: "REAL"` |
| 400 | `SETUP_INCOMPLETE` | Setup sem campo obrigatório para ligar | N | Ver `setupStatus.issues` |
| 422 | `RISK_ACK_REQUIRED` | Falta aceite dos alertas desta combinação | N | Prévia → enviar `riskAcknowledgement` |
| 422 | `DAILY_LOSS_HALT` | Trava diária atingida | T | Aguardar o dia seguinte (UTC) |
| — | `OUTSIDE_ENVELOPE` (motivo de bloqueio) | Envelope reduzido abaixo do setup atual: sem novas entradas | N | Reduzir o setup |

## Providers e conexão

| HTTP | code | Significado | Retry? | Ação |
|---|---|---|---|---|
| 403 | `HOSTED_CONNECT_REQUIRED` | Cliente de tenant não aceita segredo pela REST | N | Usar `connect-sessions` |
| 403 | `RETURN_URL_NOT_ALLOWED` | `returnUrl` fora das origens registradas (ou não-https, credenciais, data:, javascript:) | N | Pedir registro da origem ao FINAUTON |
| 404 | `CONNECT_INVALID` | Token de conexão inválido | N | Criar nova sessão |
| 409 | `CONNECT_EXPIRED` | Sessão expirou (15 min) | N | Criar nova sessão |
| 409 | `CONNECT_ALREADY_USED` / `CONNECT_NOT_ACTIVE` | Sessão concluída/cancelada | N | Criar nova sessão se precisar |
| 409 | `CONNECT_ATTEMPTS_EXHAUSTED` | 5 tentativas falhas | N | Criar nova sessão |
| 400 | `WRONG_SCHEME` | Link de um provider usado no fluxo de outro | N | Usar o fluxo certo |
| 400/422 | `PROVIDER_CREDENTIAL_REJECTED` | Provider recusou a chave | S | Cliente corrige a chave (Futures ON, IP whitelist) |
| 400 | `AGENT_APPROVAL_REJECTED` | Hyperliquid recusou ApproveAgent | S | Cliente assina de novo |
| 400 | `BUILDER_APPROVAL_REJECTED` | Hyperliquid recusou ApproveBuilderFee | S | Cliente assina de novo |
| 403 | `WALLET_MISMATCH` | Aprovação de builder ou pagamento `usdSend` com carteira diferente da principal conectada | N | Usar a mesma carteira |
| 400/422 | `API_NOT_CONFIGURED` | Conta não conectada | N | Conectar |
| 422 | `CREDENTIALS_MISSING` | Leitura no provider (posições/conta) sem conexão | N | Conectar via `connect-sessions` |
| 503 | `PROVIDER_DOWN` | Provider indisponível/resultado incerto | T | Reconsultar intenção; não duplicar |
| — | `PROVIDER_ACCESS_LOST` (estado) | Credencial/acesso perdido no provider: entradas bloqueadas, manutenção segue | N | Cliente reconecta |

## Monetização (abertura de posição)

| code | Significado | Ação |
|---|---|---|
| `BUILDER_CONFIG_REQUIRED` | Abertura Hyperliquid sem configuração efetiva de Builder; exigência aplica-se a B2C, B2B e legado | Falar com o FINAUTON |
| `BUILDER_CONFIG_INVALID` / `BUILDER_FEE_INVALID` | Beneficiário inválido ou diferente da carteira central única FIN; taxa inválida ou acima do teto | Falar com o FINAUTON |
| `BUILDER_APPROVAL_REQUIRED` | Aprovação da carteira principal não cobre a taxa efetiva positiva | `connect-sessions` com `purpose: "BUILDER_APPROVAL"` |

Uma configuração válida com taxa zero dispensa aprovação de taxa positiva; não
equivale a ausência de configuração. Contrato pode variar a taxa, preservando a
beneficiária central. Referência: [Builder no guia atual](B2B_INTEGRATION_GUIDE.md).

## Comercial (P4) — `reasonCode` em `/commercial`, `/status`, `/automation`

| reasonCode | Estado | Novas entradas | Manutenção |
|---|---|---|---|
| `B2B_CONTRACT_ACTIVE` | ACTIVE | sim | sim |
| `*_GRACE` (ex.: `MONTHLY_PERFORMANCE_FEE_GRACE`) | GRACE (24 h após vencer) | sim | sim |
| `OBLIGATION_OVERDUE` | SUSPENDED | **não** | sim |
| `CONTRACT_REQUIRED` | NO_ENTITLEMENT | não | sim |
| `CONTRACT_SUSPENDED` | NO_ENTITLEMENT | não | sim |
| `PROVIDER_NOT_GRANTED` | NO_ENTITLEMENT | não | sim |
| `B2B_ACCESS_SUSPENDED` | NO_ENTITLEMENT | não | sim |
| `REVOKED` / `BLACKLISTED` / `ACCOUNT_INACTIVE` | idem | não | sim |

## Cobrança e pagamento

| HTTP | code | Significado | Retry? | Ação |
|---|---|---|---|---|
| 400 | `RECIPIENT_NOT_CONFIGURED` | Recebedor FINAUTON não configurado | N | Falar com o FINAUTON |
| 400 | `NETWORK_NOT_ENABLED` / `TOKEN_NOT_SUPPORTED` / `CURRENCY_MISMATCH` | Rede/token não aceitos para esta cobrança | N | Usar rede/token da política |
| 400 | `INVALID_PAYER` | Endereço pagador inválido | N | Corrigir |
| 409 | `OBLIGATION_NOT_OPEN` | Obrigação já paga/dispensada | N | — |
| 409 | `PAYMENT_EXPIRED` | Instrução expirou | N | Gerar nova instrução |
| 409 | `TX_ALREADY_USED` | Transação já creditou outra cobrança | N | Nunca reutilizar tx |
| 409 | `TX_MISMATCH` | Instrução já confirmada com outra tx | N | — |
| 400 | `INVALID_TX_HASH` | Hash mal formado | N | Corrigir |
| 202 | `PAYMENT_AWAITING_CONFIRMATIONS` | Aguardando confirmações | T | Reenviar o mesmo `txHash` depois |
| 202 | `PAYMENT_UNDERPAID` | Valor abaixo do exato: não creditado | N | Gerar nova instrução / falar com o FINAUTON |
| 200 | `PAYMENT_OVERPAID_MANUAL_REVIEW` | Valor acima do exato: obrigação **quitada**; excedente em revisão manual, **sem crédito automático** | N | Nenhuma (o FINAUTON trata o excedente) |
| 400 | `PAYMENT_METHOD_MISMATCH` | `txHash` informado para pagamento `HYPERLIQUID_USD_SEND` (verificado pelo FIN no ledger) | N | Não informar; consultar o pagamento |
| 400 | `CURRENCY_MISMATCH` (HL) | `HYPERLIQUID_USD_SEND` só para obrigação em USDC | N | Usar `EVM_TRANSFER` |
| 400 | `PAYMENT_TICKET_INVALID` | Página de pagamento: assinatura expirou/já usada | N | Cliente refaz na mesma página |
| 400 | `PAYMENT_REJECTED` | Hyperliquid recusou o `usdSend` assinado | S | Cliente assina de novo (saldo/carteira) |
| — | `PAYMENT_LEDGER_BINDING_AMBIGUOUS` | Ledger mostra transferência compatível SEM nonce: não creditada automaticamente | N | FINAUTON revisa manualmente |
| — | `PAYMENT_AWAITING_LEDGER` / `PAYMENT_AWAITING_SIGNATURE` / `PAYMENT_AMOUNT_MISMATCH` | Estado do pagamento HL (em `failureReason`): aguardando ledger/assinatura; valor divergente | T/N | Aguardar `obligation.paid`; divergência → FINAUTON |
| 202 | `PAYMENT_WRONG_SENDER` / `PAYMENT_WRONG_TOKEN_OR_RECIPIENT` / `PAYMENT_WRONG_NETWORK` / `PAYMENT_TX_TOO_OLD` / `PAYMENT_TX_FAILED` / `PAYMENT_TX_NOT_FOUND` / `PAYMENT_NOT_VERIFIED` | Verificação on-chain não confere | T/N | Conferir rede, token, destinatário, pagador e valor |

## Idempotência

| HTTP | code | Significado | Retry? | Ação |
|---|---|---|---|---|
| 400 | `IDEMPOTENCY_KEY_REQUIRED` | Rota exige `Idempotency-Key` | N | Enviar o cabeçalho |
| 409 | `IDEMPOTENCY_CONFLICT` | Mesma chave com corpo diferente | N | Nova chave para nova operação |
| 409 | `IDEMPOTENCY_IN_PROGRESS` | Mesma chave ainda processando | T | Repetir com a mesma chave |
| 400 | `VALIDATION_ERROR` | Corpo/consulta inválidos | N | Corrigir conforme a mensagem |

## Admissão de nova entrada REAL (release P0/P1/P2)

Códigos que aparecem em `POST /v1/orders/*` (`error.code` com HTTP de recusa) e nos registros de admissão das entradas automáticas. **Nenhum deles bloqueia manutenção**: stop, alvos, Break Even, redução, fechamento e reconciliação continuam. `GET /v1/users/:id/automation` reflete em `newEntries`/`blockReason`/`blockDetail` os portões avaliáveis sem ordem (incluindo `ENTRY_CIRCUIT_OPEN`, `ASSET_POLICY_REQUIRED`, `POSITION_COUNT_CAP`, `DAILY_RISK_EXHAUSTED`, `BUILDER_APPROVAL_REQUIRED`) e devolve `READINESS_UNKNOWN` quando não consegue avaliar. Portões do instante da entrada (book, spread, slippage, teto agregado, distribuição da call) ainda podem recusar com `newEntries=ALLOWED`.

| code | Significado | Retry? | Ação do parceiro |
|---|---|---|---|
| `ASSET_POLICY_REQUIRED` | Ativo sem política de entrada configurada pelo FINAUTON | N | Usar outro ativo ou pedir habilitação ao FINAUTON |
| `ASSET_NOTIONAL_LIMIT` | Notional da entrada fora do mínimo/máximo do ativo | N | Ajustar tamanho/alavancagem do setup |
| `BOOK_UNVERIFIED` | Order book indisponível, desatualizado ou inconsistente | T | Aguardar; nenhuma ordem foi enviada |
| `SPREAD_LIMIT` | Spread acima do limite do ativo | T | Aguardar o mercado normalizar |
| `LIQUIDITY_LIMIT` | Entrada excede a fração permitida da liquidez visível | T | Reduzir tamanho ou aguardar |
| `SLIPPAGE_LIMIT` | Slippage estimado acima do limite do ativo | T | Reduzir tamanho ou aguardar |
| `AGGREGATE_EXPOSURE_LIMIT` | Teto agregado da plataforma por sinal, ativo ou direção atingido | T | Aguardar liberação de exposição |
| `EXPOSURE_UNVERIFIED` | Exposição agregada não verificável (há posição com atribuição pendente no ativo) | N | Aguardar conciliação pelo FINAUTON |
| `ENTRY_CIRCUIT_OPEN` | Novas entradas pausadas: provider indisponível, proteção não confirmada, reconciliação pendente ou exposição externa misturada | T | Aguardar reconciliação saudável; manutenção segue |
| `POSITION_COUNT_CAP` | Vagas ocupadas (operação REAL: 1 posição simultânea por conta, contando pendências e posições externas) | T | Aguardar fechamento |
| `SIGNAL_DISTRIBUTION_LIMIT` | Conta elegível, mas fora da coorte desta call (distribuição limitada por call) | — | Nenhuma; a conta entra no rodízio das próximas calls |

Resultado com origem ou exposição não atribuível aparece com `settlement`/fato canônico `ATTRIBUTION_PENDING`: **não é cobrado** e não entra na performance até a conciliação.

Schema do release: `maxConcurrentTrades` em `PUT /setup`, `POST /setup/preview` e `PUT /risk` aceita **1 a 3**; acima disso, `400 VALIDATION_ERROR`. A versão publicada antes do release ainda aceita até 20.

# Nota de contrato RC1

O envelope público não contém `retryable`. Preserve HTTP status, `error.code`, `error.message`, `error.requestId` (e header de correlação quando presente). Exceção existente: teste de conexão `/v1/users/:externalUserId/accounts/:provider/test` pode retornar HTTP 400 no DTO `{success:false,error,latencyMs,permissions,requestId}`, sem envelope `error.code`. Não tratar essa mensagem como permissão para repetir ordem/pagamento. Essa rota consulta provider e está fora do smoke sem REAL.
