Referência
Erros
Formato dos erros, códigos HTTP e o que fazer em cada caso.
Todo erro vem no mesmo formato, com um code estável. Programe sempre em cima do code — a message é escrita para humanos e pode mudar sem aviso.
{ "error": { "code": "validation_error", "message": "2 campos estão inválidos. Veja "fields".", "fields": { "amount": "Informe o valor em CENTAVOS, como número inteiro (ex.: 1990 = R$ 19,90).", "customer.document": "CPF inválido." }, "doc_url": "https://novexfinance.com.br/docs/erros", "request_id": "a3f1c09b7e42d85610fb2c7d9a4e5b83" } }
| Campo | Tipo | Descrição |
|---|---|---|
error.codeopcional | string | Identificador estável do erro. É o que o seu código deve verificar. |
error.messageopcional | string | Explicação em português. Não faça lógica em cima dela. |
error.fieldsopcional | objeto | Só em validation_error: o problema de cada campo, pelo caminho completo (customer.email). |
error.request_idopcional | string | Identificador da requisição. Registre no seu log — é por ele que o suporte acha o que aconteceu. |
error.doc_urlopcional | string | Página da documentação que trata do assunto. |
Códigos HTTP
| HTTP | Significa | Retentar? |
|---|---|---|
200 · 201 | Deu certo. | — |
400 | Requisição malformada (JSON inválido, por exemplo). | Não, sem corrigir. |
401 | Credencial ausente, inválida ou revogada. | Não, sem corrigir. |
402 | Pagamento recusado pelo emissor. | Não. Ofereça outro meio ao cliente. |
403 | Autenticado, mas sem permissão para esta operação. | Não, sem resolver a pendência. |
404 | Recurso ou endpoint não encontrado. | Não. |
405 | Método HTTP errado para este caminho. Veja o header Allow. | Não. |
409 | Conflito com o estado atual do recurso. | Depende do caso. |
422 | JSON válido, mas os dados não passam nas regras. | Não, sem corrigir. |
429 | Limite de requisições excedido. | Sim, após o Retry-After. |
500 | Erro nosso. | Sim, com a mesma Idempotency-Key. |
502 · 503 | Serviço de processamento indisponível. | Sim, com a mesma Idempotency-Key. |
Todos os códigos de erro
Autenticação e acesso
| Código | HTTP | O que fazer |
|---|---|---|
missing_api_key | 401 | Enviar o header Authorization: Bearer. Se você já envia, verifique se o seu servidor não o está removendo. |
invalid_api_key | 401 | Conferir a chave. Ela começa com nvx_live_. |
revoked_api_key | 401 | Gerar uma chave nova no painel. |
unauthorized | 401 | Requisição sem autenticação válida. |
account_inactive | 403 | Conta suspensa ou bloqueada. Falar com o suporte. |
kyc_required | 403 | Concluir a verificação de identidade no painel. Consultas funcionam; cobranças e saques, não. |
Dados enviados
| Código | HTTP | O que fazer |
|---|---|---|
invalid_json | 400 | Corpo não é JSON válido. Confira o Content-Type: application/json. |
validation_error | 422 | Ler fields e corrigir cada campo apontado. |
resource_not_found | 404 | O ID não existe nesta conta. Conferir se não veio de outro ambiente. |
not_found | 404 | Endpoint inexistente. Conferir o caminho. |
method_not_allowed | 405 | Usar um dos verbos listados no header Allow. |
Regras de negócio
| Código | HTTP | O que fazer |
|---|---|---|
payment_refused | 402 | O emissor não autorizou. Oferecer outro cartão ou outro meio. |
insufficient_balance | 422 | Saldo menor que valor + taxa. A mensagem traz os três números. |
amount_limit_exceeded | 403 | Valor acima do limite por transação da conta. |
daily_limit_exceeded | 403 | Limite diário atingido. Tentar no dia seguinte ou pedir revisão do limite. |
card_direct_not_enabled | 403 | Enviar dados de cartão pela API exige PCI-DSS. Usar checkout hospedado. |
checkout_already_paid | 409 | Não dá para expirar um checkout já pago. |
webhook_already_exists | 409 | Já existe endpoint com esta URL. |
webhook_limit_reached | 409 | Máximo de 10 endpoints. Remover um antes de criar outro. |
Idempotência e limites
| Código | HTTP | O que fazer |
|---|---|---|
idempotency_key_in_progress | 409 | A primeira requisição ainda está sendo processada. Aguardar e consultar antes de repetir. |
idempotency_key_reused | 422 | A mesma chave foi usada com outro corpo. Usar uma chave nova. |
rate_limit_exceeded | 429 | Esperar o Retry-After em segundos. |
Do nosso lado
| Código | HTTP | O que fazer |
|---|---|---|
processing_error | 502 | Falha no processamento. Retentar com a mesma Idempotency-Key. |
service_unavailable | 503 | Indisponibilidade temporária ou manutenção. Retentar com a mesma Idempotency-Key. |
internal_error | 500 | Erro nosso. Retentar; se persistir, informar o request_id ao suporte. |
Como tratar erros
A regra é simples: 4xx é problema do pedido — retentar sem mudar nada só repete o erro. 5xx e 429 são transitórios — retentar faz sentido, com espera crescente e sempre com a mesma Idempotency-Key.
function criarCobranca(array $payload, string $idemKey): array { $espera = 1; for ($tentativa = 1; $tentativa <= 4; $tentativa++) { [$status, $body] = post('/charges', $payload, $idemKey); if ($status < 300) { return $body; } // 4xx (menos 429): o pedido está errado. Retentar não resolve. if ($status < 500 && $status !== 429) { throw new RuntimeException( $body['error']['code'] . ': ' . $body['error']['message'] ); } // Mesma Idempotency-Key: se a 1ª chegou a criar, recebemos ela de volta // em vez de uma segunda cobrança. sleep($espera); $espera *= 2; } throw new RuntimeException('Falha após 4 tentativas.'); }
async function criarCobranca(payload, idemKey) { let espera = 1000; for (let tentativa = 1; tentativa <= 4; tentativa++) { const res = await post('/charges', payload, idemKey); const body = await res.json(); if (res.ok) return body; // 4xx (menos 429): o pedido está errado. Retentar não resolve. if (res.status < 500 && res.status !== 429) { throw new Error(`${body.error.code}: ${body.error.message}`); } // Mesma Idempotency-Key: nunca vira cobrança duplicada. await new Promise((r) => setTimeout(r, espera)); espera *= 2; } throw new Error('Falha após 4 tentativas.'); }
import time def criar_cobranca(payload, idem_key): espera = 1 for _ in range(4): res = post('/charges', payload, idem_key) if res.ok: return res.json() # 4xx (menos 429): o pedido está errado. Retentar não resolve. if res.status_code < 500 and res.status_code != 429: err = res.json()['error'] raise RuntimeError(f'{err["code"]}: {err["message"]}') # Mesma Idempotency-Key: nunca vira cobrança duplicada. time.sleep(espera) espera *= 2 raise RuntimeError('Falha após 4 tentativas.')
Registre sempre o request_id junto com o erro no seu log. Sem ele, investigar uma falha vira uma busca por horário aproximado; com ele, o suporte localiza a requisição exata em segundos.
Timeout do seu lado
Criar cobrança envolve comunicação com o processador de pagamento. Use um timeout de pelo menos 40 segundos — um timeout curto derruba a conexão enquanto a cobrança está sendo criada de verdade, e você fica sem saber o resultado.
Se o timeout acontecer mesmo assim, não crie outra cobrança às cegas: repita a chamada com a mesma Idempotency-Key. Se a primeira tiver dado certo, você recebe ela de volta; se não, uma nova é criada. Nunca duas.