Pular para o conteúdo principal

Estrutura do evento

Todos os eventos de webhook seguem esta estrutura:
{
  id: string,              // UUID - ID único do evento
  event: string,           // Tipo de evento: RAMP | USER | TRANSACTION | ACCOUNT | CUSTODIAL_ACCOUNT
  action: string,          // Ação: CREATE | UPDATE | DELETE
  data: object,            // Dados específicos do evento
  createdAt: string,       // Timestamp ISO 8601
  updatedAt: string,       // Timestamp ISO 8601
  attempts: number         // Contagem de tentativas de entrega (0 a 5)
}
Use o campo id para idempotência. O campo attempts indica a contagem de tentativas de retry.

Tipos de evento

Eventos RAMP

Tipo: RAMP Ações:
  • CREATE - Ramp criado
  • UPDATE - Status do ramp mudou
  • DELETE - Ramp cancelado (raro)
Exemplo - Ramp criado:
{
  "id": "evt_a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
  "event": "RAMP",
  "action": "CREATE",
  "data": {
    "id": "be4d353b-00a2-4309-9ef1-594f37dfb1fd",
    "userId": "2bc703f2-1c54-4cbb-a144-993e1d957688",
    "accountId": "f7df00af-5d12-4b33-b5ab-e2b32290ebad",
    "quotationId": "a656a475-0d53-479e-8f30-91582ecf450b",
    "type": "ON",
    "status": "CREATED",
    "cashInMethod": "PSE",
    "cashOutMethod": "POLYGON",
    "fromCurrency": "COP",
    "toCurrency": "USDC",
    "fromAmount": 100000,
    "toAmount": 23.81,
    "isPreFunded": false,
    "active": true,
    "createdAt": "2025-01-15T23:46:10.226Z",
    "updatedAt": "2025-01-15T23:46:10.226Z"
  },
  "createdAt": "2025-01-15T23:46:10.226Z",
  "updatedAt": "2025-01-15T23:46:10.226Z",
  "attempts": 0
}
Exemplo - Ramp concluído:
{
  "id": "evt_b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
  "event": "RAMP",
  "action": "UPDATE",
  "data": {
    "id": "be4d353b-00a2-4309-9ef1-594f37dfb1fd",
    "userId": "2bc703f2-1c54-4cbb-a144-993e1d957688",
    "accountId": "f7df00af-5d12-4b33-b5ab-e2b32290ebad",
    "type": "ON",
    "status": "COMPLETED",
    "fromCurrency": "COP",
    "toCurrency": "USDC",
    "fromAmount": 100000,
    "toAmount": 23.81,
    "transferProof": "0x8e2b1f4645ebc8b6f658c860980567a63d283a42735be7401a7950306a2539b0",
    "createdAt": "2025-01-15T23:46:10.226Z",
    "updatedAt": "2025-01-16T00:29:06.813Z"
  },
  "createdAt": "2025-01-16T00:29:06.813Z",
  "updatedAt": "2025-01-16T00:29:06.813Z",
  "attempts": 0
}
Como lidar com eventos RAMP:
if (webhookEvent.event === 'RAMP' && webhookEvent.action === 'UPDATE') {
  const { status, transferProof } = webhookEvent.data;
  
  switch(status) {
    case 'CASH_IN_COMPLETED':
      console.log('Payment received');
      break;
    case 'COMPLETED':
      console.log('Ramp completed:', transferProof);
      await notifyUser(webhookEvent.data.userId);
      break;
    case 'FAILED':
      console.log('Ramp failed');
      await handleFailure(webhookEvent.data);
      break;
  }
}
Status comuns:
  • CREATED - Ramp inicializado
  • CASH_IN_PROCESSING - Pagamento sendo processado
  • CASH_IN_COMPLETED - Pagamento confirmado
  • CONVERSION_PROCESSING - Convertendo moeda
  • CONVERSION_COMPLETED - Conversão concluída
  • CASH_OUT_PROCESSING - Enviando fundos
  • COMPLETED - Totalmente concluído
  • FAILED - Falhou
  • CANCELED - Cancelado

Eventos USER

Tipo: USER Ações:
  • CREATE - Usuário registrado
  • UPDATE - Informações ou status do usuário mudou
  • DELETE - Usuário excluído (raro)
