Skip to main content

eKYC Module

The ekyc module handles Sumsub eKYC and eKYB integration.

Import

const ekyc = await brdzSDK.ekyc;

Methods Overview (7 methods)

MethodDescriptionAuth RequiredHTTP Endpoint
getEkycStatusCheck eKYC statusGET /ekyc/status/:user_id
generateSumsubTokenGenerate Sumsub tokenPOST /ekyc/sumsub/token
generateSumsubTokenKYBGenerate KYB tokenPOST /ekyc/sumsub/token-kyb
generateWebSdkLinkGenerate Web SDK linkPOST /ekyc/sumsub/websdk/:user_id
generateWebSdkLinkKYBGenerate KYB SDK linkPOST /ekyc/sumsub/websdk-kyb/:user_id
syncSumsubStatusSync verification statusPOST /ekyc/sumsub/syncSumsubStatus
changeVerificationLevelChange verification levelPOST /ekyc/sumsub/changeLevel

Configuration

// Configure SDK
const config = await brdzSDK.config;
config.setBaseUrl('https://api.brdz.link/api');
config.setApiKey('your_api_key');
config.setToken('your_jwt_token'); // Required for most endpoints

Methods

getEkycStatus

Get current eKYC verification status for a user.

Syntax:

await ekyc.getEkycStatus(user_id)

Parameters:

  • user_id (string): User ID to check status

Returns:

{
message: "Status eKYC user Found",
data: {
user_id: "123",
ekyc_status: "APPROVED",
ekyc_verified_at: "2024-01-15T10:30:00Z",
user_status: "ACTIVE"
}
}

Example:

try {
const status = await ekyc.getEkycStatus('123');
console.log('eKYC Status:', status.data.ekyc_status);
console.log('User Status:', status.data.user_status);
console.log('Verified At:', status.data.ekyc_verified_at);
} catch (error) {
console.error('Status check failed:', error.message);
}

Status Values:

  • "Not yet Submit": User hasn't started verification
  • "PENDING": Verification in progress
  • "APPROVED": Successfully verified
  • "REJECTED": Verification failed

generateSumsubToken

Generate Sumsub SDK access token for individual verification (eKYC).

Syntax:

await ekyc.generateSumsubToken()

Parameters: None

Returns:

{
token: "sbx:uY0CgwELmgQAAAAJ-0S4d-JwqtVOmWPGZzAIKLLkVQKgBMASIJIbLJWLHxJD"
}

Example:

try {
const tokenResult = await ekyc.generateSumsubToken();
console.log('Sumsub Token:', tokenResult.token);

// Use token with Sumsub Web SDK
window.SumsubWebSdk.init(tokenResult.token, {
levelName: 'brdz-ekyc-indonesia-standard',
onMessage: (type, payload) => {
console.log('Sumsub message:', type, payload);
}
});
} catch (error) {
console.error('Token generation failed:', error.message);
}

Notes:

  • Token expires in 10 minutes (600 seconds)
  • Uses individual verification level: brdz-ekyc-indonesia-standard
  • Requires JWT authentication

generateSumsubTokenKYB

Generate Sumsub SDK access token for business verification (eKYB).

Syntax:

await ekyc.generateSumsubTokenKYB()

Parameters: None

Returns:

{
token: "sbx:uY0CgwELmgQAAAAJ-0S4d-JwqtVOmWPGZzAIKLLkVQKgBMASIJIbLJWLHxJD"
}

Example:

try {
const kybToken = await ekyc.generateSumsubTokenKYB();
console.log('Sumsub KYB Token:', kybToken.token);

// Use token with Sumsub Web SDK for business verification
window.SumsubWebSdk.init(kybToken.token, {
levelName: 'brdz-kyb-level',
onMessage: (type, payload) => {
console.log('Sumsub KYB message:', type, payload);
}
});
} catch (error) {
console.error('KYB token generation failed:', error.message);
}

Notes:

  • Token expires in 10 minutes (600 seconds)
  • Uses business verification level: brdz-kyb-level
  • For company/corporate verification

Generate Sumsub Web SDK direct link for individual verification.

Syntax:

await ekyc.generateWebSdkLink(user_id)

Parameters:

  • user_id (string): User ID for verification

Returns:

