Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.vexybank.com/llms.txt

Use this file to discover all available pages before exploring further.

Esta página detalha todos os eventos disponíveis na API Vexy Bank que podem disparar webhooks, incluindo estrutura de dados e quando cada evento é enviado.

Eventos de transação (PIX IN)

transaction_created

Quando é enviado: QR Code PIX criado com sucesso
{
  "id": "trx_1a2b3c4d5e6f7g8h9i0j",
  "type": "transaction",
  "event": "transaction_created",
  "scope": "postback",
  "transaction": {
    "id": "trx_1a2b3c4d5e6f7g8h9i0j",
    "amount": 5000,
    "status": "pending",
    "description": "Pagamento de serviços"
  }
}
Uso típico: Confirmar que QR Code foi gerado, iniciar timer de expiração

transaction_paid

Quando é enviado: PIX recebido e confirmado pelo sistema
{
  "id": "trx_1a2b3c4d5e6f7g8h9i0j",
  "type": "transaction",
  "event": "transaction_paid",
  "scope": "postback",
  "transaction": {
    "id": "trx_1a2b3c4d5e6f7g8h9i0j",
    "amount": 5000,
    "status": "paid",
    "pix": {
      "endToEndId": "E00000000202401011200000000000000",
      "payerInfo": {
        "bank": "000",
        "name": "Cliente Pagador",
        "branch": "0001",
        "document": "11122233344",
        "account_type": "CHECKING",
        "account_number": "000000"
      }
    }
  }
}
Uso típico: Liberar produto/serviço, enviar email de confirmação, atualizar estoque

transaction_refunded

Quando é enviado: Estorno processado com sucesso
{
  "id": "trx_1a2b3c4d5e6f7g8h9i0j",
  "type": "transaction",
  "event": "transaction_refunded",
  "scope": "postback",
  "transaction": {
    "id": "trx_1a2b3c4d5e6f7g8h9i0j",
    "amount": 5000,
    "status": "refunded",
    "refund": {
      "amount": 5000,
      "reason": "Solicitação do cliente",
      "refundedAt": "2024-01-20T14:20:00.000Z"
    }
  }
}
Uso típico: Cancelar entrega, notificar cliente, restaurar estoque

transaction_infraction

Quando é enviado: Problemas ou infrações detectadas pelo Banco Central
{
  "id": "trx_1a2b3c4d5e6f7g8h9i0j",
  "type": "transaction",
  "event": "transaction_infraction",
  "scope": "postback",
  "transaction": {
    "id": "trx_1a2b3c4d5e6f7g8h9i0j",
    "amount": 5000,
    "status": "infraction",
    "infraction": {
      "type": "fraud_suspected",
      "description": "Suspeita de fraude detectada",
      "reportedAt": "2024-01-20T15:10:00.000Z"
    }
  }
}
Uso típico: Pausar entrega, revisar transação, contatar suporte

Eventos de transferência (PIX OUT)

transfer_created

Quando é enviado: Transferência PIX iniciada
{
  "id": "transfer_abc123def456",
  "type": "transfer",
  "event": "transfer_created",
  "scope": "postback",
  "transfer": {
    "id": "transfer_abc123def456",
    "amount": 10000,
    "status": "queued",
    "pix": {
      "endToEndId": null,
      "creditorAccount": null
    }
  }
}
Uso típico: Registrar tentativa de transferência, notificar solicitante Status: queued - Transferência em fila para processamento

transfer_updated

Quando é enviado: Status da transferência foi atualizado
{
  "id": "transfer_abc123def456",
  "type": "transfer",
  "event": "transfer_updated",
  "scope": "postback",
  "transfer": {
    "id": "transfer_abc123def456",
    "amount": 10000,
    "status": "processing",
    "pix": {
      "endToEndId": null,
      "creditorAccount": null
    }
  }
}
Uso típico: Atualizar status em tempo real, mostrar progresso ao usuário Status: processing - Transferência sendo processada

transfer_completed

Quando é enviado: Transferência PIX concluída com sucesso
{
  "id": "transfer_abc123def456",
  "type": "transfer",
  "event": "transfer_completed",
  "scope": "postback",
  "transfer": {
    "id": "transfer_abc123def456",
    "amount": 10000,
    "status": "completed",
    "pix": {
      "endToEndId": "E00000000202401011200000000000000",
      "creditorAccount": null
    }
  }
}
Uso típico: Confirmar pagamento, atualizar sistema financeiro, notificar destinatário Status: completed - Transferência concluída com sucesso

transfer_canceled

Quando é enviado: Transferência PIX cancelada
{
  "id": "transfer_abc123def456",
  "type": "transfer",
  "event": "transfer_canceled",
  "scope": "postback",
  "transfer": {
    "id": "transfer_abc123def456",
    "amount": 10000,
    "status": "canceled",
    "pix": {
      "endToEndId": null,
      "creditorAccount": null
    }
  }
}
Uso típico: Reverter operação, notificar erro, tentar novamente se apropriado Status: canceled - Transferência foi cancelada

