Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.gu1.ai/llms.txt

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

Overview

This guide demonstrates the complete automated onboarding flow for persons (individuals/customers) using gu1’s automatic entity creation with integrated risk assessment. The system will:
  1. Fetch official data from government registries (e.g., CPF in Brazil)
  2. Execute enrichments to gather additional information
  3. Run compliance checks (PEP, sanctions, adverse media)
  4. Execute risk matrix rules to assess risk automatically
  5. Generate alerts and investigations if rules are triggered
  6. Send notifications via Socket.IO and webhooks
This is ideal for KYC (Know Your Customer) processes where you want complete automation from data collection to risk assessment.

Prerequisites

Before starting, you need:
  1. API Key - Get one from Settings > API Keys
  2. Risk Matrix - Create and configure a risk matrix with rules for the entity_created trigger
  3. Active Integrations - Enable enrichment and check providers from the Marketplace
  4. Valid Tax ID - A real tax ID from a supported country (e.g., CPF for Brazil)

The Complete Flow

Here’s what happens when you create a person automatically with a risk matrix:

Quick Start Example

Basic Person Onboarding with Risk Assessment

curl -X POST https://api.gu1.ai/entities/automatic \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "taxId": "123.456.789-00",
    "country": "BR",
    "type": "person",
    "isClient": true,
    "riskMatrixId": "risk_matrix_uuid",
    "autoExecuteIntegrations": {
      "executeAllActiveEnrichments": true,
      "executeAllActiveChecks": true
    }
  }'

Complete Response Example

When the process completes successfully, you’ll receive a comprehensive response:
{
  "success": true,
  "data": {
    "entity": {
      "id": "person_uuid_abc123",
      "organizationId": "org_uuid",
      "type": "person",
      "name": "JoΓ£o Silva",
      "taxId": "12345678900",
      "countryCode": "BR",
      "status": "under_review",
      "riskScore": 35,
      "isClient": true,
      "entityData": {
        "person": {
          "firstName": "JoΓ£o",
          "lastName": "Silva",
          "dateOfBirth": "1985-05-15",
          "nationality": "BR",
          "gender": "M",
          "motherName": "Maria Silva"
        }
      },
      "enrichmentData": {
        "serpro_cpf": {
          "status": "REGULAR",
          "situation": "ATIVA"
        },
        "bureau_credit": {
          "score": 720,
          "rating": "GOOD"
        }
      },
      "checksData": {
        "overallStatus": "CLEAR",
        "results": [
          {
            "providerCode": "pep_check",
            "status": "CLEAR",
            "match": false
          },
          {
            "providerCode": "sanctions_check",
            "status": "CLEAR",
            "match": false
          }
        ]
      },
      "createdAt": "2024-12-23T10:30:00.000Z",
      "updatedAt": "2024-12-23T10:30:05.000Z"
    },
    "summary": {
      "entitiesCreated": 1,
      "relationshipsCreated": 0,
      "errorsCount": 0
    }
  },
  "rulesResult": {
    "success": true,
    "executed": true,
    "result": {
      "entityId": "person_uuid_abc123",
      "entityType": "person",
      "riskScore": 35,
      "overallConfidence": 0.95,
      "totalRules": 12,
      "successfulRules": 3,
      "failedRules": 0,
      "rulesExecuted": [
        {
          "ruleId": "rule_age_verification",
          "ruleName": "Age Verification",
          "matched": true,
          "score": 0,
          "confidence": 1.0
        },
        {
          "ruleId": "rule_high_credit_score",
          "ruleName": "High Credit Score",
          "matched": true,
          "score": -15,
          "confidence": 0.9
        },
        {
          "ruleId": "rule_pep_check",
          "ruleName": "PEP Check",
          "matched": true,
          "score": 50,
          "confidence": 1.0,
          "alert": {
            "id": "alert_uuid",
            "severity": "MEDIUM",
            "message": "Person has PEP match"
          }
        }
      ],
      "flags": [
        {
          "type": "AGE_VERIFIED",
          "severity": "INFO",
          "message": "Person is over 18 years old"
        }
      ]
    },
    "executionTimeMs": 2450,
    "rulesTriggered": 3
  }
}

