Skip to main content

Complete KYB Verification Workflow

gu1โ€™s KYB workflow automates the entire business verification process from initial data collection to ongoing monitoring. This guide walks through each step with technical implementation details.

Workflow Overview

Step 1: Initial Data Collection

What to Collect

Gather basic business information from your application form:
  • Company Name: Legal name and trade name
  • Registration Number: Government-issued business registration
  • Tax ID: EIN (US), CNPJ (Brazil), RFC (Mexico), etc.
  • Incorporation Date: When the business was formed
  • Country: Jurisdiction of incorporation
  • Business Address: Registered office location
  • Industry: Type of business activity
  • Expected Transaction Volume: Monthly/annual estimates

Example Application Form

const businessApplication = {
  legalName: "Tech Solutions Sociedade Anรดnima",
  tradeName: "Tech Solutions",
  registrationNumber: "12.345.678/0001-90",
  taxId: "12.345.678/0001-90",
  incorporationDate: "2020-06-15",
  country: "BR",
  address: {
    street: "Av. Paulista, 1000",
    city: "Sรฃo Paulo",
    state: "SP",
    postalCode: "01310-100"
  },
  industry: "Software Development",
  website: "https://techsolutions.com.br",
  expectedMonthlyVolume: 250000,
  businessDescription: "B2B SaaS platform for enterprise clients"
};

Step 2: Create Business Entity

Use the Entities API to create a company entity in gu1:
curl -X POST http://api.gu1.ai/entities \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "company",
    "externalId": "business_12345",
    "name": "Tech Solutions Sociedade Anรดnima",
    "taxId": "12.345.678/0001-90",
    "countryCode": "BR",
    "entityData": {
      "company": {
        "legalName": "Tech Solutions Sociedade Anรดnima",
        "tradeName": "Tech Solutions",
        "incorporationDate": "2020-06-15",
        "industry": "Software Development",
        "employeeCount": 50,
        "revenue": 5000000
      }
    },
    "attributes": {
      "registrationNumber": "12.345.678/0001-90",
      "website": "https://techsolutions.com.br",
      "registeredAddress": "Av. Paulista, 1000, Sรฃo Paulo",
      "expectedMonthlyVolume": 250000,
      "applicationDate": "2024-10-03T10:00:00Z"
    }
  }'
Response:
{
  "success": true,
  "entity": {
    "id": "660e9511-f39c-52e5-b827-557766551111",
    "externalId": "business_12345",
    "type": "company",
    "name": "Tech Solutions Sociedade Anรดnima",
    "riskScore": 0,
    "status": "under_review",
    "createdAt": "2024-10-03T10:00:00Z"
  }
}

Step 3: Document Upload & Verification

Upload required business documents for verification:

Required Documents

  1. Articles of Incorporation - Founding document
  2. Business License - Government-issued operating permit
  3. Tax Certificate - Proof of tax registration
  4. Proof of Address - Utility bill or bank statement
  5. Beneficial Ownership Declaration - UBO information

Upload Documents

async function uploadBusinessDocuments(entityId, documents) {
  const documentUploads = [];

  for (const doc of documents) {
    const formData = new FormData();
    formData.append('file', doc.file);
    formData.append('documentType', doc.type);
    formData.append('entityId', entityId);

    const response = await fetch('http://api.gu1.ai/documents', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${API_KEY}`
      },
      body: formData
    });

    documentUploads.push(await response.json());
  }

  return documentUploads;
}

// Usage
const documents = [
  { file: articlesOfIncorporation, type: 'articles_of_incorporation' },
  { file: businessLicense, type: 'business_license' },
  { file: taxCertificate, type: 'tax_certificate' },
  { file: proofOfAddress, type: 'proof_of_address' }
];

const uploadedDocs = await uploadBusinessDocuments(entityId, documents);

Step 4: AI Analysis & Risk Assessment

Request AI-powered analysis of the business entity:
async function requestAIAnalysis(entityId) {
  const response = await fetch(
    `http://api.gu1.ai/entities/${entityId}/ai-analysis`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        analysisType: 'kyb_verification',
        includeDocuments: true,
        checkSanctions: true,
        checkAdverseMedia: true
      })
    }
  );

  return await response.json();
}
AI Analysis Response:
{
  "analysisId": "analysis_abc123",
  "entityId": "660e9511-f39c-52e5-b827-557766551111",
  "riskScore": 35,
  "riskLevel": "medium",
  "findings": {
    "documentVerification": {
      "status": "verified",
      "confidence": 0.95,
      "articlesOfIncorporation": "valid",
      "businessLicense": "valid",
      "taxCertificate": "valid"
    },
    "businessLegitimacy": {
      "status": "verified",
      "registrationVerified": true,
      "taxIdValid": true,
      "addressConfirmed": true
    },
    "sanctionsScreening": {
      "status": "clear",
      "listsChecked": ["OFAC", "UN", "EU", "UK"],
      "matches": []
    },
    "adverseMedia": {
      "status": "minor_flags",
      "findings": [
        {
          "source": "news_article",
          "date": "2023-05-15",
          "summary": "Small tax dispute resolved",
          "severity": "low"
        }
      ]
    },
    "riskFactors": [
      {
        "factor": "new_business",
        "impact": 20,
        "description": "Company incorporated less than 5 years ago"
      },
      {
        "factor": "high_growth_industry",
        "impact": 15,
        "description": "Software industry has elevated fraud risk"
      },
      {
        "factor": "clean_compliance_history",
        "impact": -10,
        "description": "No regulatory violations found"
      }
    ]
  },
  "recommendation": "approve_with_monitoring",
  "nextSteps": [
    "Verify beneficial ownership",
    "Set transaction monitoring thresholds",
    "Schedule 6-month review"
  ]
}

