Skip to content

Tích hợp Web SDK ​

Thiết lập, khởi tạo và scan cho eKYC Web SDK. Thực thi bundle.js sẽ tạo object toàn cục window.ekyc.

Điều kiện tiên quyết ​

Thông tinMô tả
Thư mục assetsMột nơi để serve thư mục assets /ekyc.
HTTPSBắt buộc để truy cập camera.
Quyền WebViewTrên WebView của iOS, bật chế độ phát media inline — allowsInlineMediaPlayback trong cả Flutter và React Native.
jsQRBắt buộc cho chức năng mã QR. Tải nó trước bundle của SDK.

Thiết lập HTML ​

Phần tử container với id cake-ekyc-sdk-container là bắt buộc và phải tồn tại trước khi khởi tạo.

html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>eKYC Integration</title>
    <style>
      #cake-ekyc-sdk-container {
        width: 100%;
        height: 100vh;
        position: relative;
      }
    </style>
  </head>
  <body>
    <!-- Bắt buộc: phần tử container của SDK với ID cụ thể -->
    <div class="overlay" id="cake-ekyc-sdk-container"></div>

    <!-- Bắt buộc: bundle eKYC SDK -->
    <script src="/ekyc/bundle.js"></script>

    <script>
      // Code khởi tạo SDK đặt tại đây
    </script>
  </body>
</html>

Khởi tạo ​

typescript
type SDKConfigParams = {
  resourcePath?: string             // Tùy chọn: đường dẫn đến tài nguyên SDK
  baseUrl: string                   // Bắt buộc: Base URL cho các request API
  token: string                     // Bắt buộc: Authentication token
  headers?: Record<string, string>  // Tùy chọn: Header HTTP bổ sung
}

Tham số:

Tham sốKiểuBắt buộcMặc địnhMô tả
baseUrlstringCó—Base URL cho các request API.
tokenstringCó—Authentication token.
resourcePathstringKhông—Đường dẫn đến tài nguyên SDK.
headersRecord<string, string>Không—Header HTTP bổ sung.
javascript
const sdk = await window.ekyc.initialize('cake-ekyc-sdk-container', {
  baseUrl: '<BASE_URL>',
  token: '<SDK_TOKEN>',
  resourcePath: '/path/to/resources',
  headers: {
    'Custom-Header': 'value'
  }
})

Kèm xử lý lỗi ​

javascript
async function initializeSDK() {
  try {
    const container = document.getElementById('cake-ekyc-sdk-container');
    if (!container) {
      throw new Error('SDK container element not found');
    }

    if (!window.ekyc) {
      throw new Error('eKYC SDK not loaded. Ensure bundle.js is included.');
    }

    const sdk = await window.ekyc.initialize('cake-ekyc-sdk-container', {
      baseUrl: '<BASE_URL>',
      token: await fetch('/your-backend/ekyc-token').then((r) => r.text()), // lấy lúc chạy, không đóng gói vào bundle
      resourcePath: '/ekyc/resources',
      headers: {
        'X-Client-Version': '1.0.0',
        'X-Platform': 'web',
        'X-User-Agent': navigator.userAgent
      }
    });

    return sdk;
  } catch (error) {
    console.error('SDK initialization failed:', error);
    throw error;
  }
}

WARNING

Lấy token từ backend của bạn tại thời điểm chạy — không bao giờ hardcode nó trong trang hay commit vào source. Token này ủy quyền cho các lệnh gọi trên tenant của bạn.

Scan ​

typescript
scanStart(
  types: ('face' | 'front' | 'back' | 'qrcode')[],
  opts?: ScanOptions
): Promise<{
  nid?: { front?: NIDScanResult, back?: NIDScanResult }
  face?: FaceScanResult
  qrcode?: QRCodeScanResult
}>

Tham số:

Tham sốKiểuBắt buộcMặc địnhMô tả
typesstring[]Có—Những lượt scan cần chạy: face, front, back, qrcode. Thứ tự được tôn trọng.
optsScanOptionsKhông—Tùy chọn, chủ yếu cho xác thực khuôn mặt.

ScanOptions ​

Tham sốKiểuBắt buộcMặc địnhMô tả
frontImageIdstringKhông—Image ID từ lượt scan mặt trước, dùng khi scan mặt sau.
faceauthClientIdstringKhông—Client ID cho xác thực khuôn mặt.
faceauthRefIdstringKhông—Reference ID cho xác thực khuôn mặt.
isNTBbooleanKhông—Cờ khách hàng New-to-Bank.
currentZoomnumberKhông—Mức zoom hiện tại.
timeoutDurationnumberKhông—Thời gian timeout tính bằng mili-giây.
javascript
// Scan mặt trước và mặt sau của thẻ NID
const result1 = await window.ekyc.scanStart(['front', 'back'])

// Scan khuôn mặt cho khách hàng NTB
const result2 = await window.ekyc.scanStart(['face'], {
  isNTB: true,
  faceauthClientId: 'client-123',
  faceauthRefId: 'ref-456'
})

// Scan mã QR
const result3 = await window.ekyc.scanStart(['qrcode'])

