Skip to main content

Visão Geral

Os eventos de webhook KYC permitem que você receba notificações em tempo real quando o status de uma verificação KYC mudar. Gu1 envia automaticamente solicitações HTTP POST para seu endpoint de webhook configurado sempre que um status de validação é atualizado, permitindo que você automatize fluxos de trabalho de integração de clientes e mantenha a conformidade.

Por Que Usar Webhooks KYC?

Atualizações em Tempo Real

Receba notificações instantâneas quando o status de verificação mudar

Eficiente

Não é necessário consultar a API repetidamente

Fluxos de Trabalho Automatizados

Atualize automaticamente contas de usuário com base nos resultados de verificação

Melhor UX

Notifique clientes imediatamente após a verificação

Eventos Disponíveis

Gu1 envia webhooks para os seguintes eventos de validação KYC:
Tipo de EventoDescriçãoQuando Acionado
kyc.validation_createdSessão de validação criadaQuando você cria uma nova validação KYC
kyc.validation_in_progressCliente iniciou verificaçãoCliente está completando ativamente verificação (preenchendo formulário)
kyc.validation_in_reviewVerificação em revisãoVerificação completada, requer revisão manual da equipe de compliance
kyc.validation_approvedVerificação aprovadaIdentidade verificada com sucesso
kyc.validation_rejectedVerificação rejeitadaVerificação de identidade falhou
kyc.validation_abandonedCliente abandonou processoCliente saiu sem completar
kyc.validation_expiredSessão de validação expirouSessão expirou (tipicamente após 7 dias)
kyc.validation_cancelledValidação canceladaValidação cancelada manualmente pela organização

Estrutura do Payload do Evento

Todos os eventos de webhook KYC seguem esta estrutura padrão:
{
  "event": "kyc.validation_approved",
  "timestamp": "2025-01-07T11:00:00Z",
  "organizationId": "org-123",
  "payload": {
    "validationId": "550e8400-e29b-41d4-a716-446655440000",
    "entityId": "123e4567-e89b-12d3-a456-426614174000",
    "entity": {
      "id": "123e4567-e89b-12d3-a456-426614174000",
      "externalId": "customer_xyz789",
      "name": "John Doe",
      "type": "person"
    },
    "status": "approved"
    // ... campos específicos do evento
  }
}

Campos Comuns do Payload

event
string
O tipo de evento (por exemplo, kyc.validation_approved)
timestamp
string
Timestamp ISO 8601 quando o evento ocorreu
organizationId
string
Seu ID de organização
payload.validationId
string
O ID de validação KYC no Gu1
payload.entityId
string
O ID da entidade (pessoa) sendo verificada
payload.entity
object
Informações da entidade incluindo seu externalId para busca fácil
payload.status
string
Status atual de validação: pending, in_progress, in_review, approved, rejected, abandoned, expired, cancelled

Payloads Específicos de Eventos

kyc.validation_created

Enviado quando uma nova validação KYC é criada.
{
  "event": "kyc.validation_created",
  "timestamp": "2025-01-07T10:30:00Z",
  "organizationId": "org-123",
  "payload": {
    "validationId": "550e8400-e29b-41d4-a716-446655440000",
    "entityId": "123e4567-e89b-12d3-a456-426614174000",
    "entity": {
      "id": "123e4567-e89b-12d3-a456-426614174000",
      "externalId": "customer_xyz789",
      "name": "John Doe",
      "type": "person"
    },
    "status": "pending",
    "validationUrl": "https://kyc.gu1.io/validate/abc123",
    "expiresAt": "2025-01-14T10:30:00Z"
  }
}
Caso de uso: Envie a URL de validação para seu cliente via email ou SMS.

kyc.validation_in_review

Enviado quando um cliente completa a verificação e requer revisão manual da equipe de compliance.
{
  "event": "kyc.validation_in_review",
  "timestamp": "2025-01-07T10:50:00Z",
  "organizationId": "org-123",
  "payload": {
    "validationId": "550e8400-e29b-41d4-a716-446655440000",
    "entityId": "123e4567-e89b-12d3-a456-426614174000",
    "entity": {
      "id": "123e4567-e89b-12d3-a456-426614174000",
      "externalId": "customer_xyz789",
      "name": "John Doe",
      "type": "person"
    },
    "status": "in_review",
    "completedAt": "2025-01-07T10:50:00Z"
  }
}
Caso de uso: Notifique a equipe de compliance para revisão manual. Atualize a UI para mostrar “Em revisão pela equipe de compliance”.

kyc.validation_approved