{
sdkLink: "https://cockpit.sumsub.com/checkus/websdk/i/brdz-ekyc-indonesia-standard/123?utm_medium=websdk&accessToken=sbx:..."
}

Example:

try {
const webLink = await ekyc.generateWebSdkLink('123');
console.log('Verification URL:', webLink.sdkLink);

// Redirect user to verification or open in popup
window.open(webLink.sdkLink, '_blank', 'width=800,height=600');

// Or redirect current window
// window.location.href = webLink.sdkLink;
} catch (error) {
console.error('Web SDK link generation failed:', error.message);
}

Notes:

  • Creates applicant record in database automatically
  • Direct URL for hosted verification flow
  • User completes verification in browser

generateWebSdkLinkKYB

Generate Sumsub Web SDK direct link for business verification.

Syntax:

await ekyc.generateWebSdkLinkKYB(user_id)

Parameters:

  • user_id (string): User ID for business verification

Returns:

{
sdkLink: "https://cockpit.sumsub.com/checkus/websdk/i/brdz-kyb-level/123?utm_medium=websdk&accessToken=sbx:..."
}

Example:

try {
const kybLink = await ekyc.generateWebSdkLinkKYB('123');
console.log('KYB Verification URL:', kybLink.sdkLink);

// Redirect business admin to KYB verification
window.location.href = kybLink.sdkLink;
} catch (error) {
console.error('KYB Web SDK link generation failed:', error.message);
}

Notes:

  • For company/business verification
  • Requires business documentation
  • Creates KYB applicant record automatically

syncSumsubStatus

Manually synchronize verification status from Sumsub.

Syntax:

await ekyc.syncSumsubStatus(payload)

Parameters:

  • payload (object): Status synchronization data
    • applicantId (string): Sumsub applicant ID
    • user_id (string): BRDZ user ID
    • reviewStatus (string): Review status from Sumsub
    • reviewAnswer (string): Review answer from Sumsub
    • verification_type (string, optional): "KYC" or "KYB" (default: "KYC")

Returns:

{
message: "User status updated to APPROVED"
}

Example:

try {
// Sync individual eKYC status
const syncResult = await ekyc.syncSumsubStatus({
applicantId: '64f8a9b2c1e2d3f4a5b6c7d8',
user_id: '123',
reviewStatus: 'completed',
reviewAnswer: 'GREEN',
verification_type: 'KYC'
});
console.log('Sync Result:', syncResult.message);

// Sync business eKYB status
const kybSync = await ekyc.syncSumsubStatus({
applicantId: '64f8a9b2c1e2d3f4a5b6c7d8',
user_id: '123',
reviewStatus: 'completed',
reviewAnswer: 'GREEN',
verification_type: 'KYB'
});
console.log('KYB Sync Result:', kybSync.message);
} catch (error) {
console.error('Status sync failed:', error.message);
}

Review Answer Values:

  • "GREEN": Approved
  • "RED": Rejected
  • "YELLOW": Needs review

Notes:

  • No authentication required (used by webhooks)
  • Used for manual status updates when webhooks fail
  • Triggers database updates and wallet creation if approved

changeVerificationLevel

Move user from one verification level to another.

Syntax:

await ekyc.changeVerificationLevel(payload)

Parameters:

  • payload (object): Level change data
    • user_id (string): User ID to change level
    • levelName (string): New verification level name

Returns:

{
success: true,
data: {
applicantId: "64f8a9b2c1e2d3f4a5b6c7d8",
levelName: "brdz-kyb-level",
createdAt: "2024-01-15T10:30:00Z"
}
}

Example:

try {
// Change from individual to business verification
const levelChange = await ekyc.changeVerificationLevel({
user_id: '123',
levelName: 'brdz-kyb-level'
});

console.log('Level Change Success:', levelChange.success);
console.log('New Level:', levelChange.data.levelName);
console.log('Applicant ID:', levelChange.data.applicantId);
} catch (error) {
console.error('Level change failed:', error.message);
}

Available Levels:

  • "brdz-ekyc-indonesia-standard": Individual verification
  • "brdz-kyb-level": Business verification

Notes:

  • Admin access required
  • User must have existing applicant record
  • Useful for upgrading from individual to business verification

Verification Flow

Complete eKYC Integration Example

