Erros

Entenda o envelope de erro padrão da Tokeflow, os tipos de erro, os códigos de status HTTP e como tratar falhas de forma confiável em produção.

A Tokeflow retorna erros em um único formato previsível em todos os endpoints. Construa seu tratamento de erros uma vez e ele funciona em qualquer lugar.

Toda requisição que falha retorna:

  • Um código de status HTTP significativo (o sinal em nível de transporte).
  • Um envelope de erro estruturado com um type e code legíveis por máquina, uma message legível por humanos e um request_id para o suporte.

Comece pelo type e pelo code nos seus fluxos de código, exiba a message para humanos e sempre registre o request_id em log.

Uma resposta bem-sucedida é encapsulada no envelope de sucesso (success, data, meta). Uma resposta que falha não é — ela tem um único objeto error no nível superior e nenhum campo success. Ramifique primeiro pelo código de status HTTP.

O envelope de erro

{
  "error": {
    "type": "validation_error",
    "code": "INVALID_FIELD",
    "message": "Validation failed",
    "details": {
      "amount": ["amount must be a positive integer"]
    },
    "request_id": "req_8f3c2a1b9d7e4f60",
    "timestamp": "2026-01-15T12:30:00.000Z"
  }
}
FieldTypeSempre presenteDescrição
typestringSimCategoria de erro de alto nível. Um dos tipos de erro abaixo. Use isto para ramificar seu tratamento.
codestringSimCódigo estável e legível por máquina (por exemplo, INVALID_FIELD, RESOURCE_NOT_FOUND). Mais específico que type. Seguro para usar em um switch.
messagestringSimExplicação legível por humanos. Seguro para exibir, mas o texto pode mudar com o tempo — nunca faça parsing dela.
detailsobjectNãoContexto opcional. Para erros de validação, um mapa de nome de campo para um array de mensagens. Pode ser omitido totalmente.
decline_reasonstringNãoPresente apenas em erros de pagamento que tenham um: o nome que a Tokeflow dá ao motivo da falha do pagamento, o mesmo valor qualquer que seja o provedor que respondeu (por exemplo, invalid_cvv, insufficient_funds). Veja Motivos de recusa.
request_idstringSimIdentificador único desta requisição (req_…). Registre-o em log e inclua-o em qualquer solicitação de suporte.
timestampstringSimHorário em UTC no formato ISO 8601 em que o erro foi gerado.

Use um switch em type para tratamento amplo (repetir a tentativa vs. corrigir a requisição) e em code quando precisar reagir a uma falha específica (por exemplo, IDEMPOTENCY_KEY_CONFLICT vs. RESOURCE_ALREADY_EXISTS, ambos sob conflict_error). Trate code como o contrato estável; trate message como apenas para exibição.

Como os erros fluem

Tipos de erro

Cada erro carrega um type que mapeia um-para-um com um código de status HTTP. Use o código de status para decidir sua estratégia; use type e code para decidir seu comportamento.

TypeHTTPSignificadoComo tratar
validation_error400O corpo da requisição ou os parâmetros de consulta falharam na validação.Corrija a requisição. Inspecione details para mensagens em nível de campo. Não repita sem alterar.
bad_request_error400A requisição estava malformada ou semanticamente inválida de um modo que não é validação de campo.Corrija a requisição. Não repita sem alterar.
authentication_error401A chave de API está ausente, malformada ou inválida.Verifique o cabeçalho Authorization e a chave. Não repita sem alterar.
authorization_error403A chave é válida, mas não tem o escopo necessário, ou o recurso alvo está fora do escopo da chave.Use uma chave com o escopo certo. Não repita sem alterar.
not_found_error404O recurso ou endpoint não existe (ou está fora do seu escopo).Verifique o ID e o caminho. Não repita sem alterar.
conflict_error409A requisição conflita com o estado atual (por exemplo, duplicata, reutilização de idempotency-key, recurso em uso).Resolva o conflito e depois repita. Veja code para detalhes.
business_rule_error422A requisição estava bem formada, mas viola uma regra de negócio (por exemplo, uma transição de estado inválida).Corrija a operação para satisfazer a regra. Não repita sem alterar.
rate_limit_error429Você excedeu o limite de taxa para esta chave de API.Recue e repita com backoff exponencial.
external_service_error502Um provedor downstream no caminho de orquestração retornou um erro ou estava inacessível.Repita com backoff. Se persistir, inspecione o status do recurso.
internal_server_error500Um erro inesperado ocorreu no lado da Tokeflow.Repita com backoff. Se persistir, contate o suporte com o request_id.

