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 companies (businesses) using gu1’s automatic entity creation with integrated risk assessment. The system will:
  1. Fetch official company data from business registries (e.g., CNPJ in Brazil)
  2. Extract shareholder structure automatically (up to 5 levels deep)
  3. Create shareholder entities recursively with their own enrichments
  4. Execute enrichments for the company and all shareholders
  5. Run compliance checks (sanctions, adverse media, ownership verification)
  6. Execute risk matrix rules for the company (shareholders can also trigger rules)
  7. Generate alerts and investigations if rules are triggered
  8. Send notifications via Socket.IO and webhooks
This is ideal for KYB (Know Your Business) processes where you need complete company verification including beneficial ownership structure.

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 company tax ID from a supported country (e.g., CNPJ for Brazil)

The Complete Flow

Here’s what happens when you create a company automatically with shareholder traversal and risk matrix:

Quick Start Example

Basic Company Onboarding with Shareholders and Risk Assessment

curl -X POST https://api.gu1.ai/entities/automatic \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "taxId": "12.345.678/0001-90",
    "country": "BR",
    "type": "company",
    "depth": 2,
    "isClient": true,
    "riskMatrixId": "risk_matrix_uuid",
    "autoExecuteIntegrations": {
      "executeAllActiveEnrichments": true,
      "executeAllActiveChecks": true
    },
    "autoExecuteIntegrationsShareholders": {
      "enrichments": {
        "company": ["serpro_cnpj", "receita_federal"],
        "person": ["serpro_cpf"]
      },
      "checks": {
        "company": ["sanctions_check"],
        "person": ["pep_check", "sanctions_check"]
      }
    }
  }'

Complete Response Example

When the process completes successfully, you’ll receive a comprehensive response with the full ownership structure:
{
  "success": true,
  "data": {
    "entity": {
      "id": "company_uuid_abc123",
      "organizationId": "org_uuid",
      "type": "company",
      "name": "Tech Solutions Ltda",
      "taxId": "12345678000190",
      "countryCode": "BR",
      "status": "under_review",
      "riskScore": 42,
      "isClient": true,
      "entityData": {
        "company": {
          "legalName": "Tech Solutions Ltda",
          "tradeName": "Tech Solutions",
          "incorporationDate": "2020-01-15",
          "industryCode": "6201-5/00",
          "legalNature": "206-2",
          "companySize": "MEDIUM"
        }
      },
      "enrichmentData": {
        "serpro_cnpj": {
          "status": "ATIVA",
          "situation": "REGULAR",
          "capitalSocial": "500000.00"
        },
        "receita_federal": {
          "taxCompliance": "REGULAR",
          "debts": false
        }
      },
      "checksData": {
        "overallStatus": "CLEAR",
        "results": [
          {
            "providerCode": "sanctions_check",
            "status": "CLEAR",
            "match": false
          },
          {
            "providerCode": "adverse_media",
            "status": "CLEAR",
            "articlesFound": 0
          }
        ]
      },
      "createdAt": "2024-12-23T10:30:00.000Z",
      "updatedAt": "2024-12-23T10:30:12.000Z"
    },
    "summary": {
      "entitiesCreated": 5,
      "relationshipsCreated": 4,
      "errorsCount": 0
    },
    "entitiesCreatedDetails": [
      {
        "id": "person_uuid_001",
        "name": "JoΓ£o Silva",
        "taxId": "12345678900",
        "type": "person"
      },
      {
        "id": "person_uuid_002",
        "name": "Maria Santos",
        "taxId": "98765432100",
        "type": "person"
      },
      {
        "id": "company_uuid_002",
        "name": "Holdings ABC Ltda",
        "taxId": "98765432000101",
        "type": "company"
      },
      {
        "id": "person_uuid_003",
        "name": "Carlos Costa",
        "taxId": "11122233344",
        "type": "person"
      }
    ]
  },
  "rulesResult": {
    "success": true,
    "executed": true,
    "result": {
      "entityId": "company_uuid_abc123",
      "entityType": "company",
      "riskScore": 42,
      "overallConfidence": 0.92,
      "totalRules": 15,
      "successfulRules": 4,
      "failedRules": 0,
      "rulesExecuted": [
        {
          "ruleId": "rule_company_age",
          "ruleName": "New Company (< 2 years)",
          "matched": true,
          "score": 25,
          "confidence": 1.0
        },
        {
          "ruleId": "rule_ownership_complexity",
          "ruleName": "Complex Ownership Structure",
          "matched": true,
          "score": 15,
          "confidence": 0.85
        },
        {
          "ruleId": "rule_pep_shareholders",
          "ruleName": "PEP in Shareholder Structure",
          "matched": false,
          "score": 0,
          "confidence": 1.0
        },
        {
          "ruleId": "rule_sanctions_company",
          "ruleName": "Sanctions Check - Company",
          "matched": false,
          "score": 0,
          "confidence": 1.0
        }
      ],
      "flags": [
        {
          "type": "OWNERSHIP_VERIFIED",
          "severity": "INFO",
          "message": "Beneficial ownership structure mapped to 2 levels"
        },
        {
          "type": "NEW_COMPANY",
          "severity": "WARNING",
          "message": "Company incorporated less than 2 years ago"
        }
      ]
    },
    "executionTimeMs": 5230,
    "rulesTriggered": 2
  }
}

