Minstrel

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.

TipoHTTPSignificadoO que fazer
invalid_request_error400, 422Requisicao malformada ou campo invalidoCorrija o payload. Nao retente igual.
authentication_error401Credencial ausente, invalida ou revogadaVerifique a chave.
authorization_error403Credencial valida, sem permissaoVerifique os escopos da chave.
not_found_error404Recurso inexistente no seu escopoConfira o id e o ambiente.
conflict_error409Conflito de estado ou de idempotenciaVeja a secao de idempotencia.
rate_limit_error429Limite de requisicoes excedidoAguarde meta.retryAfterSeconds.
card_error402Recusa do emissorConsulte decline.retryAction.
connector_error502Falha do adquirente (timeout, 5xx)Pode ser retentado.
flow_error422Problema no fluxo de roteamentoVerifique o fluxo publicado.
api_error500Falha interna nossaRetente 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:

codeQuandoO que fazer
client_secret_invalidO 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_confirmableO pagamento nao esta em requires_payment_method: ja confirmado, recusado ou cancelado.Consulte o pagamento; para cobrar de novo, crie outro.
payment_expiredPassou o prazo de 24 horas (actionExpiresAt) sem o cartao.Crie um pagamento novo.
no_tokenization_account422. 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_ambiguous422. 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.