Exemplo - KYC aprovado:
{
  "id": "evt_f1e2d3c4-b5a6-4978-8c9d-0e1f2a3b4c5d",
  "event": "USER",
  "action": "UPDATE",
  "data": {
    "id": "e3d5c4ca-839a-4067-af76-89b33b19696e",
    "type": "PERSON",
    "customerId": "c650925e-a4aa-4a5f-a0a9-6c97be6c6ce5",
    "externalId": "user-ext-12345",
    "status": "ACTIVE",
    "accessLevel": "L2",
    "data": {
      "firstName": "Carlos",
      "lastName": "Rodriguez",
      "email": "[email protected]",
      "phone": "+573001234567"
    }
  },
  "createdAt": "2025-01-15T10:30:00.000Z",
  "updatedAt": "2025-01-15T14:22:00.000Z",
  "attempts": 0
}
Como lidar com eventos USER:
if (webhookEvent.event === 'USER' && webhookEvent.action === 'UPDATE') {
  const { status, accessLevel } = webhookEvent.data;
  
  if (status === 'ACTIVE' && accessLevel !== 'L0') {
    // KYC aprovado - habilitar funcionalidades
    await enableUserFeatures(webhookEvent.data.id, accessLevel);
  }
  
  if (status === 'REJECTED') {
    // KYC rejeitado - notificar o usuário
    await sendKYCRejectionEmail(webhookEvent.data);
  }
}
Status do usuário:
  • PENDING - Aguardando verificação
  • ACTIVE - Verificado e ativo
  • REJECTED - KYC rejeitado
  • SUSPENDED - Conta suspensa
Níveis de acesso:
  • L0 - Não verificado
  • L1 - Básico ($1K diário)
  • L2 - Padrão ($10K diário)
  • L3 - Aprimorado ($50K diário)
  • L4 - Premium (Ilimitado)

Eventos ACCOUNT

Tipo: ACCOUNT Ações:
  • CREATE - Conta adicionada
  • UPDATE - Status da conta mudou
  • DELETE - Conta excluída
Exemplo - Conta verificada:
{
  "id": "evt_c9b8a7f6-d5e4-4321-9876-543210fedcba",
  "event": "ACCOUNT",
  "action": "UPDATE",
  "data": {
    "id": "543ab81d-0b1e-4b9d-88bc-58ba5a365f16",
    "type": "PSE",
    "status": "ACTIVE",
    "externalId": "bank-acc-7890",
    "data": {
      "firstName": "María",
      "lastName": "González",
      "email": "[email protected]",
      "countryCode": "CO"
    },
    "complianceUrl": "https://in.sumsub.com/websdk/p/AbCd1234EfGh5678"
  },
  "createdAt": "2025-01-15T09:15:00.000Z",
  "updatedAt": "2025-01-15T09:45:00.000Z",
  "attempts": 0
}
Como lidar com eventos ACCOUNT:
if (webhookEvent.event === 'ACCOUNT' && webhookEvent.action === 'UPDATE') {
  const { status, type } = webhookEvent.data;
  
  if (status === 'ACTIVE') {
    console.log(`${type} account verified and ready`);
    await notifyAccountReady(webhookEvent.data.id);
  }
  
  if (status === 'REJECTED') {
    console.log('Account verification failed');
    await requestNewAccountInfo(webhookEvent.data.id);
  }
}
Tipos de conta:
  • PSE - Banco colombiano
  • SPEI - Banco mexicano
  • ACH - Banco nos EUA
  • WIRE - Transferência bancária
  • WALLET - Carteira cripto
  • PIX - PIX do Brasil
  • TRANSFIYA - Carteira móvel na Colômbia
Status de conta:
  • PENDING - Aguardando verificação
  • ACTIVE - Verificada
  • REJECTED - Verificação falhou
  • INACTIVE - Desativada

Eventos TRANSACTION

Tipo: TRANSACTION Ações:
  • CREATE - Transação iniciada
  • UPDATE - Status da transação mudou
  • DELETE - Transação cancelada (raro)
Exemplo - Depósito em savings:
{
  "id": "evt_1a2b3c4d-5e6f-7890-abcd-ef1234567890",
  "event": "TRANSACTION",
  "action": "UPDATE",
  "data": {
    "id": "txn_9876543210abcdef",
    "userId": "e3d5c4ca-839a-4067-af76-89b33b19696e",
    "savingsAccountId": "sav_1234567890abcdef",
    "type": "DEPOSIT",
    "status": "COMPLETED",
    "amount": "1000.00",
    "currency": "USD",
    "method": "ACH"
  },
  "createdAt": "2025-01-15T10:30:00.000Z",
  "updatedAt": "2025-01-15T10:35:00.000Z",
  "attempts": 0
}
Tipos de transação:
  • DEPOSIT - Depósito em savings
  • WITHDRAWAL - Saque de savings
  • INTEREST - Pagamento de juros
  • FEE - Cobrança de taxa