Step-by-Step Implementation

Step 1: Set Up Your Risk Matrix

Before creating entities, configure your risk matrix with rules:
// Create a risk matrix for person onboarding
const riskMatrix = await fetch('https://api.gu1.ai/risk-matrices', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'Person Onboarding Risk Matrix',
    description: 'Evaluate risk for new person entities',
    enabled: true,
    rules: [
      {
        name: 'PEP Check',
        description: 'Flag if person is politically exposed',
        condition: 'checks.pep_check.match === true',
        score: 50,
        severity: 'HIGH',
        triggers: ['entity_created'],
        targetEntityTypes: ['person'],
        enabled: true
      },
      {
        name: 'Sanctions Check',
        description: 'Flag if person is in sanctions lists',
        condition: 'checks.sanctions_check.match === true',
        score: 100,
        severity: 'CRITICAL',
        triggers: ['entity_created'],
        targetEntityTypes: ['person'],
        enabled: true
      },
      {
        name: 'Low Credit Score',
        description: 'Flag if credit score is below 600',
        condition: 'enrichment.bureau_credit.score < 600',
        score: 30,
        severity: 'MEDIUM',
        triggers: ['entity_created'],
        targetEntityTypes: ['person'],
        enabled: true
      }
    ]
  })
});

const { id: riskMatrixId } = await riskMatrix.json();
console.log('Risk Matrix created:', riskMatrixId);
See Risk Matrix API Reference for more details.

Step 2: Create Person with Specific Integrations

Instead of running all active integrations, you can specify which ones to execute:
async function onboardPerson(taxId) {
  const response = await fetch('https://api.gu1.ai/entities/automatic', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      taxId: taxId,
      country: 'BR',
      type: 'person',
      externalId: `customer_${Date.now()}`,
      isClient: true,
      riskMatrixId: 'your_risk_matrix_id',
      status: 'under_review',
      autoExecuteIntegrations: {
        executeAllActiveEnrichments: false,
        executeAllActiveChecks: false,
        enrichments: [
          'serpro_cpf',        // Basic CPF data
          'bureau_credit'      // Credit score
        ],
        checks: [
          'pep_check',         // Politically exposed person
          'sanctions_check',   // International sanctions
          'adverse_media'      // Negative news
        ]
      }
    })
  });

  const result = await response.json();

  if (!result.success) {
    throw new Error(result.error);
  }

  return result;
}

// Usage
try {
  const result = await onboardPerson('123.456.789-00');

  console.log('βœ… Person onboarded successfully!');
  console.log('Entity ID:', result.data.entity.id);
  console.log('Risk Score:', result.rulesResult?.result?.riskScore);
  console.log('Status:', result.data.entity.status);

  // Check if any alerts were generated
  const alerts = result.rulesResult?.result?.rulesExecuted
    ?.filter(rule => rule.alert)
    .map(rule => rule.alert);

  if (alerts && alerts.length > 0) {
    console.log('⚠️  Alerts generated:', alerts.length);
    alerts.forEach(alert => {
      console.log(`  - [${alert.severity}] ${alert.message}`);
    });
  }

} catch (error) {
  console.error('❌ Onboarding failed:', error.message);
}

Step 3: Handle Real-Time Updates with Socket.IO

Listen for real-time events during the onboarding process:
import { io } from 'socket.io-client';

// Connect to gu1's Socket.IO server
const socket = io('https://api.gu1.ai', {
  auth: {
    token: 'YOUR_API_KEY'
  },
  query: {
    organizationId: 'your_org_id'
  }
});

// Listen for entity creation started
socket.on('entity:creation-started', (data) => {
  console.log('πŸš€ Creation started:', data.taxId);
  // Show loading UI
});

// Listen for entity creation completed
socket.on('entity:creation-completed', (data) => {
  console.log('βœ… Creation completed:', {
    entityId: data.mainEntityId,
    name: data.mainEntityName,
    riskScore: data.riskScore
  });
  // Update UI with entity details
});