O campo code é mais granular que type. Por exemplo, um conflict_error pode carregar RESOURCE_ALREADY_EXISTS, DUPLICATE_ENTRY, RESOURCE_IN_USE ou IDEMPOTENCY_KEY_CONFLICT. Ramifique em type para a estratégia, em code para os detalhes.

Estratégia de repetição em resumo

  • 4xx (exceto 429): corrija a requisição. O problema está na entrada — um campo inválido, um escopo ausente, um ID desconhecido ou uma violação de regra. Repetir a mesma requisição vai falhar do mesmo jeito.
  • 429: recue. Você está sendo limitado por taxa. Repita com backoff exponencial e jitter.
  • 5xx (500, 502): passível de repetição. Estes são transitórios. Repita de forma idempotente com backoff exponencial. Sempre envie uma Idempotency-Key em mutações de criação/cobrança para que as repetições nunca dupliquem trabalho.

Nunca repita um 4xx que não seja 429 sem alterar — ele vai falhar de forma idêntica e desperdiçar seu orçamento de limite de taxa. Leia type, code e details, corrija a requisição e então tente novamente.

Exemplos de respostas de erro

400 — Erro de validação (validation_error)

Falhas em nível de campo aparecem sob details, indexadas por nome de campo. Cada valor é um array de mensagens.

{
  "error": {
    "type": "validation_error",
    "code": "INVALID_FIELD",
    "message": "Validation failed",
    "details": {
      "amount": ["amount must be a positive integer"],
      "currency": ["currency must be a valid ISO 4217 code"]
    },
    "request_id": "req_8f3c2a1b9d7e4f60",
    "timestamp": "2026-01-15T12:30:00.000Z"
  }
}

Os valores são inteiros em unidades menores (por exemplo, 15000 para R$150,00) e currency é ISO 4217. Veja Convenções para regras de dinheiro e formatação.

401 — Erro de autenticação (authentication_error)

A chave de API está ausente, malformada ou inválida.

{
  "error": {
    "type": "authentication_error",
    "code": "INVALID_CREDENTIALS",
    "message": "Authentication failed",
    "request_id": "req_3a91c0ed7b224f18",
    "timestamp": "2026-01-15T12:30:00.000Z"
  }
}

Chaves secretas (sk_…) são exclusivamente do lado do servidor e nunca devem aparecer em código de navegador. Envie-as no cabeçalho Authorization: Bearer <secret_key> a partir do seu backend. Veja Autenticação.

403 — Erro de autorização (authorization_error)

A chave é válida, mas não tem o escopo necessário, ou o recurso alvo está fora do escopo da chave.

{
  "error": {
    "type": "authorization_error",
    "code": "INSUFFICIENT_PERMISSIONS",
    "message": "This API key does not have the required scope: transactions:write",
    "request_id": "req_77ba2c41e9f04d3a",
    "timestamp": "2026-01-15T12:30:00.000Z"
  }
}

Os escopos seguem resource:action (por exemplo, transactions:read, products:write). Ao usar uma chave de Organization contra recursos com escopo de merchant, você também deve identificar o Merchant alvo por meio do parâmetro de consulta ou campo de corpo merchant_id. Veja Autenticação.

404 — Erro de não encontrado (not_found_error)

O recurso não existe, ou está fora do escopo da sua chave.

{
  "error": {
    "type": "not_found_error",
    "code": "RESOURCE_NOT_FOUND",
    "message": "Transaction not found",
    "request_id": "req_5e0d8f3a6c124b97",
    "timestamp": "2026-01-15T12:30:00.000Z"
  }
}

409 — Erro de conflito (conflict_error)

A requisição conflita com o estado atual. Uma causa comum é reenviar uma Idempotency-Key cujo corpo difere da requisição original.

{
  "error": {
    "type": "conflict_error",
    "code": "IDEMPOTENCY_KEY_CONFLICT",
    "message": "This idempotency key was already used with a different request body.",
    "request_id": "req_1c47a98f2b6e40d5",
    "timestamp": "2026-01-15T12:30:00.000Z"
  }
}

Reenviar a mesma Idempotency-Key com o mesmo corpo retorna o resultado original (HTTP 200 no reenvio vs. 201 na primeira criação) — não um conflito. Um conflito só ocorre quando a chave é reutilizada com um payload diferente. Veja Idempotência.

Outros códigos de conflito incluem RESOURCE_ALREADY_EXISTS (já existe um registro com esses valores), DUPLICATE_ENTRY e RESOURCE_IN_USE (o recurso é referenciado por outros registros e não pode ser excluído ou modificado).

422 — Erro de regra de negócio (business_rule_error)

A requisição estava bem formada, mas viola uma regra de negócio — por exemplo, tentar uma transição de estado inválida.