Understanding Shareholder Traversal

The depth Parameter

The depth parameter controls how many levels of the ownership structure to traverse:
  • depth: 0 - Only create the main company (no shareholders)
  • depth: 1 - Create main company + direct shareholders (1 level)
  • depth: 2 - Create main company + shareholders + their shareholders (2 levels)
  • depth: 3-5 - Continue recursively up to 5 levels
// Example: depth = 2
// Main Company (Tech Solutions Ltda)
//   β”œβ”€ JoΓ£o Silva (60%) - Person
//   β”œβ”€ Holdings ABC Ltda (40%) - Company
//   β”‚   β”œβ”€ Maria Santos (70%) - Person
//   β”‚   └─ Carlos Costa (30%) - Person
// Total entities created: 5 (1 main + 4 shareholders)
// Total relationships created: 4

Shareholder-Specific Integrations

You can configure different integrations for company vs person shareholders:
autoExecuteIntegrationsShareholders: {
  enrichments: {
    company: ['serpro_cnpj', 'receita_federal'],  // For company shareholders
    person: ['serpro_cpf']                         // For person shareholders
  },
  checks: {
    company: ['sanctions_check', 'adverse_media'], // For company shareholders
    person: ['pep_check', 'sanctions_check']       // For person shareholders
  }
}
This is more efficient than running all checks on everyone.

Step-by-Step Implementation

Step 1: Set Up Your Risk Matrix for Companies

Create a risk matrix specifically for company 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: 'Company Onboarding Risk Matrix',
    description: 'Evaluate risk for new company entities',
    enabled: true,
    rules: [
      {
        name: 'New Company Flag',
        description: 'Flag companies less than 2 years old',
        condition: `
          const incorporationDate = new Date(enrichment.serpro_cnpj?.incorporationDate);
          const now = new Date();
          const ageYears = (now - incorporationDate) / (1000 * 60 * 60 * 24 * 365);
          return ageYears < 2;
        `,
        score: 25,
        severity: 'MEDIUM',
        triggers: ['entity_created'],
        targetEntityTypes: ['company'],
        enabled: true
      },
      {
        name: 'Sanctions Check - Company',
        description: 'Flag if company is in sanctions lists',
        condition: 'checks.sanctions_check.match === true',
        score: 100,
        severity: 'CRITICAL',
        triggers: ['entity_created'],
        targetEntityTypes: ['company'],
        enabled: true
      },
      {
        name: 'Complex Ownership',
        description: 'Flag companies with complex ownership structures',
        condition: `
          const shareholderCount = context.relationships?.length || 0;
          return shareholderCount > 10;
        `,
        score: 15,
        severity: 'LOW',
        triggers: ['entity_created'],
        targetEntityTypes: ['company'],
        enabled: true
      },
      {
        name: 'High Risk Industry',
        description: 'Flag companies in high-risk industries',
        condition: `
          const highRiskIndustries = ['6201', '6202', '6463', '6491'];
          const industryCode = enrichment.serpro_cnpj?.industryCode?.substring(0, 4);
          return highRiskIndustries.includes(industryCode);
        `,
        score: 30,
        severity: 'HIGH',
        triggers: ['entity_created'],
        targetEntityTypes: ['company'],
        enabled: true
      }
    ]
  })
});