// Listen for risk matrix execution completed
socket.on('risk-matrix:executed', (data) => {
  console.log('🎯 Risk assessment completed:', {
    entityId: data.entityId,
    riskScore: data.riskScore,
    alertsCount: data.alertsGenerated
  });
  // Show risk score in UI
});

// Listen for new alerts
socket.on('alert:created', (data) => {
  console.log('⚠️  New alert:', {
    severity: data.severity,
    message: data.message,
    entityId: data.entityId
  });
  // Show alert notification
});

// Listen for investigations
socket.on('investigation:created', (data) => {
  console.log('πŸ” Investigation created:', {
    id: data.investigationId,
    priority: data.priority,
    alertsCount: data.consolidatedAlerts
  });
  // Redirect to investigation page
});

Step 4: Handle Risk-Based Workflows

Based on the risk score and alerts, implement different workflows:
async function handleOnboardingResult(result) {
  const { entity } = result.data;
  const riskScore = result.rulesResult?.result?.riskScore || 0;
  const alerts = result.rulesResult?.result?.rulesExecuted
    ?.filter(rule => rule.alert) || [];

  // Risk-based decision logic
  if (riskScore >= 80) {
    // High Risk - Manual Review Required
    await createManualReviewTask(entity.id, {
      priority: 'HIGH',
      reason: 'High risk score detected',
      riskScore,
      alerts: alerts.length
    });

    await notifyComplianceTeam(entity, riskScore, alerts);
    await updateEntityStatus(entity.id, 'under_review');

    return {
      decision: 'MANUAL_REVIEW',
      action: 'HOLD',
      message: 'Manual review required due to high risk'
    };

  } else if (riskScore >= 50 || alerts.length > 0) {
    // Medium Risk - Enhanced Due Diligence
    await requestAdditionalDocuments(entity.id, [
      'proof_of_address',
      'proof_of_income',
      'bank_statement'
    ]);

    await updateEntityStatus(entity.id, 'under_review');

    return {
      decision: 'ENHANCED_DUE_DILIGENCE',
      action: 'REQUEST_DOCS',
      message: 'Additional documentation required'
    };

  } else {
    // Low Risk - Auto-Approve
    await updateEntityStatus(entity.id, 'active');
    await enableCustomerAccount(entity.id);
    await sendWelcomeEmail(entity);

    return {
      decision: 'APPROVED',
      action: 'ACTIVATE',
      message: 'Customer approved and activated'
    };
  }
}

// Helper functions
async function createManualReviewTask(entityId, details) {
  await fetch('https://api.gu1.ai/tasks', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      type: 'manual_review',
      entityId: entityId,
      priority: details.priority,
      assignTo: 'compliance_team',
      dueDate: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
      context: details
    })
  });
}

async function updateEntityStatus(entityId, status) {
  await fetch(`https://api.gu1.ai/entities/${entityId}`, {
    method: 'PATCH',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ status })
  });
}

Understanding the Rules Engine Integration

How Risk Matrices Work

When you set riskMatrixId in your request, the system automatically:
  1. Creates the entity with basic data from official registries
  2. Executes enrichments to gather additional information
  3. Executes checks for compliance (PEP, sanctions, etc.)
  4. Triggers the risk matrix with the entity_created trigger
  5. Evaluates all rules that match:
    • triggers includes "entity_created"
    • targetEntityTypes includes "person"
    • enabled is true
  6. Calculates risk score by summing scores from matched rules
  7. Generates alerts for rules that match and have high severity
  8. Consolidates alerts into investigations (after 3 seconds)
  9. Updates entity with final risk score and status
  10. Sends notifications via Socket.IO and webhooks

Rule Condition Examples

Rules can access enrichment and check results in their conditions:
// Access enrichment data
enrichment.serpro_cpf.status === 'REGULAR'
enrichment.bureau_credit.score < 600
enrichment.bureau_credit.rating === 'POOR'