// Scan kết hợp
const result4 = await window.ekyc.scanStart(['front', 'back', 'face', 'qrcode'], {
  isNTB: false,
  faceauthClientId: 'client-123',
  faceauthRefId: 'ref-456'
})

Chỉ những loại scan được yêu cầu mới xuất hiện trong response; mọi thứ khác là undefined.

Trạng thái scan ​

typescript
interface Status {
  frontCompleted: boolean
  backCompleted: boolean
  faceCompleted: boolean
  qrcodeCompleted: boolean
  timestamp?: string

  frontData?: any
  backData?: any
  faceData?: any
  qrcodeData?: any
}
javascript
const status = window.ekyc.getScanStatus()
console.log('Front scan completed:', status.frontCompleted)

Cấu trúc response ​

NIDScanResult ​

TrườngKiểuMô tả
frontSideImageobjectẢnh mặt trước: id, label, bitmap, response.
backSideImageobjectẢnh mặt sau, cùng cấu trúc.
sanityResultobjectVerdict sanity của thẻ, điểm số và bounding box thẻ được phát hiện.
cardInfoobjectTrích xuất OCR, MRZ và QR cùng điểm độ tin cậy.

sanityResult.data.card_sanity mang theo verdict, score và info. cardInfo.data.card_information là một mảng CardInformation.

CardInformation ​

TrườngKiểuMô tả
fieldstringTên trường.
valuestringGiá trị đã trích xuất.
confidence_scorenumberĐộ tin cậy tổng thể.
confidence_verdictstringKết luận dạng văn bản.
digit_confidence_scoresnumber[]Độ tin cậy theo từng ký tự.

FaceScanResult ​

TrườngKiểuMô tả
facesFaceData[]Các khuôn mặt đã chụp, mỗi khuôn mặt có image và gesture (left, right, portrait).
sanityResultSanityResult[]Verdict sanity của ảnh chân dung và điểm số cho từng ảnh.
livenessResultLivenessResultis_live, score, kết quả theo từng ảnh và main_image_id.

QRCodeScanResult ​

TrườngKiểuMô tả
rawstringDữ liệu QR thô.
imageobjectẢnh đã xử lý: id, label, bitmap, response.

Chuyển đổi bitmap ​

bitmap là một object ImageData đi kèm hai hàm hỗ trợ:

javascript
const blob   = await bitmap.toBlob('image/jpeg')
const base64 = bitmap.toBase64('image/jpeg')

Xử lý lỗi ​

Response scan giữ nguyên cấu trúc khi thất bại và đặt chi tiết trong mảng error. Response cũng có thể mang theo sdkError:

typescript
sdkError?: { code: string; message: string } | {}
// {}             -> không có lỗi phía SDK
// {code,message} -> SDK phát hiện một lỗi bạn cần xử lý

sdkError xuất hiện trên ImageResponse, SanityResult và LivenessResult của khuôn mặt, sanityResult và cardInfo của NID, và image.response của QR.

WARNING

Một response trông có vẻ thành công vẫn có thể chứa cảnh báo trong mảng error, và một sdkError có giá trị nghĩa là chính SDK đã từ chối kết quả. Hãy kiểm tra cả hai — đừng coi một promise được resolve là đã đạt.

Mã lỗi của SDK ​

TrườngKiểuMô tả
60000NID_SANITY_FAILEDKiểm tra sanity của NID thất bại.
60001NID_TAMPERING_FAILEDPhát hiện giả mạo của NID thất bại.
60002FACE_SANITY_FAILEDKiểm tra sanity khuôn mặt thất bại.
60003FACE_LIVENESS_FAILEDKiểm tra liveness khuôn mặt thất bại.

Mã lỗi mã QR ​

TrườngKiểuMô tả
DOP-675_001Scan timeout"Hết thời gian quét mã. Vui lòng thử lại."
DOP-675_002Scan error"Không thể quét được mã QR, vui lòng thử lại!"

Các mã lỗi động cũng đến từ API trong mảng error — xem Mã lỗi.

Các vấn đề thường gặp ​

Thông tinMô tả
SDK không tải đượcKiểm tra đường dẫn script và đảm bảo nó tải trước khi sử dụng.
Truy cập cameraĐảm bảo dùng HTTPS và quyền camera đã được cấp.
Không tìm thấy containerXác nhận phần tử container tồn tại trong DOM.
Vấn đề mạngKiểm tra kết nối internet và các endpoint API.
typescript
if (typeof window.ekyc === 'undefined') {
    console.error('eKYC SDK not loaded');
}

navigator.mediaDevices.getUserMedia({ video: true })
    .then(stream => {
        console.log('Camera access granted');
        stream.getTracks().forEach(track => track.stop());
    })
    .catch(error => {
        console.error('Camera access denied:', error);
    });

Thực hành tốt nhất ​

  • Khởi tạo một lần và tái sử dụng instance.
  • Dùng getScanStatus() để theo dõi tiến trình.
  • Với thẻ NID, scan mặt trước trước, sau đó scan mặt sau bằng frontImageId.
  • Bọc mọi lượt scan trong try/catch.
  • Gọi terminate() khi xong để giải phóng camera và dọn dẹp.

Bước tiếp theo ​

Developers