class EKYCIntegration {
constructor() {
this.ekyc = null;
this.init();
}

async init() {
// Initialize SDK
const config = await brdzSDK.config;
config.setBaseUrl('https://api.brdz.link/api');
config.setApiKey('your_api_key');
config.setToken('your_jwt_token');

this.ekyc = await brdzSDK.ekyc;
}

async checkUserStatus(userId) {
try {
const status = await this.ekyc.getEkycStatus(userId);
return status.data.ekyc_status;
} catch (error) {
console.error('Status check failed:', error);
return 'ERROR';
}
}

async startVerification(userId, isBusinessVerification = false) {
try {
let webLink;

if (isBusinessVerification) {
webLink = await this.ekyc.generateWebSdkLinkKYB(userId);
} else {
webLink = await this.ekyc.generateWebSdkLink(userId);
}

// Open verification in popup
const popup = window.open(
webLink.sdkLink,
'verification',
'width=800,height=600,scrollbars=yes'
);

// Monitor popup for completion
this.monitorVerification(popup, userId);

} catch (error) {
console.error('Verification start failed:', error);
}
}

monitorVerification(popup, userId) {
const checkClosed = setInterval(async () => {
if (popup.closed) {
clearInterval(checkClosed);

// Check status after verification
setTimeout(async () => {
const status = await this.checkUserStatus(userId);
console.log('Verification completed with status:', status);

if (status === 'APPROVED') {
this.onVerificationSuccess(userId);
} else if (status === 'REJECTED') {
this.onVerificationFailed(userId);
}
}, 2000);
}
}, 1000);
}

onVerificationSuccess(userId) {
console.log('Verification successful for user:', userId);
// Redirect to dashboard or next step
window.location.href = '/dashboard';
}

onVerificationFailed(userId) {
console.log('Verification failed for user:', userId);
// Show retry options or contact support
alert('Verification failed. Please contact support or try again.');
}
}

// Usage
const ekycIntegration = new EKYCIntegration();

// Check status
const status = await ekycIntegration.checkUserStatus('123');

// Start individual verification
await ekycIntegration.startVerification('123', false);

// Start business verification
await ekycIntegration.startVerification('123', true);

Token-based Integration Example

class SumsubSDKIntegration {
async initializeSumsubSDK(userId, isBusinessVerification = false) {
try {
const ekyc = await brdzSDK.ekyc;
let tokenResult;

if (isBusinessVerification) {
tokenResult = await ekyc.generateSumsubTokenKYB();
} else {
tokenResult = await ekyc.generateSumsubToken();
}

// Initialize Sumsub Web SDK
const levelName = isBusinessVerification ?
'brdz-kyb-level' :
'brdz-ekyc-indonesia-standard';

const sumsubWebSdk = window.SumsubWebSdk.init(tokenResult.token, {
levelName: levelName,
onMessage: (type, payload) => {
console.log('Sumsub message:', type, payload);
this.handleSumsubMessage(type, payload);
},
onError: (error) => {
console.error('Sumsub error:', error);
this.handleSumsubError(error);
}
});

// Show SDK in container
sumsubWebSdk.render('#sumsub-websdk-container');

} catch (error) {
console.error('Sumsub SDK initialization failed:', error);
}
}

handleSumsubMessage(type, payload) {
switch (type) {
case 'idCheck.onReady':
console.log('Sumsub SDK ready');
break;
case 'idCheck.onStepCompleted':
console.log('Step completed:', payload);
break;
case 'idCheck.onApplicantSubmitted':
console.log('Application submitted');
this.onApplicationSubmitted(payload);
break;
default:
console.log('Unhandled message type:', type);
}
}

handleSumsubError(error) {
console.error('Sumsub SDK error:', error);
// Handle specific error cases
if (error.code === 'TOKEN_EXPIRED') {
alert('Session expired. Please refresh and try again.');
window.location.reload();
}
}

async onApplicationSubmitted(payload) {
console.log('Application submitted successfully');

// Optionally check status after submission
setTimeout(async () => {
const ekyc = await brdzSDK.ekyc;
const status = await ekyc.getEkycStatus(payload.applicantId);
console.log('Current status:', status.data.ekyc_status);
}, 5000);
}
}

// Usage
const sumsubIntegration = new SumsubSDKIntegration();