Implementação por evento

Processamento de Pagamentos Recebidos

function handleTransactionPaid(transaction) {
  console.log(`Pagamento recebido: R$ ${transaction.amount / 100}`)
  
  // 1. Liberar produto/serviço
  await releaseProduct(transaction.id)
  
  // 2. Enviar email de confirmação
  await sendConfirmationEmail(transaction.customer.email, {
    amount: transaction.amount,
    transactionId: transaction.id,
    paidAt: transaction.paidAt
  })
  
  // 3. Atualizar sistema interno
  await updateInternalStatus(transaction.id, 'paid')
  
  // 4. Atualizar estoque (se aplicável)
  if (transaction.items) {
    await updateInventory(transaction.items)
  }
  
  console.log(`Processamento concluído para transação ${transaction.id}`)
}

Processamento de Transferências

function handleTransferCompleted(event) {
  const transfer = event.transfer
  console.log(`Transferência concluída: R$ ${transfer.amount}`)
  
  // 1. Atualizar registro financeiro
  await updateFinancialRecord(transfer.id, {
    status: 'completed',
    endToEndId: transfer.pix.endToEndId
  })
  
  // 2. Notificar solicitante
  await notifyRequester(transfer.id, 'completed')
  
  // 3. Registrar para auditoria
  await logTransferCompletion(transfer)
  
  console.log(`Transferência ${transfer.id} processada`)
}

function handleTransferCreated(event) {
  const transfer = event.transfer
  console.log(`Transferência criada: ${transfer.id} - Status: ${transfer.status}`)
  
  // Registrar tentativa de transferência
  await logTransferAttempt(transfer)
}

function handleTransferUpdated(event) {
  const transfer = event.transfer
  console.log(`Transferência atualizada: ${transfer.id} - Novo status: ${transfer.status}`)
  
  // Atualizar status em tempo real
  await updateTransferStatus(transfer.id, transfer.status)
}

function handleTransferCanceled(event) {
  const transfer = event.transfer
  console.log(`Transferência cancelada: ${transfer.id}`)
  
  // Reverter operação e notificar
  await revertTransfer(transfer.id)
  await notifyTransferCanceled(transfer)
}

Tratamento de Estornos

function handleTransactionRefunded(transaction) {
  console.log(`Estorno processado: R$ ${transaction.refund.amount / 100}`)
  
  // 1. Cancelar entrega se ainda não enviada
  await cancelDeliveryIfPending(transaction.id)
  
  // 2. Restaurar estoque
  if (transaction.items) {
    await restoreInventory(transaction.items)
  }
  
  // 3. Notificar cliente
  await sendRefundNotification(transaction.customer.email, {
    refundAmount: transaction.refund.amount,
    reason: transaction.refund.reason,
    refundedAt: transaction.refund.refundedAt
  })
  
  // 4. Atualizar sistemas internos
  await updateInternalStatus(transaction.id, 'refunded')
  
  console.log(`Estorno ${transaction.id} processado`)
}

Implementação robusta

Processador de Eventos Centralizado

class WebhookEventProcessor {
  constructor() {
    this.handlers = new Map()
    this.setupHandlers()
  }

  setupHandlers() {
    // Eventos de transação
    this.handlers.set('transaction_created', this.handleTransactionCreated)
    this.handlers.set('transaction_paid', this.handleTransactionPaid)
    this.handlers.set('transaction_refunded', this.handleTransactionRefunded)
    this.handlers.set('transaction_infraction', this.handleTransactionInfraction)
    
    // Eventos de transferência
    this.handlers.set('transfer_created', this.handleTransferCreated)
    this.handlers.set('transfer_completed', this.handleTransferCompleted)
    this.handlers.set('transfer_canceled', this.handleTransferCanceled)
    this.handlers.set('transfer_updated', this.handleTransferUpdated)
  }

  async processEvent(event) {
    const handler = this.handlers.get(event.event)
    
    if (!handler) {
      console.warn(`⚠️ Evento não tratado: ${event.event}`)
      return
    }

    try {
      console.log(`Processando evento: ${event.event}`)
      
      // Verificar se já foi processado (idempotência)
      if (await this.isEventProcessed(event.id)) {
        console.log(`ℹ️ Evento já processado: ${event.id}`)
        return
      }

      // Processar evento
      await handler.call(this, event)
      
      // Marcar como processado
      await this.markEventProcessed(event.id)
      
      console.log(`Evento processado: ${event.event} - ${event.id}`)
      
    } catch (error) {
      console.error(`❌ Erro ao processar evento ${event.event}:`, error)
      
      // Registrar erro para retry
      await this.logEventError(event.id, error)
      
      throw error
    }
  }

  async handleTransactionCreated(event) {
    const transaction = event.transaction
    
    // Iniciar timer de expiração
    await this.scheduleExpirationCheck(transaction.id, transaction.expiresAt)
    
    // Notificar sistemas internos
    await this.notifyTransactionCreated(transaction)
  }

