CyrusDocs

Erros

Referência completa de códigos de erro da API Cyrus.

Estrutura de erros

Quando uma requisição falha, a API retorna um JSON com success: false e um objeto error:

{
  "success": false,
  "error": {
    "code": "INSUFFICIENT_BALANCE",
    "message": "Saldo insuficiente para realizar a operação"
  }
}

Em erros de validação (422), o campo fields detalha quais campos falharam:

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Dados inválidos",
    "fields": [
      { "field": "amount", "message": "Deve ser maior que 0" },
      { "field": "pixKeyType", "message": "Valor inválido" }
    ]
  }
}

Códigos HTTP

| Status | Significado | |---|---| | 200 | Sucesso | | 201 | Recurso criado com sucesso | | 400 | Requisição inválida | | 401 | Não autenticado | | 402 | Saldo insuficiente | | 403 | Sem permissão | | 404 | Recurso não encontrado | | 409 | Conflito de estado | | 422 | Erro de validação | | 429 | Rate limit excedido | | 500 | Erro interno | | 503 | Serviço indisponível |

Códigos de erro

Autenticação

| Código | Status HTTP | Descrição | |---|---|---| | UNAUTHORIZED | 401 | API Key ausente, inválida ou revogada | | FORBIDDEN | 403 | Sem permissão para esta operação | | API_KEY_EXPIRED | 401 | API Key expirada (não se aplica — chaves não expiram atualmente) |

Validação

| Código | Status HTTP | Descrição | |---|---|---| | VALIDATION_ERROR | 422 | Um ou mais campos não passaram na validação | | INVALID_PIX_KEY | 400 | Formato de chave PIX inválido para o tipo especificado | | INVALID_AMOUNT | 400 | Valor deve ser positivo e no máximo 2 casas decimais | | INVALID_QR_CODE | 400 | Código EMV malformado ou não reconhecido |

Saldo e pagamentos

| Código | Status HTTP | Descrição | |---|---|---| | INSUFFICIENT_BALANCE | 402 | Saldo insuficiente para cobrir o valor + taxa | | PAYMENT_FAILED | 400 | Falha no processamento bancário | | PIX_KEY_NOT_FOUND | 400 | Chave PIX não encontrada no sistema bancário | | DUPLICATE_EXTERNAL_REF | 409 | externalRef já usado em outra transação |

Estornos

| Código | Status HTTP | Descrição | |---|---|---| | REFUND_DEADLINE_EXPIRED | 400 | Prazo de 90 dias para estorno expirado | | REFUND_AMOUNT_EXCEEDS_ORIGINAL | 400 | Valor do estorno maior que o original | | ALREADY_REFUNDED | 409 | Transação já foi estornada integralmente | | REFUND_NOT_ALLOWED | 400 | Tipo de transação não suporta estorno |

Webhooks

| Código | Status HTTP | Descrição | |---|---|---| | WEBHOOK_LIMIT_REACHED | 409 | Limite de 10 webhooks por conta atingido | | INVALID_WEBHOOK_URL | 400 | URL deve ser HTTPS | | UNKNOWN_EVENT | 400 | Evento não reconhecido |

Geral

| Código | Status HTTP | Descrição | |---|---|---| | NOT_FOUND | 404 | Recurso não encontrado | | RATE_LIMIT_EXCEEDED | 429 | Limite de requisições atingido | | INTERNAL_ERROR | 500 | Erro interno — tente novamente em alguns instantes | | SERVICE_UNAVAILABLE | 503 | Serviço temporariamente indisponível |

Boas práticas de tratamento de erros

Implementar retry com backoff

Para erros 5xx e 503, implemente retry com backoff exponencial:

async function callWithRetry<T>(
  fn: () => Promise<T>,
  maxRetries = 3
): Promise<T> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn()
    } catch (err: any) {
      const status = err.response?.status
      const shouldRetry = [500, 502, 503, 504].includes(status)
 
      if (!shouldRetry || attempt === maxRetries) throw err
 
      const delay = Math.min(1000 * 2 ** attempt, 30000)
      await new Promise(r => setTimeout(r, delay))
    }
  }
  throw new Error('Max retries reached')
}

Não retentar erros 4xx

Erros 4xx indicam problema na requisição (dados inválidos, saldo insuficiente, etc.). Retentar sem corrigir o problema não vai resolver.

if (error.response?.status >= 400 && error.response?.status < 500) {
  // Trate o erro na lógica da aplicação
  throw new ApplicationError(error.response.data.error.code)
}