Skip to content

Tratamento de Erros

Guia completo para entender e tratar erros da API DiviPay.

Códigos de Status HTTP

CódigoSignificadoDescrição
200OKRequisição bem-sucedida (GET)
201CreatedRecurso criado com sucesso (POST)
400Bad RequestDados inválidos na requisição
401UnauthorizedCredenciais inválidas
403ForbiddenToken inválido ou sem permissão
404Not FoundRecurso não encontrado
412Precondition FailedPré-condição não atendida
422Unprocessable EntityValidação de negócio falhou
429Too Many RequestsRate limit excedido
500Internal Server ErrorErro interno do servidor
503Service UnavailableServiço temporariamente indisponível

Formato de Erro

Todos os erros seguem o mesmo formato:

json
{
  "statusCode": 400,
  "message": "Validation failed",
  "error": "Bad Request",
  "errors": [
    "amount must be a positive number",
    "client.document must be a valid CPF or CNPJ"
  ]
}

Erros Comuns

401 Unauthorized

Causa: Credenciais inválidas ou API não habilitada.

json
{
  "statusCode": 401,
  "message": "Unauthorized",
  "error": "Invalid credentials"
}

Solução:

  • Verifique client_id e client_secret
  • Confirme que a API está habilitada no painel
  • Verifique se não há espaços extras

403 Forbidden

Causa: Token inválido, expirado ou sem permissão.

json
{
  "statusCode": 403,
  "message": "Forbidden"
}

Solução:

  • Renove o token
  • Verifique se o token está correto
  • Confirme que o token não expirou

400 Bad Request

Causa: Dados inválidos na requisição.

json
{
  "statusCode": 400,
  "message": "Validation failed",
  "errors": [
    "amount must be a positive number",
    "description is required"
  ]
}

Solução:

  • Valide todos os campos obrigatórios
  • Verifique tipos de dados
  • Confirme formato dos valores

404 Not Found

Causa: Recurso não encontrado.

json
{
  "statusCode": 404,
  "message": "Charge not found",
  "error": "Not Found"
}

Solução:

  • Verifique se o ID está correto
  • Confirme que o recurso existe
  • Verifique permissões de acesso

412 Precondition Failed

Causa: Operação não permitida no estado atual.

json
{
  "statusCode": 412,
  "message": "Cannot cancel a paid charge",
  "error": "Precondition Failed"
}

Solução:

  • Verifique o status do recurso
  • Confirme se a operação é permitida
  • Consulte a documentação da operação

429 Too Many Requests

Causa: Rate limit excedido.

json
{
  "statusCode": 429,
  "message": "Too many requests",
  "error": "Rate limit exceeded",
  "retryAfter": 60
}

Solução:

  • Aguarde o tempo indicado em retryAfter
  • Implemente backoff exponencial
  • Reduza frequência de requisições

Tratamento de Erros

JavaScript

javascript
class DiviPayError extends Error {
  constructor(statusCode, message, errors = []) {
    super(message);
    this.name = 'DiviPayError';
    this.statusCode = statusCode;
    this.errors = errors;
  }
}

async function makeRequest(endpoint, options) {
  try {
    const response = await fetch(endpoint, options);
    
    if (!response.ok) {
      const error = await response.json();
      throw new DiviPayError(
        error.statusCode,
        error.message,
        error.errors
      );
    }
    
    return await response.json();
    
  } catch (error) {
    if (error instanceof DiviPayError) {
      // Erro da API
      console.error('API Error:', error.message);
      console.error('Status:', error.statusCode);
      console.error('Details:', error.errors);
      
      // Tratar por tipo
      switch (error.statusCode) {
        case 401:
          // Reautenticar
          await authenticate();
          return makeRequest(endpoint, options);
          
        case 429:
          // Aguardar e tentar novamente
          await sleep(60000);
          return makeRequest(endpoint, options);
          
        case 500:
        case 503:
          // Tentar novamente com backoff
          return retryWithBackoff(() => makeRequest(endpoint, options));
          
        default:
          throw error;
      }
    } else {
      // Erro de rede ou outro
      console.error('Network Error:', error);
      throw error;
    }
  }
}

// Retry com backoff exponencial
async function retryWithBackoff(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      
      const delay = Math.pow(2, i) * 1000;
      console.log(`Retry ${i + 1}/${maxRetries} after ${delay}ms`);
      await sleep(delay);
    }
  }
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

PHP

php
<?php
class DiviPayException extends Exception {
    private $statusCode;
    private $errors;

    public function __construct($statusCode, $message, $errors = []) {
        parent::__construct($message);
        $this->statusCode = $statusCode;
        $this->errors = $errors;
    }

    public function getStatusCode() {
        return $this->statusCode;
    }

    public function getErrors() {
        return $this->errors;
    }
}