Step 5: Risk-Based Decision

Based on the risk score, route to appropriate workflow:
async function processKYBDecision(analysisResult) {
  const { riskScore, riskLevel, recommendation } = analysisResult;

  if (riskScore < 30) {
    // Low Risk - Auto-approve
    return await autoApprove(analysisResult.entityId);

  } else if (riskScore < 70) {
    // Medium Risk - Enhanced Due Diligence
    return await enhancedDueDiligence(analysisResult.entityId);

  } else {
    // High Risk - Manual Review Required
    return await flagForManualReview(analysisResult.entityId, analysisResult.findings);
  }
}

async function autoApprove(entityId) {
  // Update entity status to approved
  await fetch(`http://api.gu1.ai/entities/${entityId}`, {
    method: 'PATCH',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      attributes: {
        kybStatus: 'approved',
        approvedAt: new Date().toISOString(),
        approvedBy: 'automated_system',
        reviewNotes: 'Low risk - auto-approved'
      }
    })
  });

  // Send approval notification
  await sendApprovalEmail(entityId);

  // Enable monitoring
  await enableOngoingMonitoring(entityId);

  return { status: 'approved', action: 'auto_approved' };
}

async function enhancedDueDiligence(entityId) {
  // Request additional information
  await requestAdditionalDocs(entityId, [
    'financial_statements',
    'ownership_structure',
    'source_of_funds'
  ]);

  // Update status
  await updateEntityStatus(entityId, 'enhanced_due_diligence');

  return { status: 'pending', action: 'edd_required' };
}

async function flagForManualReview(entityId, findings) {
  // Create review task
  await createReviewTask({
    entityId,
    priority: 'high',
    assignTo: 'compliance_team',
    findings,
    dueDate: new Date(Date.now() + 24 * 60 * 60 * 1000) // 24 hours
  });

  return { status: 'manual_review', action: 'flagged_for_review' };
}

Step 6: Beneficial Ownership Verification

Identify and verify Ultimate Beneficial Owners (UBOs):
async function verifyBeneficialOwners(entityId, owners) {
  const verifiedOwners = [];

  for (const owner of owners) {
    // Create person entity for each UBO
    const uboEntity = await fetch('http://api.gu1.ai/entities', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        type: 'person',
        externalId: `ubo_${owner.id}`,
        name: `${owner.firstName} ${owner.lastName}`,
        countryCode: owner.nationality,
        entityData: {
          person: {
            firstName: owner.firstName,
            lastName: owner.lastName,
            dateOfBirth: owner.dateOfBirth,
            nationality: owner.nationality
          }
        },
        attributes: {
          ownershipPercentage: owner.ownership,
          isPEP: owner.isPEP,
          relationshipToCompany: 'beneficial_owner'
        }
      })
    });

    const ubo = await uboEntity.json();

    // Run KYC checks on UBO
    const kycResult = await runKYCCheck(ubo.entity.id);

    // Create relationship between company and UBO
    await createRelationship({
      fromEntityId: entityId,
      toEntityId: ubo.entity.id,
      relationshipType: 'beneficial_owner',
      ownershipPercentage: owner.ownership
    });

    verifiedOwners.push({
      ...ubo.entity,
      kycStatus: kycResult.status,
      riskScore: kycResult.riskScore
    });
  }

  return verifiedOwners;
}

