Visão Geral
Os webhooks de PIX Cash Out notificam seu sistema em tempo real sobre o status das transferências PIX realizadas, permitindo que você acompanhe e processe as operações de saque com eficiência.
Os webhooks de cash out seguem o mesmo padrão de segurança dos webhooks de cash in.
Status dos Webhooks
WITHDRAW_REQUEST
Transferência PIX foi iniciada e está sendo processada pelo provedor.
WITHDRAW_PAID
Transferência PIX foi executada com sucesso. Valor debitado da conta.
REFUND_IN
Estorno de PIX enviado. Valor previamente cobrado foi devolvido para conta de origem.
ERROR
Transferência PIX falhou durante o processamento. Valor não foi debitado.
Payload dos Webhooks
Transferência Concluída (Status: WITHDRAW_PAID)
{
"transactionId" : "withdraw-abc123-def456-ghi789" ,
"businessTransactionId" : "transfer-789012" ,
"status" : "WITHDRAW_PAID" ,
"value" : 25050 ,
"movementType" : "DEBIT" ,
"endToEndId" : "E00416968202401151530150123456789" ,
"pixKey" : "[email protected] " ,
"createdDate" : "2024-01-15T15:30:15.123Z" ,
"ReceiverBankAccount" : "123456" ,
"ReceiverToBankAccountDigit" : "7" ,
"ReceiverBankBranch" : "0001" ,
"ReceiverBankCode" : "077" ,
"ReceiverDocumentNumber" : "12345678901" ,
"ReceiverBankName" : "BANCO INTER S.A." ,
"ReceiverBankISPB" : "00416968" ,
"ReceiverName" : "ANA SILVA SANTOS" ,
"PayerBankAccount" : "567890" ,
"PayerBankAccountDigit" : "1" ,
"PayerBankBranch" : "0001" ,
"PayerBankCode" : "077" ,
"PayerDocumentNumber" : "45438750000188" ,
"PayerBankName" : "BANCO INTER S.A." ,
"PayerBankISPB" : "00416968" ,
"PayerName" : "MINHA EMPRESA LTDA" ,
"VoucherUrl" : "https://voucher.firebanking.com/withdraw/withdraw-abc123-def456-ghi789.pdf"
}
{
"transactionId" : "error-withdraw-123456789" ,
"businessTransactionId" : "transfer-erro-789012" ,
"status" : "ERROR" ,
"value" : 25050 ,
"movementType" : null ,
"endToEndId" : null ,
"pixKey" : "[email protected] " ,
"createdDate" : "2024-01-15T15:30:15.123Z" ,
"ReceiverBankAccount" : null ,
"ReceiverToBankAccountDigit" : null ,
"ReceiverBankBranch" : null ,
"ReceiverBankCode" : null ,
"ReceiverDocumentNumber" : null ,
"ReceiverBankName" : null ,
"ReceiverBankISPB" : null ,
"ReceiverName" : null ,
"PayerBankAccount" : null ,
"PayerBankAccountDigit" : null ,
"PayerBankBranch" : null ,
"PayerBankCode" : null ,
"PayerDocumentNumber" : null ,
"PayerBankName" : null ,
"PayerBankISPB" : null ,
"PayerName" : null ,
"VoucherUrl" : null
}
Estorno Enviado (Status: REFUND_IN)
{
"transactionId" : "8f7e6d5c-4b3a-2918-7654-3210fedcba98" ,
"businessTransactionId" : "estorno-pedido-12345" ,
"status" : "REFUND_IN" ,
"value" : 15000 ,
"movementType" : "DEBIT" ,
"endToEndId" : "E00000000202401151700300987654321" ,
"pixKey" : "[email protected] " ,
"createdDate" : "2024-01-15T17:00:30.123Z" ,
"ReceiverBankAccount" : "123456" ,
"ReceiverToBankAccountDigit" : "7" ,
"ReceiverBankBranch" : "0001" ,
"ReceiverBankCode" : "001" ,
"ReceiverDocumentNumber" : "12345678901" ,
"ReceiverBankName" : "BANCO DO BRASIL S.A." ,
"ReceiverBankISPB" : "00000000" ,
"ReceiverName" : "JOAO COSTA SILVA" ,
"PayerBankAccount" : "567890" ,
"PayerBankAccountDigit" : "1" ,
"PayerBankBranch" : "0001" ,
"PayerBankCode" : "077" ,
"PayerDocumentNumber" : "45438750000188" ,
"PayerBankName" : "BANCO INTER S.A." ,
"PayerBankISPB" : "00416968" ,
"PayerName" : "MINHA EMPRESA LTDA" ,
"VoucherUrl" : "https://voucher.firebanking.com/refund/8f7e6d5c-4b3a-2918-7654-3210fedcba98.pdf"
}
Transferência Solicitada (Status: WITHDRAW_REQUEST)
{
"transactionId" : "pending-qr-789012345" ,
"businessTransactionId" : "qr-transfer-001" ,
"status" : "WITHDRAW_REQUEST" ,
"value" : 15000 ,
"movementType" : "DEBIT" ,
"endToEndId" : null ,
"pixKey" : "00020101021226830014br.gov.bcb.pix2584" ,
"createdDate" : "2024-01-15T16:45:05.123Z" ,
"ReceiverBankAccount" : "456789" ,
"ReceiverToBankAccountDigit" : "0" ,
"ReceiverBankBranch" : "0001" ,
"ReceiverBankCode" : "001" ,
"ReceiverDocumentNumber" : "98765432100" ,
"ReceiverBankName" : "BANCO DO BRASIL S.A." ,
"ReceiverBankISPB" : "00000000" ,
"ReceiverName" : "MARIA SANTOS" ,
"PayerBankAccount" : "567890" ,
"PayerBankAccountDigit" : "1" ,
"PayerBankBranch" : "0001" ,
"PayerBankCode" : "077" ,
"PayerDocumentNumber" : "45438750000188" ,
"PayerBankName" : "BANCO INTER S.A." ,
"PayerBankISPB" : "00416968" ,
"PayerName" : "MINHA EMPRESA LTDA" ,
"VoucherUrl" : null
}
Implementação do Webhook
Node.js - Processamento de Cash Out
Python - Análise de Transferências
app . post ( '/webhooks/pix-cashout' , ( req , res ) => {
const signature = req . headers [ 'x-firebanking-signature' ];
const payload = req . body ;
if ( ! verifySignature ( payload , signature )) {
return res . status ( 401 ). send ( 'Unauthorized' );
}
const webhook = JSON . parse ( payload );
switch ( webhook . operation . status ) {
case 'WITHDRAW_REQUEST' :
handleWithdrawRequested ( webhook );
break ;
case 'WITHDRAW_PAID' :
handleWithdrawCompleted ( webhook );
break ;
case 'REFUND_IN' :
handleRefundSent ( webhook );
break ;
case 'ERROR' :
handleWithdrawFailed ( webhook );
break ;
}
res . status ( 200 ). send ( 'OK' );
});
function handleWithdrawCompleted ( transaction ) {
const valueBrl = transaction . operation . value / 100 ;
const feeBrl = transaction . operation . fee / 100 ;
const resultBrl = transaction . operation . result / 100 ;
console . log ( `Transferência PIX concluída: ${ transaction . operation . externalID } ` );
console . log ( `Beneficiário: ${ transaction . receiver . fullName } ` );
console . log ( `Valor: R$ ${ valueBrl } (Taxa: R$ ${ feeBrl } , Líquido: R$ ${ resultBrl } )` );
console . log ( `End-to-End ID: ${ transaction . operation . additionalInfo . endToEndId } ` );
// Atualizar sistema interno
updateTransferStatus ( transaction . operation . externalID , 'completed' );
// Notificar usuário
sendNotification ({
type: 'transfer_success' ,
message: `Transferência PIX de R$ ${ valueBrl } realizada com sucesso` ,
transaction_id: transaction . operation . externalID ,
endToEndId: transaction . operation . additionalInfo . endToEndId
});
}
function handleWithdrawFailed ( transaction ) {
const error = transaction . operation . error ?.[ 0 ];
const amountReturned = transaction . operation . additionalInfo ?. amountReturned ;
console . log ( `Transferência PIX falhou: ${ transaction . operation . externalID } ` );
console . log ( `Código do erro: ${ error ?. code } ` );
console . log ( `Mensagem: ${ error ?. message } ` );
console . log ( `Valor retornado: ${ amountReturned ? 'Sim' : 'Não' } ` );
// Atualizar sistema interno
updateTransferStatus ( transaction . operation . externalID , 'failed' , error );
// Notificar usuário do erro
sendNotification ({
type: 'transfer_error' ,
message: `Erro na transferência PIX: ${ error ?. message } ` ,
transaction_id: transaction . operation . externalID ,
error_code: error ?. code ,
amount_returned: amountReturned
});
// Log para auditoria
logTransferFailure ({
transactionId: transaction . _id ,
businessId: transaction . businessId ,
errorCode: error ?. code ,
errorMessage: error ?. message
});
}
Categorias de Erro
VALIDATION_ERROR
Descrição : Erro de validação (chave PIX inválida, dados incorretos)
Ação : Corrigir dados e tentar novamente
Valor retornado : Sim
INSUFFICIENT_BALANCE
Descrição : Saldo insuficiente na conta
Ação : Adicionar saldo e tentar novamente
Valor retornado : Sim
LIMIT_EXCEEDED
Descrição : Limite de transferência excedido
Ação : Aguardar próximo período ou ajustar limites
Valor retornado : Sim
TEMPORARY_ERROR
Descrição : Erro temporário do sistema PIX
Ação : Tentar novamente em alguns minutos
Valor retornado : Sim
CRITICAL_ERROR
Descrição : Erro crítico que requer intervenção manual
Ação : Contatar suporte
Valor retornado : Varia
Monitoramento de Transferências
Métricas Importantes
// Acompanhar performance das transferências
function trackWithdrawMetrics ( data ) {
const metrics = {
// Taxa de sucesso
success_rate: calculateSuccessRate (),
// Tempo médio de processamento
avg_processing_time: calculateAvgProcessingTime ( data ),
// Bancos mais utilizados
top_banks: getTopBanks ( data . beneficiary . bank ),
// Valores médios
avg_amount: calculateAvgAmount ( data . transaction . amount ),
// Tipos de erro mais comuns
common_errors: getCommonErrors ()
};
sendMetrics ( metrics );
}
Dashboard de Transferências
Volume diário : Total de transferências por dia
Taxa de sucesso : % de transferências bem-sucedidas
Tempo médio : Tempo de processamento
Principais erros : Tipos de erro mais frequentes
Distribuição por banco : Transferências por instituição
Casos de Uso
Marketplace - Pagamento de Vendedores
function handleWithdrawCompleted ( data ) {
const vendorId = extractVendorId ( data . metadata );
const amount = data . transaction . amount ;
// Atualizar saldo do vendedor
updateVendorBalance ( vendorId , amount );
// Notificar vendedor
notifyVendor ( vendorId , {
type: 'payment_received' ,
amount: amount ,
transaction_id: data . transaction . id
});
// Registrar para relatórios
recordVendorPayment ( vendorId , amount , data . transaction . processed_at );
}
Sistema de Folha de Pagamento
function handleWithdrawCompleted ( data ) {
const employeeId = data . metadata . employee_id ;
const salaryAmount = data . transaction . amount ;
// Marcar salário como pago
markSalaryAsPaid ( employeeId , data . transaction . external_id );
// Gerar comprovante de pagamento
generateSalaryReceipt ( employeeId , {
amount: salaryAmount ,
date: data . transaction . processed_at ,
reference: data . transaction . external_id
});
// Enviar por email
emailSalaryReceipt ( employeeId );
}
function handleWithdrawCompleted ( data ) {
const serviceId = data . metadata . service_id ;
const providerId = data . metadata . provider_id ;
// Marcar serviço como pago
updateServiceStatus ( serviceId , 'paid' );
// Notificar prestador de serviço
notifyServiceProvider ( providerId , {
service_id: serviceId ,
payment_amount: data . transaction . amount ,
payment_date: data . transaction . processed_at
});
// Atualizar rating/reputação
updateProviderRating ( providerId , serviceId );
}
Recuperação de Falhas
Retry Automático
function handleWithdrawFailed ( data ) {
const error = data . error ;
const transactionId = data . transaction . external_id ;
// Determinar se deve tentar novamente
if ( shouldRetry ( error . category )) {
const retryDelay = calculateRetryDelay ( error . category );
setTimeout (() => {
retryTransfer ( transactionId , {
reason: error . message ,
attempt: getAttemptCount ( transactionId ) + 1
});
}, retryDelay );
} else {
// Erro permanente - notificar usuário
notifyPermanentFailure ( transactionId , error );
}
}
function shouldRetry ( errorCategory ) {
const retryableErrors = [
'TEMPORARY_ERROR' ,
'SYSTEM_UNAVAILABLE' ,
'TIMEOUT_ERROR'
];
return retryableErrors . includes ( errorCategory );
}
Boas Práticas
Tratamento de Erros
Classifique erros : Separe erros temporários de permanentes
Retry inteligente : Apenas para erros recuperáveis
Alerta proativo : Monitore taxa de erro
Backup manual : Tenha processo manual para casos críticos
Auditoria e Compliance
Log completo : Registre todas as transferências
Rastrebilidade : Mantenha End-to-End ID
Relatórios : Gere relatórios regulares
Conciliação : Compare com extratos bancários
Processamento assíncrono : Não bloqueie o webhook
Filas de trabalho : Use filas para tarefas pesadas
Cache de dados : Cache informações frequentes
Monitoramento : Acompanhe tempo de resposta
Próximos Passos