// Initialize for individual verification
await sumsubIntegration.initializeSumsubSDK('123', false);

// Initialize for business verification
await sumsubIntegration.initializeSumsubSDK('123', true);

Error Handling

Common Error Patterns

try {
const result = await ekyc.getEkycStatus('123');
} catch (error) {
if (error.message.includes('API key is missing')) {
console.error('SDK not configured properly');
// Redirect to setup or show configuration error
} else if (error.message.includes('User or Client not found')) {
console.error('Invalid user or client ID');
// Show user-friendly error message
} else if (error.message.includes('Failed to get status')) {
console.error('Server error occurred');
// Show retry option or contact support
} else {
console.error('Unexpected error:', error.message);
}
}

Sumsub-specific Errors

try {
const token = await ekyc.generateSumsubToken();
} catch (error) {
const response = error.response?.data;

if (response?.error === 'INVALID_PARAMS') {
console.error('Invalid verification level configuration');
} else if (response?.error === 'APPLICANT_NOT_FOUND') {
console.error('User not found in Sumsub system');
} else if (response?.error === 'TOKEN_EXPIRED') {
console.error('Previous token expired, generating new one');
}
}

Best Practices

1. Token Management

// Cache tokens with expiration tracking
class TokenManager {
constructor() {
this.tokens = new Map();
}

async getToken(userId, isKYB = false) {
const key = `${userId}-${isKYB ? 'kyb' : 'kyc'}`;
const cached = this.tokens.get(key);

if (cached && cached.expiresAt > Date.now()) {
return cached.token;
}

const ekyc = await brdzSDK.ekyc;
const result = isKYB ?
await ekyc.generateSumsubTokenKYB() :
await ekyc.generateSumsubToken();

// Cache with 9-minute expiration (1 minute before actual expiry)
this.tokens.set(key, {
token: result.token,
expiresAt: Date.now() + (9 * 60 * 1000)
});

return result.token;
}
}

2. Status Polling

// Poll for status updates after verification
async function pollVerificationStatus(userId, maxAttempts = 30) {
const ekyc = await brdzSDK.ekyc;
let attempts = 0;

return new Promise((resolve, reject) => {
const poll = async () => {
try {
attempts++;
const status = await ekyc.getEkycStatus(userId);
const ekycStatus = status.data.ekyc_status;

if (ekycStatus === 'APPROVED' || ekycStatus === 'REJECTED') {
resolve(ekycStatus);
} else if (attempts >= maxAttempts) {
reject(new Error('Polling timeout'));
} else {
setTimeout(poll, 10000); // Poll every 10 seconds
}
} catch (error) {
reject(error);
}
};

poll();
});
}

3. Environment Configuration

// Environment-specific configuration
const config = {
development: {
baseUrl: 'https://api-dev.brdz.link/api',
sumsubEnv: 'test'
},
production: {
baseUrl: 'https://api.brdz.link/api',
sumsubEnv: 'production'
}
};

const currentConfig = config[process.env.NODE_ENV] || config.development;

const sdkConfig = await brdzSDK.config;
sdkConfig.setBaseUrl(currentConfig.baseUrl);

Verification Levels

Individual (eKYC): brdz-ekyc-indonesia-standard

  • Purpose: Personal identity verification
  • Documents: ID card, passport, driver's license
  • Process: Selfie + document verification
  • Use Case: Individual users, personal accounts

Business (eKYB): brdz-kyb-level

  • Purpose: Company/business verification
  • Documents: Business registration, tax documents, director identification
  • Process: Enhanced due diligence for businesses
  • Use Case: Corporate clients, business accounts

Integration Notes

  • Webhook Integration: Sumsub automatically sends verification results via webhooks
  • Database Sync: Status updates trigger automatic database synchronization
  • Wallet Creation: Approved verifications automatically create user wallets
  • Client Updates: Business verifications update client status in system
  • Audit Trail: All verification activities are logged for compliance

Security Considerations

  • Token Expiration: All tokens expire in 10 minutes for security
  • API Key Protection: Never expose API keys in client-side code
  • JWT Authentication: Most endpoints require valid JWT tokens
  • Webhook Validation: Webhook signatures are validated with HMAC-SHA256
  • Data Encryption: All verification data is encrypted in transit and at rest