Step 7: Setup Ongoing Monitoring

Enable continuous monitoring for approved businesses:
async function setupOngoingMonitoring(entityId) {
  // Configure monitoring rules
  await fetch('http://api.gu1.ai/rules', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      name: `KYB Monitoring - ${entityId}`,
      entityId: entityId,
      rules: [
        {
          type: 'sanctions_screening',
          frequency: 'daily',
          action: 'alert_compliance_team'
        },
        {
          type: 'adverse_media',
          frequency: 'weekly',
          action: 'create_review_task'
        },
        {
          type: 'ownership_changes',
          frequency: 'realtime',
          action: 'trigger_reverification'
        },
        {
          type: 'transaction_anomalies',
          threshold: 'high',
          action: 'flag_for_review'
        }
      ]
    })
  });

  // Setup webhook notifications
  await configureWebhook({
    entityId,
    events: [
      'sanctions_match',
      'adverse_media_found',
      'ownership_change',
      'transaction_anomaly'
    ],
    url: 'https://your-app.com/webhooks/kyb-alerts'
  });
}

Step 8: Status Updates & Notifications

Keep the business informed throughout the process:
async function sendStatusUpdate(entityId, status, details) {
  // Get entity details
  const entity = await getEntity(entityId);

  // Send email notification
  await sendEmail({
    to: entity.attributes.contactEmail,
    subject: `KYB Verification Update - ${status}`,
    template: 'kyb_status_update',
    data: {
      companyName: entity.name,
      status: status,
      details: details,
      nextSteps: getNextSteps(status),
      dashboardUrl: `https://app.gu1.ai/onboarding/${entityId}`
    }
  });

  // Send webhook to your system
  await sendWebhook({
    event: 'kyb_status_changed',
    entityId: entityId,
    status: status,
    timestamp: new Date().toISOString(),
    details: details
  });
}

// Status update examples
await sendStatusUpdate(entityId, 'documents_received', {
  message: 'We have received your documents and are processing them.'
});

await sendStatusUpdate(entityId, 'approved', {
  message: 'Your business has been verified and approved!',
  approvalDate: new Date().toISOString()
});

await sendStatusUpdate(entityId, 'additional_info_required', {
  message: 'We need additional information to complete your verification.',
  requiredDocuments: ['financial_statements', 'ownership_structure']
});

Complete Workflow Implementation

Hereโ€™s a complete function that orchestrates the entire KYB workflow:
async function executeKYBWorkflow(applicationData) {
  try {
    // Step 1 & 2: Create entity
    console.log('Creating business entity...');
    const entity = await createBusinessEntity(applicationData);

    // Step 3: Upload documents
    console.log('Uploading verification documents...');
    await uploadBusinessDocuments(entity.id, applicationData.documents);

    // Step 4: Request AI analysis
    console.log('Running AI analysis...');
    const analysis = await requestAIAnalysis(entity.id);

    // Step 5: Make risk-based decision
    console.log('Processing KYB decision...');
    const decision = await processKYBDecision(analysis);

    if (decision.status === 'approved') {
      // Step 6: Verify UBOs (for approved entities)
      console.log('Verifying beneficial owners...');
      await verifyBeneficialOwners(entity.id, applicationData.beneficialOwners);

      // Step 7: Setup monitoring
      console.log('Setting up ongoing monitoring...');
      await setupOngoingMonitoring(entity.id);
    }

    // Step 8: Send status update
    console.log('Sending status notification...');
    await sendStatusUpdate(entity.id, decision.status, analysis.findings);

    return {
      success: true,
      entityId: entity.id,
      status: decision.status,
      riskScore: analysis.riskScore,
      decision: decision
    };

  } catch (error) {
    console.error('KYB workflow error:', error);
    return {
      success: false,
      error: error.message
    };
  }
}

Timeline Estimates

Risk LevelAutomated ProcessingWith Manual ReviewTraditional Process
Low Risk2-5 minutes30 minutes2-3 days
Medium Risk15-30 minutes2-4 hours3-5 days
High Risk30-60 minutes1-2 days5-10 days

Next Steps

Data Requirements

See detailed data fields needed for KYB

Complete Example

Full working code implementation

API Reference

Entity creation API documentation

Webhooks

Setup real-time notifications