Tratamento de Erros

O Toktus API utiliza códigos HTTP padrão e retorna erros em formato JSON consistente.

Formato Padrão de Erro

Todas as respostas de erro seguem este formato:

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Descrição legível do problema"
  }
}
CampoDescrição
successSempre false para erros
error.codeCódigo programático do erro (use para lógica condicional)
error.messageMensagem descritiva (pode exibir ao usuário ou logar)

[!NOTE]
O campo error.details existe apenas em ambiente de desenvolvimento (NODE_ENV=development). Em produção, os erros retornam somente code e message.

Códigos HTTP

HTTPSignificadoAção
200SucessoProcessar resposta normalmente
201Criado com sucessoRecurso foi criado
400Requisição inválidaCorrigir dados enviados
401Não autenticadoVerificar API Key
403Conta inativaContatar suporte
404Não encontradoRecurso não existe
400Credenciais não cadastradasCadastrar via POST /api/v1/credentials
422Operação não suportadaGateway não suporta esta operação
429Rate limit excedidoAguardar antes de tentar novamente
502Erro do gatewayProblema no gateway, verificar status
502Gateway inacessívelGateway offline ou sem conexão
504Timeout do gatewayGateway demorou muito, tentar novamente

Erros por Categoria

Autenticação (HTTP 401 / 403)

```json
{
  "success": false,
  "error": {
    "code": "MISSING_API_KEY",
    "message": "Header x-api-key is required"
  }
}
```

**Solução:**
```javascript
// Incorrect — missing x-api-key header
fetch('https://api.toktus.com/api/v1/customers', { method: 'POST' });

// Correct — include x-api-key in every authenticated request
fetch('https://api.toktus.com/api/v1/customers', {
  method: 'POST',
  headers: { 'x-api-key': process.env.TOKTUS_API_API_KEY }
});
```



```json
{
  "success": false,
  "error": {
    "code": "INVALID_API_KEY",
    "message": "The provided API key is invalid"
  }
}
```

**Causas:** API Key incorreta ou revogada.



```json
{
  "success": false,
  "error": {
    "code": "CLIENT_INACTIVE",
    "message": "Your account has been deactivated"
  }
}
```

**Solução:** Entre em contato com o suporte para reativar sua conta.



```json
{
  "success": false,
  "error": {
    "code": "GATEWAY_AUTH_ERROR",
    "message": "Credenciais inválidas para o gateway \"pagarme\". Verifique a apiKey/secretKey cadastrada.",
    "gateway": "pagarme"
  }
}
```

**Solução:** Atualize as credenciais via `POST /api/v1/credentials`.

[!NOTE]
O HTTP status reflete o código retornado pelo gateway: 401 ou 403 dependendo do provedor.

Validação (HTTP 400)

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Dados inválidos na requisição",
    "details": {
      "errors": [
        { "field": "amount", "message": "Valor mínimo é 100 centavos (R$ 1,00)" },
        { "field": "email", "message": "Formato de e-mail inválido" }
      ]
    }
  }
}

Causas comuns: Campos obrigatórios ausentes, tipos de dados incorretos, valores fora dos limites, formato inválido.

Exemplo de validação preventiva:

const Joi = require('joi');

const chargeSchema = Joi.object({
  gateway: Joi.string().valid('stripe', 'pagarme', 'asaas', 'mercadopago', 'pagseguro').required(),
  paymentMethod: Joi.string().valid('credit_card', 'boleto', 'pix').required(),
  amount: Joi.number().integer().min(100).required(),
  customer: Joi.object({
    name: Joi.string().min(3).max(100).required(),
    email: Joi.string().email().required(),
    document: Joi.string().pattern(/^\d{11}$|^\d{14}$/).required()
  })
});

Recurso Não Encontrado (HTTP 404)

```json
{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "Cliente 'cus_abc123' não encontrado no gateway Stripe"
  }
}
```

**Causas:** ID incorreto, recurso deletado, recurso pertence a outra conta, gateway errado.



```json
{
  "success": false,
  "error": {
    "code": "MISSING_CREDENTIALS",
    "message": "Credenciais do gateway \"stripe\" não cadastradas. Faça POST /api/v1/credentials com as chaves desse gateway antes de usar esse endpoint."
  }
}
```

**Solução:** Cadastre as credenciais via `POST /api/v1/credentials` antes de operar.

