Split de Pagamento
Sistema de divisão automática de pagamentos entre conta principal e sub-contas.
O que é Split?
Split é a divisão automática do valor de uma transação entre diferentes contas. Ideal para:
- Marketplaces: Dividir entre plataforma e vendedores
- Agregadores: Distribuir comissões automaticamente
- Plataformas SaaS: Repassar valores para clientes
Como Funciona
mermaid
graph LR
A[Cliente Paga R$ 100] --> B[DiviPay]
B --> C[Conta Principal R$ 10]
B --> D[Sub-conta R$ 90]Tipos de Split
1. Split por Taxa Fixa
Defina um valor fixo que fica na conta principal:
javascript
{
"customerId": "sub_abc123",
"fee": "10.00",
"amount": 100.00
}Resultado:
- R$ 10,00 → Conta principal
- R$ 90,00 → Sub-conta
2. Split Inverso
Use valor negativo para inverter a lógica:
javascript
{
"customerId": "sub_abc123",
"fee": "-10.00",
"amount": 100.00
}Resultado:
- R$ 90,00 → Conta principal
- R$ 10,00 → Sub-conta
3. Split por Percentual (Item)
Configure percentual de comissão por item:
javascript
{
"customerId": "sub_abc123",
"itens": [
{
"name": "Produto A",
"quantity": 1,
"unitPrice": 100.00,
"feePercent": 10.0 // 10%
}
]
}Resultado:
- R$ 10,00 → Conta principal (10% de R$ 100)
- R$ 90,00 → Sub-conta
Exemplos Práticos
Marketplace de Produtos
javascript
async function createMarketplaceSale(sale) {
const marketplaceFee = 0.10; // 10% de comissão
const feeAmount = sale.total * marketplaceFee;
const charge = await auth.request('/api/charge/pix', 'POST', {
customerId: sale.seller.diviPayId,
fee: feeAmount.toFixed(2),
amount: sale.total,
description: `Pedido #${sale.id}`,
referenceId: sale.id,
callbackUrl: `${BASE_URL}/webhook/sale`,
expirationSeconds: 3600,
client: {
name: sale.customer.name,
document: sale.customer.cpf,
email: sale.customer.email,
phone: sale.customer.phone,
ip: sale.customer.ip
},
itens: sale.items.map(item => ({
name: item.name,
quantity: item.quantity,
unitPrice: item.price,
feePercent: marketplaceFee * 100
}))
});
return charge;
}
// Uso
const sale = {
id: 'sale-123',
total: 250.00,
seller: {
id: 'seller-456',
diviPayId: 'sub_abc123'
},
customer: {
name: 'João Silva',
cpf: '12345678901',
email: 'joao@email.com',
phone: '11999999999',
ip: '192.168.1.1'
},
items: [
{
name: 'Produto A',
quantity: 2,
price: 125.00
}
]
};
const charge = await createMarketplaceSale(sale);
// R$ 25,00 para marketplace
// R$ 225,00 para vendedorPlataforma de Serviços
javascript
async function createServicePayment(booking) {
// Taxa fixa de R$ 15,00 + 5% do valor
const fixedFee = 15.00;
const percentFee = booking.amount * 0.05;
const totalFee = fixedFee + percentFee;
const charge = await auth.request('/api/charge/pix', 'POST', {
customerId: booking.provider.diviPayId,
fee: totalFee.toFixed(2),
amount: booking.amount,
description: `Serviço #${booking.id}`,
referenceId: booking.id,
callbackUrl: `${BASE_URL}/webhook/booking`,
expirationSeconds: 1800,
client: {
name: booking.client.name,
document: booking.client.cpf,
email: booking.client.email,
phone: booking.client.phone,
ip: booking.client.ip
},
itens: [
{
name: booking.service.name,
quantity: 1,
unitPrice: booking.amount,
feePercent: 5.0
}
]
});
return charge;
}Agregador de Pagamentos
javascript
async function createAggregatorPayment(payment) {
// Comissão variável por tipo de cliente
const feeRates = {
'premium': 0.02, // 2%
'standard': 0.05, // 5%
'basic': 0.10 // 10%
};
const feeRate = feeRates[payment.client.tier] || 0.05;
const feeAmount = payment.amount * feeRate;
const charge = await auth.request('/api/charge/pix', 'POST', {
customerId: payment.client.diviPayId,
fee: feeAmount.toFixed(2),
amount: payment.amount,
description: payment.description,
referenceId: payment.id,
callbackUrl: `${BASE_URL}/webhook/payment`,
expirationSeconds: 3600,
client: {
name: payment.payer.name,
document: payment.payer.document,
email: payment.payer.email,
phone: payment.payer.phone,
ip: payment.payer.ip
},
itens: [
{
name: payment.description,
quantity: 1,
unitPrice: payment.amount,
feePercent: feeRate * 100
}
]
});
return charge;
}Split com Múltiplos Itens
javascript
async function createMultiItemSale(cart) {
const charge = await auth.request('/api/charge/pix', 'POST', {
customerId: cart.seller.diviPayId,
amount: cart.total,
description: `Pedido #${cart.id}`,
referenceId: cart.id,
callbackUrl: `${BASE_URL}/webhook/cart`,
expirationSeconds: 3600,
client: {
name: cart.customer.name,
document: cart.customer.cpf,
email: cart.customer.email,
phone: cart.customer.phone,
ip: cart.customer.ip
},
itens: cart.items.map(item => ({
name: item.name,
quantity: item.quantity,
unitPrice: item.price,
// Comissão diferente por categoria
feePercent: item.category === 'electronics' ? 5.0 : 10.0
}))
});
return charge;
}
// Exemplo de carrinho
const cart = {
id: 'cart-789',
total: 350.00,
seller: {
diviPayId: 'sub_abc123'
},
customer: {
name: 'Maria Santos',
cpf: '98765432100',
email: 'maria@email.com',
phone: '11988888888',
ip: '192.168.1.2'
},
items: [
{
name: 'Notebook',
quantity: 1,
price: 250.00,
category: 'electronics' // 5% comissão
},
{
name: 'Mouse',
quantity: 2,
price: 50.00,
category: 'accessories' // 10% comissão
}
]
};
// Split resultante:
// Notebook: R$ 12,50 (5% de R$ 250)
// Mouse: R$ 10,00 (10% de R$ 100)
// Total marketplace: R$ 22,50
// Total vendedor: R$ 327,50Calculando Split
Função Helper
javascript
function calculateSplit(amount, feePercent) {
const fee = amount * (feePercent / 100);
const sellerAmount = amount - fee;
return {
total: amount,
platformFee: parseFloat(fee.toFixed(2)),
sellerAmount: parseFloat(sellerAmount.toFixed(2)),
feePercent
};
}
// Uso
const split = calculateSplit(100.00, 10);
console.log(split);
// {
// total: 100.00,
// platformFee: 10.00,
// sellerAmount: 90.00,
// feePercent: 10
// }Validação de Split
javascript
function validateSplit(amount, fee) {
if (fee < 0) {
throw new Error('Fee cannot be negative');
}
if (fee >= amount) {
throw new Error('Fee cannot be greater than or equal to amount');
}
const sellerAmount = amount - fee;
if (sellerAmount < 1.00) {
throw new Error('Seller amount must be at least R$ 1.00');
}
return true;
}Webhooks com Split
Quando um pagamento com split é confirmado, ambas as contas recebem webhook:
Webhook Conta Principal
json
{
"event": "charge.paid",
"chargeId": "cob_abc123",
"referenceId": "sale-123",
"amount": 100.00,
"platformFee": 10.00,
"sellerAmount": 90.00,
"customerId": "sub_abc123",
"paidAt": "2024-11-04T15:30:00.000Z"
}Webhook Sub-conta
json
{
"event": "charge.paid",
"chargeId": "cob_abc123",
"referenceId": "sale-123",
"amount": 90.00,
"receivedAmount": 90.00,
"paidAt": "2024-11-04T15:30:00.000Z"
}Relatórios de Split
javascript
async function getSplitReport(startDate, endDate) {
const charges = await db.charges.findMany({
where: {
paidAt: {
gte: startDate,
lte: endDate
},
customerId: { not: null }
}
});
const report = {
totalTransactions: charges.length,
totalAmount: 0,
totalPlatformFee: 0,
totalSellerAmount: 0,
bySeller: {}
};
charges.forEach(charge => {
report.totalAmount += charge.amount;
report.totalPlatformFee += charge.fee;
report.totalSellerAmount += (charge.amount - charge.fee);
if (!report.bySeller[charge.customerId]) {
report.bySeller[charge.customerId] = {
transactions: 0,
amount: 0,
fee: 0,
received: 0
};
}
const seller = report.bySeller[charge.customerId];
seller.transactions++;
seller.amount += charge.amount;
seller.fee += charge.fee;
seller.received += (charge.amount - charge.fee);
});
return report;
}Boas Práticas
1. Transparência
Mostre claramente a divisão para vendedores:
javascript
function displaySplitInfo(amount, feePercent) {
const split = calculateSplit(amount, feePercent);
return `
Valor total: R$ ${split.total.toFixed(2)}
Taxa da plataforma (${feePercent}%): R$ ${split.platformFee.toFixed(2)}
Você receberá: R$ ${split.sellerAmount.toFixed(2)}
`;
}2. Validação
Valide valores antes de criar cobrança:
javascript
function validateChargeWithSplit(data) {
if (data.fee && data.fee >= data.amount) {
throw new Error('Fee must be less than amount');
}
const sellerAmount = data.amount - (data.fee || 0);
if (sellerAmount < 1.00) {
throw new Error('Seller must receive at least R$ 1.00');
}
}3. Auditoria
Registre todas as operações de split:
javascript
await db.splitLog.create({
data: {
chargeId: charge.id,
amount: charge.amount,
fee: charge.fee,
customerId: charge.customerId,
createdAt: new Date()
}
});