eKYC Module
The ekyc module handles Sumsub eKYC and eKYB integration.
Import
const ekyc = await brdzSDK.ekyc;
Methods Overview (7 methods)
| Method | Description | Auth Required | HTTP Endpoint |
|---|---|---|---|
getEkycStatus | Check eKYC status | ✅ | GET /ekyc/status/:user_id |
generateSumsubToken | Generate Sumsub token | ✅ | POST /ekyc/sumsub/token |
generateSumsubTokenKYB | Generate KYB token | ✅ | POST /ekyc/sumsub/token-kyb |
generateWebSdkLink | Generate Web SDK link | ✅ | POST /ekyc/sumsub/websdk/:user_id |
generateWebSdkLinkKYB | Generate KYB SDK link | ✅ | POST /ekyc/sumsub/websdk-kyb/:user_id |
syncSumsubStatus | Sync verification status | ❌ | POST /ekyc/sumsub/syncSumsubStatus |
changeVerificationLevel | Change verification level | ✅ | POST /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
generateWebSdkLink
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 dataapplicantId(string): Sumsub applicant IDuser_id(string): BRDZ user IDreviewStatus(string): Review status from SumsubreviewAnswer(string): Review answer from Sumsubverification_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 datauser_id(string): User ID to change levellevelName(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