Skip to main content

Overview

Fossapay is built with compliance at its core. This guide covers KYC (Know Your Customer) requirements, compliance standards, and best practices for maintaining regulatory compliance.

Why KYC Matters

Regulatory Compliance

Meet CBN and NDPR requirements

Fraud Prevention

Prevent identity theft and financial fraud

Risk Management

Identify and manage high-risk customers

Customer Trust

Build trust through verified identities

KYC Tiers

Fossapay supports three KYC tiers based on transaction limits:

Tier 1 - Basic

Requirements:
  • Phone number verification
  • Email verification
Limits:
  • Daily limit: ₦50,000
  • Monthly limit: ₦300,000
  • Maximum balance: ₦300,000

Tier 2 - Intermediate

Requirements:
  • Full name
  • Date of birth
  • BVN (Bank Verification Number)
  • Residential address
Limits:
  • Daily limit: ₦200,000
  • Monthly limit: ₦1,000,000
  • Maximum balance: ₦1,000,000

Tier 3 - Full

Requirements:
  • All Tier 2 requirements
  • Government-issued ID (NIN, Driver’s License, or Passport)
  • Proof of address (utility bill, bank statement)
  • Selfie verification
Limits:
  • Daily limit: ₦5,000,000
  • Monthly limit: ₦unlimited
  • Maximum balance: Unlimited

Implementing KYC

Create Customer with KYC

const customer = await fossapay.customers.create({
  email: '[email protected]',
  phone: '+2348012345678',
  first_name: 'John',
  last_name: 'Doe',
  date_of_birth: '1990-01-15',
  bvn: '22222222222',
  address: {
    street: '123 Main Street',
    city: 'Lagos',
    state: 'Lagos',
    country: 'NG'
  },
  metadata: {
    user_id: 'user_123'
  }
});

console.log(customer);
// {
//   "customer_id": "cus_abc123",
//   "kyc_tier": 2,
//   "kyc_status": "verified",
//   "daily_limit": 200000,
//   "monthly_limit": 1000000
// }

Upgrade to Tier 3

// Upload ID document
const idUpload = await fossapay.customers.uploadDocument({
  customer_id: 'cus_abc123',
  document_type: 'national_id',
  document_number: 'ABC1234567890',
  file: idImageBuffer // or file path
});

// Upload selfie
const selfieUpload = await fossapay.customers.uploadDocument({
  customer_id: 'cus_abc123',
  document_type: 'selfie',
  file: selfieImageBuffer
});

// Request tier upgrade
const upgrade = await fossapay.customers.upgradeKYC({
  customer_id: 'cus_abc123',
  target_tier: 3
});

// Check verification status
const status = await fossapay.customers.getKYCStatus('cus_abc123');

BVN Verification

Verify BVN

const verification = await fossapay.kyc.verifyBVN({
  bvn: '22222222222',
  first_name: 'John',
  last_name: 'Doe',
  date_of_birth: '1990-01-15'
});

console.log(verification);
// {
//   "status": "success",
//   "matched": true,
//   "bvn": "22222222222",
//   "data": {
//     "first_name": "JOHN",
//     "last_name": "DOE",
//     "date_of_birth": "15-Jan-1990",
//     "phone_number": "080********78"
//   }
// }

Handle BVN Mismatch

if (!verification.matched) {
  await db.customers.update(customerId, {
    kyc_status: 'failed',
    kyc_failure_reason: 'BVN details do not match'
  });

  await sendNotification(customerId, {
    title: 'KYC Verification Failed',
    message: 'The details you provided do not match your BVN records. Please contact support.'
  });
}

NIN Verification

const ninVerification = await fossapay.kyc.verifyNIN({
  nin: '12345678901',
  first_name: 'John',
  last_name: 'Doe'
});

console.log(ninVerification);
// {
//   "status": "success",
//   "matched": true,
//   "nin": "12345678901",
//   "data": {
//     "full_name": "JOHN DOE",
//     "date_of_birth": "1990-01-15",
//     "gender": "Male"
//   }
// }

Transaction Monitoring

Monitor for Suspicious Activity