// Access check results
checks.pep_check.match === true
checks.sanctions_check.status === 'HIT'
checks.adverse_media.results?.length > 0

// Access entity basic data
entity.type === 'person'
entity.countryCode === 'BR'
entity.isClient === true

// Combine multiple conditions
checks.pep_check.match === true && enrichment.bureau_credit.score < 500
See Rules API Reference for complete condition syntax.

Error Handling

Common Errors and Solutions

async function createPersonWithErrorHandling(taxId) {
  try {
    const response = await fetch('https://api.gu1.ai/entities/automatic', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer YOUR_API_KEY',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        taxId: taxId,
        country: 'BR',
        type: 'person',
        riskMatrixId: 'risk_matrix_id',
        autoExecuteIntegrations: {
          executeAllActiveEnrichments: true,
          executeAllActiveChecks: true
        }
      })
    });

    const result = await response.json();

    if (!result.success) {
      // Handle different error types
      switch (response.status) {
        case 400:
          // Invalid request
          console.error('Invalid request:', result.error);
          throw new Error(`Invalid data: ${result.error}`);

        case 404:
          // Person not found in registry
          console.error('Person not found:', result.details);
          throw new Error('CPF not found in official registry');

        case 409:
          // Person already exists
          console.log('Person already exists:', result.details.existingEntityId);
          return {
            success: true,
            entity: await getEntity(result.details.existingEntityId),
            alreadyExisted: true
          };

        case 429:
          // Rate limit exceeded
          console.error('Rate limit exceeded');
          throw new Error('Too many requests. Please try again later.');

        default:
          throw new Error(result.error || 'Unknown error');
      }
    }

    // Check for partial failures (enrichments/checks that failed)
    if (result.data.errors) {
      const { enrichmentFailed, creationFailed } = result.data.errors;

      if (enrichmentFailed.length > 0) {
        console.warn('Some enrichments failed:', enrichmentFailed);
        // Continue anyway - entity was created
      }

      if (creationFailed.length > 0) {
        console.error('Some entities failed to create:', creationFailed);
        // This shouldn't happen for the main entity
      }
    }

    return result;

  } catch (error) {
    console.error('Onboarding error:', error);
    throw error;
  }
}

Best Practices

1. Always Set a Risk Matrix

// ❌ Bad: No risk assessment
const result = await createPerson({
  taxId: '123.456.789-00',
  country: 'BR',
  type: 'person'
  // Missing riskMatrixId
});

// βœ… Good: Risk assessment included
const result = await createPerson({
  taxId: '123.456.789-00',
  country: 'BR',
  type: 'person',
  riskMatrixId: 'your_risk_matrix_id' // Always include
});

2. Use Specific Integrations for Better Performance

// ❌ Slower: Execute all active integrations
autoExecuteIntegrations: {
  executeAllActiveEnrichments: true,
  executeAllActiveChecks: true
}

// βœ… Faster: Specify only what you need
autoExecuteIntegrations: {
  enrichments: ['serpro_cpf', 'bureau_credit'],
  checks: ['pep_check', 'sanctions_check']
}

3. Handle Async Operations

The creation is synchronous, but notifications are async:
// βœ… Good: Don't wait for notifications
const result = await createPerson(data);
// Entity is created and risk matrix executed
// Notifications will arrive via Socket.IO

// ❌ Bad: Trying to wait for notifications
await createPerson(data);
await sleep(5000); // Don't do this
// Notifications are async and unpredictable

4. Monitor Data Coverage

If rules fail due to missing data, check coverage:
if (!result.rulesResult.executed) {
  const { metadata } = result.rulesResult;

  if (metadata?.missingFields) {
    console.log('Missing fields:', metadata.missingFields);
    console.log('Recommended providers:', metadata.recommendedProviders);

    // Enable missing providers and try again
    await enableProviders(metadata.recommendedProviders);
  }
}

Person API Reference

Complete API documentation for person creation

Risk Matrix Guide

Learn how to configure risk matrices and rules

Integrations Marketplace

Browse available enrichment and check providers

Webhooks Setup

Configure webhooks for event notifications