const { id: riskMatrixId } = await riskMatrix.json();
console.log('Risk Matrix created:', riskMatrixId);

Step 2: Create Company with Full Ownership Structure

async function onboardCompanyWithOwnership(cnpj, depth = 2) {
  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: cnpj,
      country: 'BR',
      type: 'company',
      depth: depth,
      externalId: `business_${Date.now()}`,
      isClient: true,
      riskMatrixId: 'your_risk_matrix_id',
      status: 'under_review',

      // Main company integrations
      autoExecuteIntegrations: {
        enrichments: [
          'serpro_cnpj',       // Basic company data + shareholders
          'receita_federal',   // Tax compliance
          'serasa_company'     // Credit score
        ],
        checks: [
          'sanctions_check',   // International sanctions
          'adverse_media',     // Negative news
          'ownership_verify'   // Verify ownership structure
        ]
      },

      // Shareholder integrations (differentiated by type)
      autoExecuteIntegrationsShareholders: {
        enrichments: {
          company: [
            'serpro_cnpj',     // Company shareholders: basic data
            'receita_federal'  // Company shareholders: tax status
          ],
          person: [
            'serpro_cpf'       // Person shareholders: basic data only
          ]
        },
        checks: {
          company: [
            'sanctions_check'  // Company shareholders: sanctions only
          ],
          person: [
            'pep_check',       // Person shareholders: PEP check
            'sanctions_check'  // Person shareholders: sanctions
          ]
        }
      }
    })
  });

  const result = await response.json();

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

  return result;
}