async function monitorTransaction(transaction) {
  const customer = await db.customers.findOne({
    id: transaction.customer_id
  });

  // Check if exceeds tier limits
  const dailyTotal = await calculateDailyTotal(customer.id);

  if (dailyTotal + transaction.amount > customer.daily_limit) {
    // Block transaction
    await fossapay.customers.freeze({
      customer_id: customer.id,
      reason: 'Daily limit exceeded'
    });

    await sendAlert({
      type: 'limit_exceeded',
      customer_id: customer.id,
      amount: transaction.amount,
      daily_total: dailyTotal
    });

    throw new Error('Daily transaction limit exceeded');
  }

  // Check for suspicious patterns
  if (isHourBetween(0, 4) && transaction.amount > 100000) {
    await flagForReview({
      transaction_id: transaction.id,
      reason: 'Large transaction at unusual hour'
    });
  }

  // Check for rapid transactions
  const recentCount = await countRecentTransactions(customer.id, 10); // last 10 mins
  if (recentCount > 5) {
    await flagForReview({
      transaction_id: transaction.id,
      reason: 'Multiple rapid transactions'
    });
  }
}

Compliance Standards

PCI-DSS Compliance

Fossapay is PCI-DSS Level 1 compliant:
  • All data encrypted in transit (TLS 1.2+)
  • All data encrypted at rest (AES-256)
  • Regular security audits
  • No card data storage

NDPR Compliance

Nigerian Data Protection Regulation compliance:
  • Data minimization
  • Purpose limitation
  • Storage limitation
  • Consent management

CBN Regulations

Central Bank of Nigeria compliance:
  • KYC/AML requirements
  • Transaction limits
  • Settlement standards
  • Reporting requirements

Handling High-Risk Transactions

async function screenTransaction(transaction) {
  // Screen against sanctions lists
  const sanctionsCheck = await fossapay.compliance.screenSanctions({
    name: transaction.sender_name,
    account_number: transaction.sender_account
  });

  if (sanctionsCheck.hit) {
    await blockTransaction(transaction.id);
    await reportToAuthorities(transaction);
  }

  // Check for PEP (Politically Exposed Persons)
  const pepCheck = await fossapay.compliance.checkPEP({
    name: transaction.sender_name
  });

  if (pepCheck.is_pep) {
    await flagForEnhancedDueDiligence(transaction);
  }

  // AML screening
  const amlScore = await calculateAMLScore(transaction);

  if (amlScore > 70) {
    await flagForReview({
      transaction_id: transaction.id,
      reason: 'High AML risk score',
      score: amlScore
    });
  }
}

Document Requirements

Accepted ID Documents

Document TypeCodeValid For
National Identity Number (NIN)national_idPrimary ID
International PassportpassportPrimary ID
Driver’s Licensedrivers_licensePrimary ID
Voter’s Cardvoters_cardSecondary ID

Proof of Address

  • Utility bills (< 3 months old)
  • Bank statements (< 3 months old)
  • Government correspondence
  • Tenancy agreement

Webhook Events

app.post('/webhooks/fossapay', (req, res) => {
  const { event, data } = req.body;

  switch (event) {
    case 'kyc.verified':
      await handleKYCVerified(data);
      break;

    case 'kyc.failed':
      await handleKYCFailed(data);
      break;

    case 'customer.flagged':
      await handleCustomerFlagged(data);
      break;

    case 'transaction.flagged':
      await handleTransactionFlagged(data);
      break;
  }
});

async function handleKYCVerified(data) {
  await db.customers.update(data.customer_id, {
    kyc_status: 'verified',
    kyc_tier: data.tier,
    verified_at: data.verified_at
  });

  await sendNotification(data.customer_id, {
    title: 'Identity Verified!',
    message: `Your account has been upgraded to Tier ${data.tier}`
  });
}

Best Practices

Request KYC information during onboarding:
// During signup
const user = await createUser({
  email,
  phone,
  kyc_required: true
});

// Prompt for KYC immediately
await promptKYCCollection(user.id);
Start with basic info and upgrade as needed:
  • Tier 1: Email + Phone (instant)
  • Tier 2: BVN (when limits reached)
  • Tier 3: Full KYC (for high-value users)
Use automated monitoring to detect anomalies:
// Flag unusual patterns
if (transactionTime.hour < 4 && amount > 500000) {
  await flagForReview(transaction);
}
Log all KYC and compliance activities:
await db.auditLogs.create({
  type: 'kyc_verification',
  customer_id: customerId,
  action: 'bvn_verified',
  timestamp: new Date()
});
Periodically review customer KYC status:
  • Annual KYC refresh for active customers
  • Enhanced due diligence for high-risk customers
  • Document expiry checks

Regulatory Reporting

Generate Compliance Reports

// Monthly compliance report
const report = await fossapay.compliance.generateReport({
  period: 'monthly',
  year: 2024,
  month: 1,
  include: [
    'new_customers',
    'kyc_verifications',
    'flagged_transactions',
    'high_value_transactions'
  ]
});

// Submit to regulatory authorities
await submitToRegulator(report);

Next Steps