Skip to content

Cancelar Cobrança

Cancela uma cobrança antes do pagamento ser realizado.

IMPORTANTE

O cancelamento só é possível antes do pagamento. Após o pagamento, use Estornar.

DELETE /api/charge/

Cancela uma cobrança genérica (Link de Pagamento).

Endpoint

DELETE https://api.divipay.com.br/api/charge/{chargeId}

Headers

HeaderValorObrigatório
AuthorizationBearerSim

Path Parameters

ParâmetroTipoDescrição
chargeIdstringID da cobrança

Exemplo de Requisição

bash
curl -X DELETE https://api.divipay.com.br/api/charge/cob_abc123 \
  -H "Authorization: Bearer SEU_TOKEN"
javascript
const response = await fetch(
  'https://api.divipay.com.br/api/charge/cob_abc123',
  {
    method: 'DELETE',
    headers: {
      'Authorization': 'Bearer SEU_TOKEN'
    }
  }
);

const result = await response.json();
python
import requests

response = requests.delete(
    'https://api.divipay.com.br/api/charge/cob_abc123',
    headers={
        'Authorization': 'Bearer SEU_TOKEN'
    }
)

result = response.json()

Resposta de Sucesso

Status: 200 OK

json
{
  "id": "cob_abc123",
  "status": "CANCELED",
  "message": "Charge canceled successfully"
}

DELETE /api/charge/{chargeId}/pix

Cancela uma cobrança Pix específica.

Endpoint

DELETE https://api.divipay.com.br/api/charge/{chargeId}/pix

Exemplo de Requisição

bash
curl -X DELETE https://api.divipay.com.br/api/charge/cob_abc123/pix \
  -H "Authorization: Bearer SEU_TOKEN"

Resposta

json
{
  "id": "cob_abc123",
  "status": "CANCELED",
  "canceledAt": "2024-11-04T15:45:00.000Z"
}

Exemplo de Uso

Cancelar Cobrança

javascript
async function cancelCharge(chargeId) {
  try {
    const response = await fetch(
      `https://api.divipay.com.br/api/charge/${chargeId}`,
      {
        method: 'DELETE',
        headers: {
          'Authorization': `Bearer ${token}`
        }
      }
    );

    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.message);
    }

    const result = await response.json();
    console.log('✅ Cobrança cancelada:', result.id);
    return result;

  } catch (error) {
    console.error('❌ Erro ao cancelar:', error.message);
    throw error;
  }
}

// Uso
await cancelCharge('cob_abc123');

Cancelar com Verificação

javascript
async function safeCancelCharge(chargeId) {
  try {
    // 1. Verificar status atual
    const charge = await fetch(
      `https://api.divipay.com.br/api/charge/${chargeId}`,
      {
        headers: { 'Authorization': `Bearer ${token}` }
      }
    ).then(r => r.json());

    // 2. Verificar se pode cancelar
    if (charge.status === 'PAID') {
      throw new Error('Cobrança já foi paga. Use estorno.');
    }

    if (charge.status === 'CANCELED') {
      console.log('Cobrança já está cancelada');
      return charge;
    }

    if (charge.status === 'EXPIRED') {
      console.log('Cobrança já expirou');
      return charge;
    }

    // 3. Cancelar
    const response = await fetch(
      `https://api.divipay.com.br/api/charge/${chargeId}`,
      {
        method: 'DELETE',
        headers: { 'Authorization': `Bearer ${token}` }
      }
    );

    const result = await response.json();
    console.log('✅ Cobrança cancelada com sucesso');
    return result;

  } catch (error) {
    console.error('❌ Erro:', error.message);
    throw error;
  }
}

Cancelar Pedido Completo

javascript
async function cancelOrder(orderId) {
  try {
    // 1. Buscar cobrança no banco
    const order = await db.orders.findUnique({
      where: { id: orderId },
      include: { charge: true }
    });

    if (!order.charge) {
      throw new Error('Pedido sem cobrança associada');
    }

    // 2. Cancelar cobrança na DiviPay
    await cancelCharge(order.charge.chargeId);

    // 3. Atualizar banco de dados
    await db.orders.update({
      where: { id: orderId },
      data: {
        status: 'CANCELED',
        canceledAt: new Date()
      }
    });

    // 4. Notificar cliente
    await sendCancellationEmail(order.customer.email, orderId);

    console.log(`✅ Pedido ${orderId} cancelado`);

  } catch (error) {
    console.error('❌ Erro ao cancelar pedido:', error);
    throw error;
  }
}

Cancelamento em Lote

javascript
async function cancelMultipleCharges(chargeIds) {
  const results = {
    success: [],
    failed: []
  };

  for (const chargeId of chargeIds) {
    try {
      await cancelCharge(chargeId);
      results.success.push(chargeId);
    } catch (error) {
      results.failed.push({
        chargeId,
        error: error.message
      });
    }
  }

  console.log(`✅ Canceladas: ${results.success.length}`);
  console.log(`❌ Falharam: ${results.failed.length}`);

  return results;
}