Enviado quando a verificação é concluída com sucesso.
{
  "event": "kyc.validation_approved",
  "timestamp": "2025-01-07T11:00:00Z",
  "organizationId": "org-123",
  "payload": {
    "validationId": "550e8400-e29b-41d4-a716-446655440000",
    "entityId": "123e4567-e89b-12d3-a456-426614174000",
    "entity": {
      "id": "123e4567-e89b-12d3-a456-426614174000",
      "externalId": "customer_xyz789",
      "name": "John Doe",
      "type": "person"
    },
    "status": "approved",
    "verifiedAt": "2025-01-07T11:00:00Z",
    "extractedData": {
      "firstName": "John",
      "lastName": "Doe",
      "dateOfBirth": "1990-05-20",
      "nationality": "US",
      "documentNumber": "AB123456",
      "documentType": "passport",
      "documentExpiry": "2030-05-20"
    },
    "verifiedFields": [
      "firstName",
      "lastName",
      "dateOfBirth",
      "nationality",
      "documentNumber"
    ],
    "warnings": [],
    "decision": {
      "id_verification": "pass",
      "face_match": "pass",
      "liveness": "pass",
      "document_authenticity": "pass"
    }
  }
}
Caso de uso: Ative a conta do cliente e conceda acesso aos serviços.

kyc.validation_rejected

Enviado quando a verificação falha.
{
  "event": "kyc.validation_rejected",
  "timestamp": "2025-01-07T11:00:00Z",
  "organizationId": "org-123",
  "payload": {
    "validationId": "550e8400-e29b-41d4-a716-446655440000",
    "entityId": "123e4567-e89b-12d3-a456-426614174000",
    "entity": {
      "id": "123e4567-e89b-12d3-a456-426614174000",
      "externalId": "customer_xyz789",
      "name": "John Doe",
      "type": "person"
    },
    "status": "rejected",
    "verifiedAt": "2025-01-07T11:00:00Z",
    "warnings": [
      "Document authenticity check failed",
      "Face match confidence low",
      "Liveness detection failed"
    ],
    "rejectionReason": "Document authenticity could not be verified"
  }
}
Caso de uso: Notifique o cliente que a verificação falhou e forneça orientação sobre os próximos passos.

kyc.validation_cancelled

Enviado quando uma validação é cancelada manualmente pela organização.
{
  "event": "kyc.validation_cancelled",
  "timestamp": "2025-01-07T12:00:00Z",
  "organizationId": "org-123",
  "payload": {
    "validationId": "550e8400-e29b-41d4-a716-446655440000",
    "entityId": "123e4567-e89b-12d3-a456-426614174000",
    "entity": {
      "id": "123e4567-e89b-12d3-a456-426614174000",
      "externalId": "customer_xyz789",
      "name": "John Doe",
      "type": "person"
    },
    "status": "cancelled",
    "cancelledAt": "2025-01-07T12:00:00Z",
    "cancelledBy": "user_123"
  }
}
Caso de uso: Notifique o cliente que a validação foi cancelada. Limpe recursos associados e atualize o status no seu sistema.

Exemplos de Código

Node.js - Lidando com Eventos KYC

const express = require('express');
const crypto = require('crypto');

const app = express();

app.use(express.json({
  verify: (req, res, buf) => {
    req.rawBody = buf.toString('utf8');
  }
}));

app.post('/webhooks/kyc', async (req, res) => {
  try {
    // Verificar assinatura de webhook (veja guia de segurança)
    const signature = req.headers['x-webhook-signature'];
    const webhookSecret = process.env.GU1_WEBHOOK_SECRET;

    if (!verifySignature(req.rawBody, signature, webhookSecret)) {
      console.error('Invalid webhook signature');
      return res.status(401).json({ error: 'Invalid signature' });
    }

    // Extrair dados do webhook
    const { event, timestamp, organizationId, payload } = req.body;

    console.log('Received KYC webhook:', {
      event,
      validationId: payload.validationId,
      status: payload.status
    });

    // Processar o webhook com base no tipo de evento
    await handleKycWebhook(event, payload);

    // Retornar 200 para confirmar recebimento
    res.status(200).json({
      success: true,
      message: 'Webhook received'
    });
  } catch (error) {
    console.error('Webhook error:', error);
    res.status(500).json({
      error: error.message
    });
  }
});