  async handleTransactionPaid(event) {
    const transaction = event.transaction
    
    // Executar ações em paralelo quando possível
    await Promise.all([
      this.releaseProduct(transaction.id),
      this.sendConfirmationEmail(transaction),
      this.updateInventory(transaction.items),
      this.updateAnalytics('payment_received', transaction)
    ])
  }

  async handleTransferCreated(event) {
    const transfer = event.transfer
    
    // Registrar transferência criada
    await this.logTransferAttempt(transfer)
    await this.notifyTransferCreated(transfer)
  }

  async handleTransferUpdated(event) {
    const transfer = event.transfer
    
    // Atualizar status da transferência
    await this.updateTransferStatus(transfer.id, transfer.status)
  }

  async handleTransferCompleted(event) {
    const transfer = event.transfer
    
    await Promise.all([
      this.updateFinancialRecord(transfer),
      this.notifyTransferCompletion(transfer),
      this.updateAnalytics('transfer_completed', transfer)
    ])
  }

  async handleTransferCanceled(event) {
    const transfer = event.transfer
    
    // Reverter e notificar cancelamento
    await this.revertTransfer(transfer.id)
    await this.notifyTransferCanceled(transfer)
  }

  // Métodos utilitários
  async isEventProcessed(eventId) {
    // Verificar se evento já foi processado (implementar conforme sua arquitetura)
    return await redis.exists(`processed_event:${eventId}`)
  }

  async markEventProcessed(eventId) {
    // Marcar evento como processado com TTL
    await redis.setex(`processed_event:${eventId}`, 86400, 'true') // 24 horas
  }

  async logEventError(eventId, error) {
    // Registrar erro para possível retry
    await errorLogger.log({
      eventId,
      error: error.message,
      stack: error.stack,
      timestamp: new Date().toISOString()
    })
  }
}

// Uso no endpoint webhook
const eventProcessor = new WebhookEventProcessor()

app.post('/webhooks/vexy-bank', async (req, res) => {
  try {
    // Verificar assinatura
    if (!verifySignature(req.body, req.headers['vexy-signature'], WEBHOOK_SECRET)) {
      return res.status(401).send('Invalid signature')
    }

    const event = JSON.parse(req.body)
    
    // Processar evento
    await eventProcessor.processEvent(event)
    
    res.status(200).send('OK')
  } catch (error) {
    console.error('Webhook processing error:', error)
    res.status(500).send('Internal server error')
  }
})

Boas práticas

1. Idempotência

// Sempre verificar se evento já foi processado
async function processEventIdempotent(event) {
  const eventKey = `event_${event.id}`
  
  if (await cache.get(eventKey)) {
    console.log('Evento já processado')
    return
  }
  
  try {
    await processEvent(event)
    await cache.set(eventKey, 'processed', 86400) // 24h TTL
  } catch (error) {
    // Não marcar como processado em caso de erro
    throw error
  }
}

2. Retry e Recuperação

async function processEventWithRetry(event, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      await processEvent(event)
      return
    } catch (error) {
      console.error(`Tentativa ${attempt} falhou:`, error.message)
      
      if (attempt === maxRetries) {
        // Enviar para dead letter queue
        await deadLetterQueue.send(event)
        throw error
      }
      
      // Aguardar antes de tentar novamente
      await new Promise(resolve => setTimeout(resolve, 1000 * attempt))
    }
  }
}

3. Monitoramento

class WebhookMonitor {
  constructor() {
    this.metrics = {
      eventsReceived: 0,
      eventsProcessed: 0,
      eventsFailed: 0,
      processingTimes: []
    }
  }

  async recordEventProcessing(eventType, processingTime, success) {
    this.metrics.eventsReceived++
    
    if (success) {
      this.metrics.eventsProcessed++
    } else {
      this.metrics.eventsFailed++
    }
    
    this.metrics.processingTimes.push(processingTime)
    
    // Enviar métricas para sistema de monitoramento
    await this.sendMetrics(eventType, {
      processingTime,
      success,
      timestamp: Date.now()
    })
  }

  getStatistics() {
    const avgProcessingTime = this.metrics.processingTimes.reduce((a, b) => a + b, 0) / this.metrics.processingTimes.length
    
    return {
      eventsReceived: this.metrics.eventsReceived,
      eventsProcessed: this.metrics.eventsProcessed,
      eventsFailed: this.metrics.eventsFailed,
      successRate: (this.metrics.eventsProcessed / this.metrics.eventsReceived) * 100,
      averageProcessingTime: avgProcessingTime
    }
  }
}

Próximos passos

➕ Criar Webhook

Configure webhooks para receber estes eventos

Verificar assinatura

Implemente validação de assinatura

Listar webhooks

Gerencie seus webhooks existentes

PIX IN

Comece a receber pagamentos PIX