Comece aqui
Catalogo de erros
Todo erro da API do Minstrel, com o significado de cada tipo e codigo e o que fazer em cada caso.
Todo erro da API segue o mesmo envelope. Previsibilidade no formato de erro e o que permite escrever um unico tratador no seu codigo em vez de um por endpoint.
{
"error": {
"type": "card_error",
"code": "insufficient_funds",
"message": "Saldo ou limite insuficiente.",
"param": "amount",
"requestId": "req_01HQ8M5X7P2K3N4R5T6V7W8X9Y",
"docsUrl": "https://docs.minstrel.com.br/errors/insufficient_funds",
"meta": {}
}
}
Guarde o requestId. Com ele, o suporte localiza a requisicao exata, com o
corpo enviado e a resposta de cada conector acionado. Sem ele, a investigacao
comeca do zero.
Tipos
O type e a categoria estavel: trate por ele, nao pela mensagem.
| Tipo | HTTP | Significado | O que fazer |
|---|---|---|---|
invalid_request_error | 400, 422 | Requisicao malformada ou campo invalido | Corrija o payload. Nao retente igual. |
authentication_error | 401 | Credencial ausente, invalida ou revogada | Verifique a chave. |
authorization_error | 403 | Credencial valida, sem permissao | Verifique os escopos da chave. |
not_found_error | 404 | Recurso inexistente no seu escopo | Confira o id e o ambiente. |
conflict_error | 409 | Conflito de estado ou de idempotencia | Veja a secao de idempotencia. |
rate_limit_error | 429 | Limite de requisicoes excedido | Aguarde meta.retryAfterSeconds. |
card_error | 402 | Recusa do emissor | Consulte decline.retryAction. |
connector_error | 502 | Falha do adquirente (timeout, 5xx) | Pode ser retentado. |
flow_error | 422 | Problema no fluxo de roteamento | Verifique o fluxo publicado. |
api_error | 500 | Falha interna nossa | Retente e, se persistir, informe o requestId. |
Observe a distincao entre card_error e connector_error: o primeiro e uma
decisao do emissor (negocio), o segundo e uma falha tecnica. A diferenca muda
completamente o que vale fazer em seguida.
Recusa na criacao do pagamento nao e erro HTTP. POST /v1/payments
responde 201 com o pagamento em status: failed e o motivo em decline
(classificacao ABECS, com retryAction): o pagamento existe e tem historico.
O card_error (402) aparece nas operacoes sobre um pagamento existente -
captura, cancelamento e estorno recusados pelo adquirente.
Codigos mais comuns
Dados de cartao recusados
{
"error": {
"type": "invalid_request_error",
"code": "raw_card_data_rejected",
"param": "card.number",
"meta": { "offendingPaths": ["card.number", "card.cvv"] }
}
}
A API nao aceita numero de cartao, CVV, trilha ou PIN. Tokenize o cartao e envie apenas o token. O erro lista os caminhos dos campos, nunca os valores - caso contrario ele mesmo vazaria o dado para os seus logs.
A checagem tambem pega cartao colado em campo de texto livre, como
description ou metadata.
Chave de idempotencia reutilizada
{
"error": {
"type": "conflict_error",
"code": "idempotency_key_reused",
"message": "Esta chave de idempotencia ja foi usada com um corpo de requisicao diferente. Gere uma nova chave para uma cobranca diferente."
}
}
Este erro esta protegendo voce do bug mais perigoso da categoria: reaproveitar uma chave entre cobrancas distintas faria a segunda ser silenciosamente ignorada, e o cliente nao seria cobrado. Gere uma chave por operacao.
Requisicao em andamento
{
"error": {
"type": "conflict_error",
"code": "idempotency_request_in_progress"
}
}
Duas requisicoes com a mesma chave chegaram ao mesmo tempo. Aguarde alguns segundos e consulte o pagamento - nao crie outro.
Devolvemos 409 em vez da resposta parcial de proposito: tratar como sucesso algo que ainda pode falhar seria pior.
Nenhum conector disponivel
{
"error": {
"type": "connector_error",
"code": "no_connector_available",
"meta": { "requested": ["ca_..."] }
}
}
Nenhuma conta de conector do fluxo esta habilitada e saudavel. Pode ser circuito aberto por falhas consecutivas: consulte o painel de conectores.
Fluxo nao publicado
{
"error": {
"type": "flow_error",
"code": "flow_not_published",
"message": "Ha mais de um conector habilitado e nenhum fluxo publicado. Publique um fluxo para definir o roteamento."
}
}
Com um unico conector habilitado, roteamos direto. Com mais de um, escolher por voce seria adivinhar a intencao em algo que move dinheiro.
Checkout transparente
Erros das rotas do checkout transparente, que o
@minstrel/js entrega como MinstrelError do tipo api:
code | Quando | O que fazer |
|---|---|---|
client_secret_invalid | O clientSecret nao confere com o pagamento (ou o pagamento nao existe: a resposta e a mesma). | Confira o par paymentId e clientSecret que o seu servidor entregou a pagina. |
payment_not_confirmable | O pagamento nao esta em requires_payment_method: ja confirmado, recusado ou cancelado. | Consulte o pagamento; para cobrar de novo, crie outro. |
payment_expired | Passou o prazo de 24 horas (actionExpiresAt) sem o cartao. | Crie um pagamento novo. |
no_tokenization_account | 422. Nenhuma conta habilitada tokeniza cartao no navegador, ou a informada em tokenizationAccountId nao serve. | Habilite uma conta com tokenizacao no navegador (Cielo com Silent Order Post). |
tokenization_account_ambiguous | 422. Ha mais de uma conta que tokeniza e o pagamento nao disse qual. | Informe tokenizationAccountId ao criar o pagamento. |
As rotas publicas (/v1/public/payments/...) tambem respondem 429
(rate_limit_error) com Retry-After: ha um teto por IP e, por pagamento, um
teto de sessoes de tokenizacao e de confirmacoes por hora.
Tratando erros
import { Minstrel, MinstrelApiError } from '@minstrel/sdk';
try {
const payment = await minstrel.payments.create({ amount: 14990 });
} catch (error) {
if (!(error instanceof MinstrelApiError)) throw error;
// Recusa do emissor: mostre a mensagem ao cliente.
if (error.isCardError) {
return mostrarAoCliente(error.message);
}
// Falha tecnica: pode ser retentada com a MESMA chave de idempotencia.
if (error.isRetryable) {
return agendarRetentativa();
}
// Erro de integracao: corrija o codigo.
logger.error({ code: error.code, requestId: error.requestId }, error.message);
throw error;
}
A regra geral: retente connector_error, rate_limit_error e api_error
usando a mesma chave de idempotencia. Nao retente invalid_request_error nem
card_error - no primeiro, a requisicao esta errada; no segundo, consulte
decline.retryAction, que diz o que fazer.