// Uso
const results = await cancelMultipleCharges([
  'cob_abc123',
  'cob_def456',
  'cob_ghi789'
]);

Interface de Cancelamento

javascript
// React Component
function CancelChargeButton({ chargeId, onCancel }) {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  async function handleCancel() {
    if (!confirm('Tem certeza que deseja cancelar esta cobrança?')) {
      return;
    }

    setLoading(true);
    setError(null);

    try {
      await cancelCharge(chargeId);
      alert('Cobrança cancelada com sucesso!');
      onCancel?.();
    } catch (err) {
      setError(err.message);
      alert('Erro ao cancelar: ' + err.message);
    } finally {
      setLoading(false);
    }
  }

  return (
    <div>
      <button 
        onClick={handleCancel} 
        disabled={loading}
        style={{ 
          backgroundColor: 'red', 
          color: 'white',
          padding: '10px 20px',
          border: 'none',
          borderRadius: '5px',
          cursor: loading ? 'not-allowed' : 'pointer'
        }}
      >
        {loading ? 'Cancelando...' : 'Cancelar Cobrança'}
      </button>
      {error && <p style={{ color: 'red' }}>{error}</p>}
    </div>
  );
}

Webhook

Quando uma cobrança é cancelada, você recebe:

json
{
  "event": "charge.canceled",
  "chargeId": "cob_abc123",
  "referenceId": "pedido-123",
  "amount": 100.00,
  "canceledAt": "2024-11-04T15:45:00.000Z",
  "status": "CANCELED",
  "reason": "Cancelado pelo vendedor"
}

Respostas de Erro

412 Precondition Failed

Cobrança já foi paga.

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

Solução: Use Estornar para cobranças pagas.

404 Not Found

Cobrança não encontrada.

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

403 Forbidden

Sem permissão para cancelar.

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

Casos de Uso

1. Cliente Desistiu da Compra

javascript
async function handleCustomerCancellation(orderId, reason) {
  try {
    await cancelOrder(orderId);
    
    await db.cancellations.create({
      data: {
        orderId,
        reason,
        canceledBy: 'CUSTOMER',
        canceledAt: new Date()
      }
    });

    console.log('Pedido cancelado pelo cliente');
  } catch (error) {
    console.error('Erro:', error);
  }
}

2. Produto Fora de Estoque

javascript
async function handleOutOfStock(orderId) {
  try {
    await cancelOrder(orderId);
    
    await sendEmail({
      to: order.customer.email,
      subject: 'Pedido Cancelado - Produto Indisponível',
      body: 'Infelizmente o produto está fora de estoque...'
    });

    console.log('Pedido cancelado por falta de estoque');
  } catch (error) {
    console.error('Erro:', error);
  }
}

3. Cancelamento Automático por Timeout

javascript
async function cancelExpiredCharges() {
  const expiredCharges = await db.charges.findMany({
    where: {
      status: 'PENDING',
      createdAt: {
        lt: new Date(Date.now() - 24 * 60 * 60 * 1000) // 24h atrás
      }
    }
  });

  for (const charge of expiredCharges) {
    try {
      await cancelCharge(charge.chargeId);
      console.log(`Cobrança ${charge.chargeId} cancelada por timeout`);
    } catch (error) {
      console.error(`Erro ao cancelar ${charge.chargeId}:`, error);
    }
  }
}

// Executar diariamente
setInterval(cancelExpiredCharges, 24 * 60 * 60 * 1000);

Boas Práticas

1. Sempre Verificar Status

javascript
// ✅ BOM
const charge = await getCharge(chargeId);
if (charge.status === 'PENDING') {
  await cancelCharge(chargeId);
}

// ❌ RUIM
await cancelCharge(chargeId); // Pode falhar se já foi pago

2. Registrar Motivo

javascript
await db.charges.update({
  where: { id: chargeId },
  data: {
    status: 'CANCELED',
    cancelReason: 'Cliente desistiu',
    canceledBy: userId,
    canceledAt: new Date()
  }
});

3. Notificar Cliente

javascript
async function cancelWithNotification(chargeId, reason) {
  const charge = await cancelCharge(chargeId);
  
  await sendEmail({
    to: charge.customer.email,
    subject: 'Cobrança Cancelada',
    body: `Sua cobrança foi cancelada. Motivo: ${reason}`
  });
}

4. Tratamento de Erros

javascript
try {
  await cancelCharge(chargeId);
} catch (error) {
  if (error.message.includes('paid')) {
    console.log('Use estorno para cobranças pagas');
  } else if (error.message.includes('not found')) {
    console.log('Cobrança não existe');
  } else {
    console.error('Erro desconhecido:', error);
  }
}

Próximos Passos

Documentação da API DiviPay