async function handleKycWebhook(event, data) {
  const { validationId, entityId, entity, status } = data;

  // Atualizar seu banco de dados com ID de validação do Gu1
  await db.updateEntity(entity.externalId, {
    kycValidationId: validationId,
    kycStatus: status,
    lastUpdated: new Date()
  });

  // Realizar ações com base no tipo de evento
  switch (event) {
    case 'kyc.validation_created':
      console.log('KYC validation created for:', entity.name);
      // Enviar URL de validação ao cliente
      await sendValidationEmail(entity, data.validationUrl);
      break;

    case 'kyc.validation_in_progress':
      await notifyCustomer(entity.externalId, 'verification-started');
      break;

    case 'kyc.validation_in_review':
      // Notificar equipe de compliance
      await notifyComplianceTeam(entity, validationId);
      await notifyCustomer(entity.externalId, 'verification-in-review');
      break;

    case 'kyc.validation_approved':
      // Extrair dados verificados
      const { extractedData, verifiedFields } = data;

      await db.updateEntity(entity.externalId, {
        verifiedData: extractedData,
        verifiedFields: verifiedFields,
        verifiedAt: data.verifiedAt,
        isVerified: true
      });

      // Ativar conta de cliente
      await activateCustomerAccount(entity.externalId);
      await notifyCustomer(entity.externalId, 'verification-approved');
      break;

    case 'kyc.validation_rejected':
      await db.updateEntity(entity.externalId, {
        isVerified: false,
        rejectionReasons: data.warnings,
        rejectionReason: data.rejectionReason
      });

      await notifyCustomer(entity.externalId, 'verification-rejected', {
        reasons: data.warnings
      });
      break;

    case 'kyc.validation_abandoned':
      await notifyCustomer(entity.externalId, 'verification-incomplete', {
        lastStep: data.lastStep
      });
      break;

    case 'kyc.validation_expired':
      await notifyCustomer(entity.externalId, 'verification-expired');
      // Limpar validação expirada
      await db.deleteValidation(validationId);
      break;

    case 'kyc.validation_cancelled':
      await notifyCustomer(entity.externalId, 'verification-cancelled');
      // Limpar recursos associados
      await db.deleteValidation(validationId);
      break;
  }
}

function verifySignature(rawBody, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  return signature === expectedSignature;
}

app.listen(3000);

Melhores Práticas

O webhook inclui entity.externalId que é o ID que você forneceu ao criar a entidade. Use-o para buscar o cliente no seu banco de dados.
const customer = await db.findCustomer({
  externalId: data.entity.externalId
});
Armazene o validationId do Gu1 no seu banco de dados. Isso permite que você consulte detalhes de validação mais tarde, se necessário.
await db.updateCustomer(customer.id, {
  kycValidationId: data.validationId,
  kycStatus: data.status
});
Você pode receber o mesmo webhook múltiplas vezes. Use o validationId para garantir que você processe cada evento apenas uma vez.
async function handleWebhook(webhook) {
  const alreadyProcessed = await db.checkWebhookProcessed(
    webhook.payload.validationId,
    webhook.event
  );

  if (alreadyProcessed) {
    return; // Pular duplicado
  }

  // Processar webhook
  await processValidation(webhook.payload);

  // Marcar como processado
  await db.markWebhookProcessed(
    webhook.payload.validationId,
    webhook.event
  );
}
Sempre retorne um código de status 200 o mais rápido possível para confirmar o recebimento. Processe o webhook assincronamente se necessário.
app.post('/webhooks/kyc', async (req, res) => {
  // Confirmar imediatamente
  res.status(200).send('OK');

  // Processar assincronamente
  processWebhook(req.body).catch(console.error);
});
Sempre verifique o header X-Webhook-Signature para garantir que o webhook seja autêntico. Veja o guia de segurança para detalhes.
const signature = req.headers['x-webhook-signature'];
if (!verifySignature(req.rawBody, signature, secret)) {
  return res.status(401).json({ error: 'Invalid signature' });
}

Solução de Problemas

Verificar estes itens:
  • URL do webhook é publicamente acessível via HTTPS
  • Webhook está configurado e habilitado no dashboard
  • Inscrito nos tipos de eventos KYC corretos
  • Endpoint retorna código de status 200 dentro de 30 segundos
  • Verificar logs do servidor para solicitações recebidas
extractedData e verifiedFields são incluídos apenas em:
  • kyc.validation_approved
  • kyc.validation_rejected
Eles não estão presentes em outros tipos de eventos como validation_created ou validation_in_progress.
Causas comuns:
  • Usar secret errado (verificar dashboard para secret atual)
  • Verificar assinatura em JSON analisado em vez de corpo raw
  • Secret não salvo corretamente após criação do webhook
  • Problemas de codificação (garantir UTF-8)
Veja o guia de segurança para implementação adequada.
Este é um comportamento normal. Webhooks podem ser enviados múltiplas vezes devido a problemas de rede, timeouts ou tentativas.Sempre implemente idempotência usando o validationId do webhook e tipo de event.

Próximos Passos