// Usage
try {
  const result = await onboardCompanyWithOwnership('12.345.678/0001-90', 2);

  console.log('βœ… Company onboarded successfully!');
  console.log('Main Entity:', result.data.entity.name);
  console.log('Risk Score:', result.rulesResult?.result?.riskScore);
  console.log('Entities Created:', result.data.summary.entitiesCreated);
  console.log('Relationships Created:', result.data.summary.relationshipsCreated);

  // Log ownership structure
  console.log('\nπŸ“Š Ownership Structure:');
  result.data.entitiesCreatedDetails.forEach((entity, index) => {
    console.log(`  ${index + 1}. ${entity.name} (${entity.type}) - ${entity.taxId}`);
  });

  // Check for errors
  if (result.data.errors) {
    const totalErrors =
      result.data.errors.creationFailed.length +
      result.data.errors.enrichmentFailed.length;

    if (totalErrors > 0) {
      console.log('\n⚠️  Partial failures detected:');
      result.data.errors.creationFailed.forEach(err => {
        console.log(`  - Failed to create: ${err.name} (${err.taxId})`);
      });
      result.data.errors.enrichmentFailed.forEach(err => {
        console.log(`  - Enrichment failed: ${err.name} (${err.taxId})`);
      });
    }
  }

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

Step 3: Visualize Ownership Structure

After creating the company, fetch and visualize the ownership graph:
async function getOwnershipStructure(companyId) {
  // Fetch entity with relationships
  const response = await fetch(
    `https://api.gu1.ai/entities/${companyId}?includeRelationships=true`,
    {
      headers: {
        'Authorization': 'Bearer YOUR_API_KEY'
      }
    }
  );

  const { entity, relationships } = await response.json();

  // Build ownership tree
  const tree = buildOwnershipTree(entity, relationships);
  return tree;
}

function buildOwnershipTree(entity, relationships, level = 0) {
  const indent = '  '.repeat(level);
  let tree = `${indent}${entity.name} (${entity.type})\n`;

  // Find shareholders of this entity
  const shareholders = relationships.filter(
    rel => rel.fromEntityId === entity.id && rel.relationshipType === 'shareholder'
  );

  shareholders.forEach(rel => {
    const percentage = rel.metadata?.ownershipPercentage || 0;
    tree += `${indent}  β”œβ”€ ${rel.toEntity.name} (${percentage}%)\n`;

    // Recursively get sub-shareholders if available
    if (rel.toEntity.relationships) {
      tree += buildOwnershipTree(rel.toEntity, rel.toEntity.relationships, level + 2);
    }
  });

  return tree;
}

// Usage
const structure = await getOwnershipStructure('company_uuid_abc123');
console.log('Ownership Structure:\n', structure);

// Output:
// Tech Solutions Ltda (company)
//   β”œβ”€ JoΓ£o Silva (60%)
//   β”œβ”€ Holdings ABC Ltda (40%)
//     β”œβ”€ Maria Santos (70%)
//     └─ Carlos Costa (30%)

Step 4: Handle Complex Scenarios

Scenario 1: Circular Ownership Detection

The system automatically prevents circular ownership loops:
// Company A β†’ Company B β†’ Company A (circular)
// System will detect and stop at the second occurrence of Company A

Scenario 2: Large Shareholder Structures

For companies with many shareholders (e.g., 50+), consider:
// Option 1: Limit depth to reduce processing time
depth: 1  // Only direct shareholders

// Option 2: Use specific enrichments only
autoExecuteIntegrationsShareholders: {
  enrichments: {
    company: ['serpro_cnpj'],  // Only basic data
    person: ['serpro_cpf']      // Only basic data
  },
  checks: {
    company: [],  // No checks
    person: []    // No checks
  }
}

// Option 3: Skip shareholders entirely for initial creation
depth: 0  // Create company only, add shareholders later

Scenario 3: Foreign Shareholders

When shareholders are from different countries:
// The system will:
// 1. Detect country from taxId format
// 2. Use country-specific providers automatically
// 3. Create relationships with country metadata

// Example: Brazilian company with US shareholder
// Main: BR company β†’ uses serpro_cnpj
// Shareholder: US person β†’ uses us_ssn_lookup (if available)

Real-Time Updates for Company Creation

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

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

// Track creation progress
let entitiesCreated = 0;
let shareholdersCreated = 0;

socket.on('entity:creation-started', (data) => {
  console.log('πŸš€ Starting creation:', data.taxId);
});

socket.on('entity:creation-completed', (data) => {
  entitiesCreated++;

  if (data.isMainEntity) {
    console.log('βœ… Main company created:', data.mainEntityName);
  } else {
    shareholdersCreated++;
    console.log(`  β”œβ”€ Shareholder ${shareholdersCreated} created:`, data.mainEntityName);
  }

  // Update progress bar
  updateProgress(entitiesCreated, shareholdersCreated);
});

socket.on('risk-matrix:executed', (data) => {
  console.log('🎯 Risk assessment:', {
    riskScore: data.riskScore,
    status: data.newStatus,
    alerts: data.alertsGenerated
  });
});

socket.on('investigation:created', (data) => {
  console.log('πŸ” Investigation opened:', {
    id: data.investigationId,
    priority: data.priority,
    reason: 'Multiple alerts consolidated'
  });
});

Understanding Risk Assessment for Companies

Company-Specific Risk Factors

Companies are evaluated differently than persons:
// Rule examples for companies
{
  // Age of company
  condition: `
    const ageYears = (new Date() - new Date(enrichment.serpro_cnpj.incorporationDate)) / 31536000000;
    return ageYears < 2;
  `,
  score: 25,
  severity: 'MEDIUM'
}

{
  // Capital social (authorized capital)
  condition: `
    const capital = parseFloat(enrichment.serpro_cnpj.capitalSocial);
    return capital < 10000; // Less than R$ 10k
  `,
  score: 20,
  severity: 'MEDIUM'
}

{
  // Industry risk
  condition: `
    const highRiskCodes = ['6201', '6463', '6491'];
    return highRiskCodes.includes(enrichment.serpro_cnpj.industryCode?.substring(0, 4));
  `,
  score: 30,
  severity: 'HIGH'
}

{
  // Ownership complexity
  condition: `
    const shareholderCount = context.relationships?.length || 0;
    const hasIndirectOwners = context.relationships?.some(r => r.level > 1);
    return shareholderCount > 10 || hasIndirectOwners;
  `,
  score: 15,
  severity: 'LOW'
}

Shareholder Risk Propagation

Risks from shareholders can affect the main company:
// Example: If any shareholder is PEP, flag the company
{
  name: 'PEP in Ownership Structure',
  condition: `
    // Check all shareholders
    const shareholders = context.shareholders || [];
    return shareholders.some(s => s.checksData?.pep_check?.match === true);
  `,
  score: 40,
  severity: 'HIGH',
  targetEntityTypes: ['company']
}

Best Practices

1. Choose Appropriate Depth

// βœ… Good: Most common use cases
depth: 0  // No shareholders - fastest, company only
depth: 1  // Direct shareholders only - balanced
depth: 2  // Two levels - complete for most cases

// ⚠️  Use carefully: Expensive operations
depth: 3  // Three levels - slow, many entities
depth: 4-5  // Very deep - only for specific compliance requirements

2. Differentiate Shareholder Integrations

// ❌ Bad: Same checks for everyone (expensive)
autoExecuteIntegrationsShareholders: {
  executeAllActiveEnrichments: true,
  executeAllActiveChecks: true
}

// βœ… Good: Targeted checks by entity type
autoExecuteIntegrationsShareholders: {
  enrichments: {
    company: ['serpro_cnpj'],    // Basic only for company shareholders
    person: ['serpro_cpf']        // Basic only for person shareholders
  },
  checks: {
    company: ['sanctions_check'], // Only critical checks
    person: ['pep_check']         // Only critical checks
  }
}

3. Handle Partial Failures Gracefully

if (result.success) {
  const { errors } = result.data;

  // Main entity always succeeds, but shareholders might fail
  if (errors.creationFailed.length > 0) {
    console.warn(`${errors.creationFailed.length} shareholders failed to create`);

    // You can:
    // 1. Continue with the main company
    // 2. Retry failed shareholders individually
    // 3. Flag for manual review
  }

  if (errors.enrichmentFailed.length > 0) {
    console.warn(`${errors.enrichmentFailed.length} entities had enrichment failures`);

    // Entity exists but some data is missing
    // You can retry enrichments later
  }
}

4. Monitor Performance

// Track creation time
const startTime = Date.now();

const result = await onboardCompany(cnpj, depth);

const duration = Date.now() - startTime;
const entitiesPerSecond = result.data.summary.entitiesCreated / (duration / 1000);

console.log(`Created ${result.data.summary.entitiesCreated} entities in ${duration}ms`);
console.log(`Performance: ${entitiesPerSecond.toFixed(2)} entities/second`);

// Typical performance:
// depth=0: 2-5 seconds (company only)
// depth=1: 5-15 seconds (5-10 entities)
// depth=2: 15-45 seconds (10-50 entities)

Troubleshooting

Issue: Timeout Errors

// Problem: Request times out with depth=3+
// Solution: Reduce depth or use fewer integrations

// Option 1: Reduce depth
depth: 1

// Option 2: Skip shareholder checks
autoExecuteIntegrationsShareholders: {
  enrichments: {
    company: ['serpro_cnpj'],
    person: ['serpro_cpf']
  },
  checks: {
    company: [],  // No checks
    person: []    // No checks
  }
}

Issue: Too Many Entities Created

// Problem: Created 100+ entities from deep structure
// Solution: Limit depth and review structure

// Check the response
console.log('Total entities:', result.data.summary.entitiesCreated);

// If too many, recreate with depth=1
if (result.data.summary.entitiesCreated > 50) {
  console.log('Structure too large, reducing depth');
  result = await onboardCompany(cnpj, 1);  // Only direct shareholders
}

Issue: Circular Ownership Detected

// The system automatically prevents circular references
// but logs them in the response

if (result.data.warnings?.includes('CIRCULAR_OWNERSHIP')) {
  console.log('Circular ownership detected - stopped at:',
    result.data.warnings.circularAt);
}

Company API Reference

Complete API documentation for company creation

Person Onboarding

Learn about person entity onboarding

Risk Matrix Guide

Configure risk matrices and rules

Relationships API

Work with entity relationships