function makeRequest($endpoint, $method = 'GET', $data = null) {
    $ch = curl_init($endpoint);
    
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
    
    if ($data) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
    }
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    $data = json_decode($response, true);
    
    if ($httpCode < 200 || $httpCode >= 300) {
        throw new DiviPayException(
            $data['statusCode'] ?? $httpCode,
            $data['message'] ?? 'Unknown error',
            $data['errors'] ?? []
        );
    }
    
    return $data;
}

// Uso com tratamento
try {
    $charge = makeRequest('/api/charge/pix', 'POST', $chargeData);
    echo "Cobrança criada: " . $charge['id'];
    
} catch (DiviPayException $e) {
    error_log("API Error: " . $e->getMessage());
    error_log("Status: " . $e->getStatusCode());
    error_log("Errors: " . json_encode($e->getErrors()));
    
    switch ($e->getStatusCode()) {
        case 401:
            // Reautenticar
            authenticate();
            break;
            
        case 400:
            // Mostrar erros de validação
            foreach ($e->getErrors() as $error) {
                echo "Erro: $error\n";
            }
            break;
            
        default:
            throw $e;
    }
}
?>

Python

python
class DiviPayError(Exception):
    def __init__(self, status_code, message, errors=None):
        super().__init__(message)
        self.status_code = status_code
        self.errors = errors or []

def make_request(endpoint, method='GET', data=None):
    try:
        if method == 'GET':
            response = requests.get(endpoint)
        elif method == 'POST':
            response = requests.post(endpoint, json=data)
        elif method == 'PUT':
            response = requests.put(endpoint, json=data)
        elif method == 'DELETE':
            response = requests.delete(endpoint)
        
        if response.status_code < 200 or response.status_code >= 300:
            error_data = response.json()
            raise DiviPayError(
                error_data.get('statusCode', response.status_code),
                error_data.get('message', 'Unknown error'),
                error_data.get('errors', [])
            )
        
        return response.json()
        
    except DiviPayError as e:
        print(f'API Error: {e}')
        print(f'Status: {e.status_code}')
        print(f'Errors: {e.errors}')
        
        if e.status_code == 401:
            # Reautenticar
            authenticate()
            return make_request(endpoint, method, data)
        elif e.status_code == 429:
            # Aguardar e tentar novamente
            time.sleep(60)
            return make_request(endpoint, method, data)
        else:
            raise

# Uso
try:
    charge = make_request('/api/charge/pix', 'POST', charge_data)
    print(f'Cobrança criada: {charge["id"]}')
except DiviPayError as e:
    print(f'Erro ao criar cobrança: {e}')

Validação de Dados

Antes de Enviar

javascript
function validateChargeData(data) {
  const errors = [];
  
  if (!data.amount || data.amount <= 0) {
    errors.push('Amount must be positive');
  }
  
  if (!data.description || data.description.length > 25) {
    errors.push('Description is required (max 25 chars)');
  }
  
  if (!data.client?.document || !isValidCPF(data.client.document)) {
    errors.push('Valid CPF/CNPJ is required');
  }
  
  if (!data.client?.email || !isValidEmail(data.client.email)) {
    errors.push('Valid email is required');
  }
  
  if (errors.length > 0) {
    throw new Error(`Validation failed:\n${errors.join('\n')}`);
  }
}

// Uso
try {
  validateChargeData(chargeData);
  const charge = await createCharge(chargeData);
} catch (error) {
  console.error('Validation error:', error.message);
}

Logging de Erros

javascript
function logError(error, context = {}) {
  const errorLog = {
    timestamp: new Date().toISOString(),
    error: {
      name: error.name,
      message: error.message,
      statusCode: error.statusCode,
      errors: error.errors,
      stack: error.stack
    },
    context
  };
  
  // Em produção, enviar para serviço de logging
  if (process.env.NODE_ENV === 'production') {
    sendToLoggingService(errorLog);
  } else {
    console.error(JSON.stringify(errorLog, null, 2));
  }
}

// Uso
try {
  await createCharge(data);
} catch (error) {
  logError(error, {
    operation: 'createCharge',
    userId: user.id,
    chargeData: data
  });
}

Monitoramento

javascript
class ErrorMonitor {
  constructor() {
    this.errors = [];
  }

  track(error) {
    this.errors.push({
      timestamp: Date.now(),
      statusCode: error.statusCode,
      message: error.message
    });
    
    // Limpar erros antigos (> 1 hora)
    const oneHourAgo = Date.now() - 60 * 60 * 1000;
    this.errors = this.errors.filter(e => e.timestamp > oneHourAgo);
    
    // Alertar se muitos erros
    if (this.errors.length > 10) {
      this.sendAlert('High error rate detected');
    }
  }

  sendAlert(message) {
    console.error('🚨 ALERT:', message);
    // Enviar para sistema de alertas
  }
}

const monitor = new ErrorMonitor();

// Uso
try {
  await createCharge(data);
} catch (error) {
  monitor.track(error);
  throw error;
}

Próximos Passos

Documentação da API DiviPay