Eventos CUSTODIAL_ACCOUNT

Tipo: CUSTODIAL_ACCOUNT Ações:
  • CREATE - Conta criada
  • UPDATE - Saldo ou status atualizado
  • DELETE - Conta encerrada (raro)
Exemplo - Saldo atualizado:
{
  "id": "evt_abcd1234-ef56-7890-1234-567890abcdef",
  "event": "CUSTODIAL_ACCOUNT",
  "action": "UPDATE",
  "data": {
    "id": "cust_1234567890abcdef",
    "userId": "e3d5c4ca-839a-4067-af76-89b33b19696e",
    "type": "SAVINGS",
    "status": "ACTIVE",
    "balance": "5250.00",
    "currency": "USD",
    "previousBalance": "5000.00",
    "changeAmount": "250.00",
    "changeReason": "DEPOSIT",
    "interestRate": "4.50"
  },
  "createdAt": "2025-01-15T10:35:00.000Z",
  "updatedAt": "2025-01-15T10:35:00.000Z",
  "attempts": 0
}
Motivos de mudança:
  • DEPOSIT - Fundos depositados
  • WITHDRAWAL - Fundos sacados
  • INTEREST - Juros creditados
  • FEE - Taxa cobrada
  • ADJUSTMENT - Ajuste manual

Boas práticas de tratamento de eventos

Filtrar por evento e ação

const handleWebhook = (webhookEvent) => {
  const { event, action, data } = webhookEvent;
  
  // Roteie por tipo de evento
  if (event === 'RAMP') {
    if (action === 'CREATE') {
      handleRampCreated(data);
    } else if (action === 'UPDATE') {
      handleRampUpdated(data);
    }
  } else if (event === 'USER') {
    if (action === 'UPDATE') {
      handleUserUpdated(data);
    }
  }
  // ... outros tipos de eventos
};

Verificar status específico

const handleRampUpdated = (data) => {
  switch(data.status) {
    case 'CASH_IN_COMPLETED':
      console.log('Payment received');
      break;
    case 'COMPLETED':
      console.log('Ramp completed:', data.transferProof);
      updateDatabase(data);
      notifyUser(data.userId);
      break;
    case 'FAILED':
      console.log('Ramp failed:', data.details);
      handleFailure(data);
      break;
  }
};

Usar o ID do evento para idempotência

const processWebhook = async (webhookEvent) => {
  // Verifique se já foi processado
  const existing = await db.webhookEvents.findOne({ 
    eventId: webhookEvent.id 
  });
  
  if (existing) {
    console.log('Duplicate event, skipping');
    return { received: true, duplicate: true };
  }
  
  // Armazenar e processar
  await db.webhookEvents.create({
    eventId: webhookEvent.id,
    eventType: webhookEvent.event,
    action: webhookEvent.action,
    payload: webhookEvent.data,
    attempts: webhookEvent.attempts,
    receivedAt: new Date()
  });
  
  await handleWebhook(webhookEvent);
  
  return { received: true };
};

Monitorar tentativas de retry

if (webhookEvent.attempts > 3) {
  console.warn(`High retry count for event ${webhookEvent.id}`);
  // Alertar sistema de monitoramento
  alertOps('webhook-retries-high', {
    eventId: webhookEvent.id,
    attempts: webhookEvent.attempts,
    event: webhookEvent.event
  });
}

Referência rápida

Tipo de eventoAções comunsCampos chave em data
RAMPCREATE, UPDATEstatus, transferProof, fromAmount, toAmount
USERCREATE, UPDATEstatus, accessLevel, data
ACCOUNTCREATE, UPDATE, DELETEstatus, type, data
TRANSACTIONCREATE, UPDATEtype, status, amount
CUSTODIAL_ACCOUNTUPDATEbalance, changeReason, changeAmount

Próximos passos

Configuração de Webhook

Configure endpoints de webhook

Guia de Segurança

Verifique assinaturas de webhook

Conceito de Webhook

Aprenda sobre a arquitetura de webhooks

Referência da API

Documentação da API de Webhooks