{
  "error": {
    "type": "business_rule_error",
    "code": "INVALID_STATE_TRANSITION",
    "message": "Cannot capture a transaction that has already been voided.",
    "details": {
      "current_status": "voided",
      "requested_action": "capture"
    },
    "request_id": "req_9b2f6d1a3e8c47f0",
    "timestamp": "2026-01-15T12:30:00.000Z"
  }
}

422 significa "Entendi a requisição, mas ela não pode ser aplicada no estado atual." Inspecione o status atual do recurso antes de repetir. Códigos relacionados incluem TRANSACTION_ALREADY_VOIDED, TRANSACTION_ALREADY_CAPTURED e TRANSACTION_ALREADY_REFUNDED.

429 — Erro de limite de taxa (rate_limit_error)

Você excedeu um limite de requisições para esta chave de API neste endpoint. Os limites são contabilizados por chave e por rota, em janelas de 60 segundos, e dependem da classe da rota — consulte Limites de taxa. A resposta traz Retry-After e, em details, retry_after_seconds e limit.

{
  "error": {
    "type": "rate_limit_error",
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded. Retry after a short delay.",
    "request_id": "req_4d8e1a07f5c9426b",
    "timestamp": "2026-01-15T12:30:00.000Z"
  }
}

Em 429, repita com backoff exponencial e jitter em vez de um atraso fixo. Distribuir as repetições evita um efeito de "manada" quando muitos clientes recuam ao mesmo tempo.

5xx — Erros de servidor e upstream (internal_server_error, external_service_error)

Um 500 indica um erro inesperado no lado da Tokeflow. Um 502 indica que um provedor downstream no caminho de orquestração falhou ou estava inacessível. Ambos são transitórios — repita com backoff.

{
  "error": {
    "type": "internal_server_error",
    "code": "INTERNAL_ERROR",
    "message": "Internal server error",
    "request_id": "req_a1b2c3d4e5f60718",
    "timestamp": "2026-01-15T12:30:00.000Z"
  }
}

Se um 5xx persistir após várias repetições com backoff, contate o suporte e inclua o request_id. Ele nos permite rastrear a requisição exata de ponta a ponta.

Tratando erros no código

Leia o status HTTP para decidir se deve repetir, e o envelope para decidir como reagir. O exemplo abaixo repete 429 e 5xx com backoff exponencial e expõe todo o resto para o chamador corrigir.

async function tokeflowRequest(url, options, attempt = 0) {
  const MAX_RETRIES = 4;
  const res = await fetch(url, options);

  if (res.ok) {
    return res.json();
  }

  const body = await res.json();
  const { type, code, message, request_id } = body.error;

  // Always log the request_id — it is your support handle.
  console.error(`Tokeflow error ${res.status} ${code}: ${message} (request_id=${request_id})`);

  const isRetryable = res.status === 429 || res.status >= 500;

  if (isRetryable && attempt < MAX_RETRIES) {
    // Exponential backoff with jitter: 0.5s, 1s, 2s, 4s (+/- jitter).
    const delay = Math.pow(2, attempt) * 500 + Math.random() * 250;
    await new Promise((r) => setTimeout(r, delay));
    return tokeflowRequest(url, options, attempt + 1);
  }

  // 4xx (except 429): the request must change. Surface it to the caller.
  const error = new Error(message);
  Object.assign(error, { type, code, request_id, status: res.status });
  throw error;
}
# Inspect the status code and envelope on a failed request.
curl -i https://api.tokeflow.com/api/v1/transactions/tx_does_not_exist \
  -H "Authorization: Bearer sk_live_mer_xxxxxxxxxxxxxxxx"

# HTTP/1.1 404 Not Found
# {
#   "error": {
#     "type": "not_found_error",
#     "code": "RESOURCE_NOT_FOUND",
#     "message": "Transaction not found",
#     "request_id": "req_5e0d8f3a6c124b97",
#     "timestamp": "2026-01-15T12:30:00.000Z"
#   }
# }

Boas práticas

  • Registre o request_id em log em toda falha. É a maneira mais rápida de o suporte rastrear uma requisição. Inclua-o em tickets e logs internos.
  • Ramifique em type e code, nunca em message. As mensagens são para humanos e podem mudar; type e code são o contrato estável.
  • Trate 5xx e 429 como passíveis de repetição com backoff exponencial e jitter; trate outros 4xx como corrija-a-requisição.
  • Sempre envie uma Idempotency-Key em mutações de criação/cobrança para que repetições seguras nunca dupliquem trabalho.
  • Leia details em 400 para identificar exatamente o campo que falhou na validação.

Relacionados

  • Convenções — envelopes, paginação, idempotência, dinheiro e limites de taxa.
  • Autenticação — chaves, escopos e cabeçalhos.
  • Webhooks — verificação de assinatura e entrega de eventos.

Nesta página