Timeout (HTTP 504)

{
  "success": false,
  "error": {
    "code": "GATEWAY_TIMEOUT",
    "message": "O gateway Stripe não respondeu dentro do tempo limite (30 segundos)."
  }
}

Estratégia de retry com exponential backoff:

async function createChargeWithRetry(data, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch('https://api.toktus.com/api/v1/charges', {
        method: 'POST',
        headers: {
          'x-api-key': API_KEY,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(data)
      });

      if (response.status === 504 && attempt < maxRetries) {
        await sleep(Math.pow(2, attempt) * 1000); // 2s, 4s, 8s
        continue;
      }

      return await response.json();
    } catch (error) {
      if (attempt === maxRetries) throw error;
      await sleep(2000);
    }
  }
}

Operação Não Suportada (HTTP 422)

{
  "success": false,
  "error": {
    "code": "GATEWAY_UNSUPPORTED_OPERATION",
    "message": "Asaas exige \"customerId\" em toda cobrança. Crie um customer antes (POST /api/v1/customers) e envie o externalId retornado."
  }
}

Rate Limit (HTTP 429)

{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Limite de requisições excedido."
  }
}

Headers incluídos:

  • Retry-After: 45 (segundos)
  • X-RateLimit-Limit: 100
  • X-RateLimit-Remaining: 0
  • X-RateLimit-Reset: 60 (segundos até reset)
async function makeRequest(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.status === 429) {
      const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
      await sleep(retryAfter * 1000);
      continue;
    }

    return response;
  }
}

Erro do Gateway (HTTP 502)

{
  "success": false,
  "error": {
    "code": "GATEWAY_ERROR",
    "message": "Erro retornado pelo gateway Stripe: Card declined",
    "gateway": "stripe"
  }
}

Erros comuns de gateway:

Gateway CodeSignificadoAção
card_declinedCartão recusadoSolicitar outro cartão
insufficient_fundsSaldo insuficienteSolicitar outro método
expired_cardCartão vencidoAtualizar dados do cartão
incorrect_cvcCVV incorretoVerificar CVV
processing_errorErro de processamentoTentar novamente

Tratamento com mensagens amigáveis:

const ERROR_MESSAGES = {
  card_declined: 'Seu cartão foi recusado. Por favor, tente outro cartão.',
  insufficient_funds: 'Saldo insuficiente. Por favor, use outro cartão.',
  expired_card: 'Seu cartão está vencido. Por favor, atualize os dados.',
  incorrect_cvc: 'Código de segurança (CVV) incorreto.',
  processing_error: 'Erro no processamento. Por favor, tente novamente.'
};

Gateway Inacessível (HTTP 502)

{
  "success": false,
  "error": {
    "code": "GATEWAY_UNREACHABLE",
    "message": "Não foi possível estabelecer conexão com o gateway Stripe."
  }
}

Solução: Implemente circuit breaker ou fallback para gateways alternativos.

Estratégias de Tratamento

Fallback para Gateways Alternativos

const GATEWAY_PRIORITY = ['stripe', 'pagarme', 'asaas'];

async function createChargeWithFallback(data) {
  for (const gateway of GATEWAY_PRIORITY) {
    try {
      data.gateway = gateway;
      return await createCharge(data);
    } catch (error) {
      console.warn(`Falha em ${gateway}:`, error.message);
      if (gateway === GATEWAY_PRIORITY.at(-1)) throw error;
    }
  }
}

Referência Rápida

CódigoHTTPRetry?Ação
VALIDATION_ERROR400NãoCorrigir dados enviados
MISSING_API_KEY401NãoAdicionar header x-api-key
INVALID_API_KEY401NãoVerificar API Key
GATEWAY_AUTH_ERROR401 / 403NãoAtualizar credenciais do gateway
CLIENT_INACTIVE403NãoContatar suporte
NOT_FOUND404NãoVerificar ID do recurso
MISSING_CREDENTIALS400NãoCadastrar credenciais via POST /api/v1/credentials
GATEWAY_UNSUPPORTED_OPERATION422NãoUsar método alternativo
RATE_LIMIT_EXCEEDED429SimAguardar Retry-After
GATEWAY_ERROR502CondicionalDepende do erro retornado pelo gateway
GATEWAY_UNREACHABLE502SimCircuit breaker / fallback
GATEWAY_TIMEOUT504SimRetry com exponential backoff