Tổng quan eKYC
eKYC là nền tảng xác minh danh tính được CAKE lưu trữ (hosted): một tập hợp API HTTP không lưu trạng thái (stateless), tải một ảnh lên một lần, sau đó chạy các kiểm tra thẻ ID (ID card) (phát hiện, sanity, OCR, giả mạo) và kiểm tra khuôn mặt (sanity, liveness, so sánh, lập chỉ mục và tìm kiếm) trên ảnh đó. Trang này trình bày xác thực, hợp đồng request/response dùng chung, và luồng xác minh đầu-cuối.
INFO
Mọi ví dụ trong tài liệu này dùng cùng một danh tính giả định — Nguyễn Văn A, CCCD 001xxxxxxxxx, user_id user_00000001, ref_id ref_00000001. Thông tin xác thực, token và key được ghi dạng <PLACEHOLDER>. Đây không phải dữ liệu thật; hãy thay toàn bộ bằng giá trị của bạn.
Điều kiện tiên quyết
Trước khi gọi bất kỳ endpoint nào, bạn cần một tenant được CAKE cấp phát cùng bộ thông tin xác thực đi kèm.
| Thông tin | Mô tả |
|---|---|
| Access ID | Một UUID định danh duy nhất cho Tenant của bạn. Được gửi trong header Authorization. Do CAKE cung cấp. |
| Access Key | Secret key dùng để ký mọi request và xác minh signature của mọi response. Do CAKE cung cấp. |
| Base URL | Do CAKE cấp cùng bộ credentials, cho cả môi trường stage và production. |
| Cấu hình tenant | Ngưỡng, collection và các kiểm tra được bật là do CAKE cấu hình riêng cho từng tenant trước khi go-live. |
| Client ID | Giá trị X-Client-ID được cấp cùng bộ thông tin xác thực, gửi trên các request đi qua gateway. |
Liên hệ CAKE Support để nhận access_id và access_key.
Các ví dụ trong tài liệu này ghi base URL dưới dạng <BASE_URL> — hãy thay bằng giá trị CAKE cấp cho bạn.
WARNING
Access Key là một bí mật phía server. Không bao giờ nhúng nó vào ứng dụng di động, một bundle trình duyệt, hay bất kỳ client nào do người dùng cuối kiểm soát — chỉ ký request từ backend của bạn. Client di động xác thực bằng một JWT token ngắn hạn thay thế (xem bên dưới).
Khái niệm cốt lõi
Vòng đời giao dịch
Mỗi phiên eKYC diễn ra bên trong một giao dịch (transaction), đi qua ba trạng thái.
| Trường | Kiểu | Mô tả |
|---|---|---|
NOT_VERIFIED | string | Giao dịch đã được tạo và token đã được cấp, nhưng việc xác minh chưa hoàn tất. |
VERIFIED | string | Authentication key đã được redeem thành công. |
EXPIRED | string | Giao dịch không được hoàn tất trước khi token hết hạn. |
| Thông tin | Mô tả |
|---|---|
| Tạo giao dịch | Backend của bạn mở một giao dịch và nhận JWT mà SDK sẽ dùng. |
| Lấy giao dịch | Đọc trạng thái hiện tại bất kỳ lúc nào. |
| Xác minh khóa giao dịch | Redeem authentication key và đóng giao dịch. |
Giao dịch là tùy chọn với một lần kiểm tra ảnh đơn lẻ, nhưng bắt buộc khi bạn cần một kết quả có thể xác minh và kiểm toán mà backend của bạn tin cậy được.
Xác thực
eKYC hỗ trợ hai phương thức xác thực, được chọn theo bên gọi.
Phương án 1: Xác thực HMAC (backend đến eKYC backend)
Các request server-to-server được xác thực bằng HMAC-SHA256, chứng minh cả tính toàn vẹn lẫn tính xác thực của nội dung request bằng một khóa dùng chung (shared secret) giữa backend của bạn và CAKE.
Hai header là bắt buộc trên mọi request:
| Header | Mô tả |
|---|---|
X-TV-Timestamp | Timestamp hiện tại theo định dạng RFC3339. Ví dụ: 2019-04-21T18:00:15+07:00 |
Authorization | ATV <ACCESS_ID>:<SIGNATURE> |
Signature là một HMAC-SHA256 mã hóa Base64 của một StringToSign chuẩn hóa:
StringToSign = HttpMethod + "\n" + UrlPath + "\n" + Timestamp + "\n" + HashedBody
# HttpMethod: POST, GET, PUT, PATCH hoặc DELETE
# UrlPath: đường dẫn route tương đối, không gồm domain. Ví dụ: /v1/images
# Timestamp: thời điểm request theo định dạng RFC3339; phải khớp với header X-TV-Timestamp
# HashedBody: hex_encode(SHA256(raw body))
# Ví dụ (body `{}`): 44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a
Signature = Base64(HmacSha256(AccessKeySecret, Utf8EncodingOf(StringToSign)))Cách triển khai tham chiếu bằng JavaScript:
const CryptoJS = require("crypto-js");
const timestamp = new Date().toISOString(); // 2024-05-09T07:53:10.591Z
const access_key = "<ACCESS_KEY>";
const path = "/v1/create_ekyc_transaction";
const body = `{
"user_id": "user_00000001",
"ref_id": "ref_00000001"
}`;
function tokenize(method, path, timestamp, body, key) {
const hashed_body = CryptoJS.SHA256(body).toString(CryptoJS.enc.Hex);
const formatted = `${method}\n${path}\n${timestamp}\n${hashed_body}`;
const hmac = CryptoJS.HmacSHA256(formatted, key);
const hashed = hmac.toString(CryptoJS.enc.Hex);
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(hashed));
}
const authorize_token = tokenize("POST", path, timestamp, body, access_key);
// Gửi `timestamp` làm X-TV-Timestamp và `authorize_token` làm signature — không bao giờ ghi log.Ví dụ request đã ký:
curl --location '<BASE_URL>/v1/create_ekyc_transaction' \
--header 'Authorization: ATV <ACCESS_ID>:<SIGNATURE>' \
--header 'X-TV-Timestamp: <TIMESTAMP>' \
--header 'Content-Type: application/json' \
--header 'X-Request-Id: <RANDOM_UUID>' \
--header 'X-Client-ID: <CLIENT_ID>' \
--data '{
"user_id": "user_00000001",
"ref_id": "ref_00000001"
}'INFO
StringToSign dùng SHA256 của raw body mã hóa dạng hex. Một số tenant của CAKE được cấp phát dùng hash body mã hóa Base64 thay thế — hãy xác nhận với đội CAKE tenant của bạn đang dùng biến thể nào trước khi triển khai.
Phương án 2: JWT token (mobile SDK đến eKYC backend)
Một JWT token được cấp trong bước eKYC cho một user và ref_id cụ thể, và Mobile SDK trình nó khi gọi trực tiếp eKYC Server. Token ngừng hoạt động khi hết hạn.
Xem token là chuỗi mờ (opaque): chuyển nguyên trạng cho SDK, không parse, không ghi log, không lưu trữ.
Ký response
Mọi response từ eKYC Server đều được ký bằng HMAC-SHA256 trên method, path, timestamp và hash của response body, để backend của bạn có thể chứng minh payload thực sự đến từ CAKE.
| Header | Mô tả |
|---|---|
X-Signature-Timestamp | Timestamp đã ký theo định dạng RFC3339. Ví dụ: 2019-04-21T18:00:15+07:00 |
X-Signature | Token HMAC mã hóa Base64 từ server CAKE. Ví dụ: <SIGNATURE> |
StringToSign = HttpMethod + "\n" + UrlPath + "\n" + Timestamp + "\n" + HashedBody
# HttpMethod: method của API đã được gọi
# UrlPath: đường dẫn route tương đối, không gồm domain. Ví dụ: /v1/images
# Timestamp: thời điểm ký theo định dạng RFC3339, được gửi trong X-Signature-Timestamp
# HashedBody: hex_encode(SHA256(raw response body))
Signature = Base64(HmacSha256(AccessKeySecret, Utf8EncodingOf(StringToSign)))WARNING
Hãy tính lại và so sánh X-Signature trước khi tin tưởng một kết luận (verdict). Một response chưa được xác minh là một response chưa được xác thực, và các kết luận của eKYC là căn cứ cho các quyết định onboarding.
Cách hoạt động
Một phiên eKYC đầy đủ trải qua bốn actor: ứng dụng di động, backend của bạn, eKYC Backend, và các AI engine phía sau nó. Sơ đồ dưới đây thể hiện luồng thành công (happy path) chuẩn.
sequenceDiagram
autonumber
participant App as Mobile App / SDK
participant BE as Backend của bạn
participant EKYC as eKYC Backend
participant AI as AI Engines
Note over App,EKYC: Giai đoạn 1 — Chụp & tải lên
App->>BE: Ảnh thẻ ID và ảnh chân dung đã chụp
BE->>EKYC: POST /v1/images (multipart, ký HMAC)
EKYC-->>BE: image_id
Note over BE,AI: Giai đoạn 2 — Xác minh thẻ ID
BE->>EKYC: POST /v1/verify_id_card_sanity_sync
EKYC->>AI: Model sanity
AI-->>EKYC: kết luận + score
EKYC-->>BE: kết luận card_sanity
BE->>EKYC: POST /v1/read_id_card_info_sync
EKYC-->>BE: card_information (OCR / MRZ / QR / NFC)
BE->>EKYC: POST /v1/detect_id_card_tampering_sync
EKYC-->>BE: kết luận card_tampering + chi tiết
Note over BE,AI: Giai đoạn 3 — Xác minh khuôn mặt
BE->>EKYC: POST /v1/verify_portrait_sanity_sync
EKYC-->>BE: kết luận portrait_sanity
BE->>EKYC: POST /v1/verify_face_liveness_sync
EKYC-->>BE: is_live + score
BE->>EKYC: POST /v1/compare_faces_sync (chân dung so với ảnh thẻ)
EKYC-->>BE: matched / unmatched / unsure + score
Note over BE,EKYC: Giai đoạn 4 — Khử trùng lặp & quyết định
BE->>EKYC: POST /v1/search_faces_sync (kiểm tra trùng lặp)
EKYC-->>BE: các khuôn mặt tương đồng + score
BE->>EKYC: POST /v1/index_faces_sync (đăng ký người dùng đã duyệt)
EKYC-->>BE: status success
BE-->>App: Quyết định onboarding
Giai đoạn 1 — Chụp và tải lên
- Ứng dụng di động hoặc Mobile SDK chụp mặt trước thẻ ID, mặt sau thẻ ID và một ảnh chân dung selfie, rồi chuyển chúng cho backend của bạn.
- Backend của bạn gọi
POST /v1/imagesmột lần cho mỗi ảnh vớilabelchính xác. Mỗi lệnh gọi trả về mộtimage_id. - Backend của bạn giữ lại các giá trị
image_idcho phần còn lại của phiên — mọi API downstream đều nhận mộtimage_idthay vì tải lại dữ liệu ảnh.
Giai đoạn 2 — Xác minh thẻ ID
POST /v1/verify_id_card_sanity_synckiểm tra ảnh thẻ có dùng được không: đủ sắc nét, đầy đủ, không phải bản photocopy, không bị chói lóa trên các trường dữ liệu. Hãy chạy bước này trước tiên — một ảnh xấu sẽ làm sai lệch mọi kiểm tra sau nó.POST /v1/read_id_card_info_synctrích xuất các trường của thẻ qua OCR, MRZ, QR và (khi có) NFC, mỗi trường kèm một độ tin cậy.POST /v1/detect_id_card_tampering_synctìm dấu hiệu giả mạo: ảnh chân dung bị chỉnh sửa, font chữ bất thường, sự không khớp giữa các nguồn MRZ, QR và OCR, và logic số ID hoặc ngày hết hạn không hợp lệ.
Giai đoạn 3 — Xác minh khuôn mặt
POST /v1/verify_portrait_sanity_synckiểm tra ảnh selfie có dùng được không: một khuôn mặt, được lấy khung tốt, mắt mở, không bị che khuất.POST /v1/verify_face_liveness_syncxác nhận có một người thật trước camera thay vì một tấm ảnh hoặc một lần phát lại màn hình (screen replay).POST /v1/compare_faces_syncso khớp ảnh selfie với khuôn mặt in trên thẻ ID, trả vềmatched,unmatchedhoặcunsurecùng một điểm tương đồng (similarity score).
Giai đoạn 4 — Khử trùng lặp và quyết định
POST /v1/search_faces_synctìm kiếm trong collection khuôn mặt của bạn xem có ai đã được đăng ký với cùng khuôn mặt hay không — kiểm tra trùng tài khoản và blocklist tiêu chuẩn.POST /v1/index_faces_syncthêm khuôn mặt của người dùng đã được duyệt vào collection để các phiên sau có thể tìm thấy họ.- Backend của bạn kết hợp mọi kết luận thành một quyết định onboarding duy nhất và trả về cho ứng dụng. eKYC trả về bằng chứng; chính sách chấp nhận/từ chối vẫn là của bạn.
Cấu trúc response dùng chung
Mọi endpoint JSON đều trả về cùng một cấu trúc bên ngoài.
{
"data": {
"request_id": "f77bf948-fce3-48f3-b61c-396e4cd9a89b",
"status": "success"
},
"errors": [],
"success": true,
"code": 0,
"message": "Success"
}| Trường | Kiểu | Mô tả |
|---|---|---|
data | object | Payload riêng của từng endpoint. Rỗng khi request thất bại trước khi được xử lý. |
data.status | string | success hoặc failure — request có được xử lý thành công hay không. |
data.request_id | string | Request ID do server tạo. Cung cấp cho CAKE Support khi cần kiểm tra log. |
errors | array | Chi tiết từng lỗi. Rỗng khi thành công. |
errors[].code | string | Mã lỗi dạng máy đọc được, ví dụ image_not_found_exception. |
errors[].message | string | Mô tả dạng người đọc được về lỗi. |
errors[].detail | object | Ngữ cảnh tùy chọn, ví dụ field nêu tên tham số không hợp lệ. |
success | bool | Bản thân cuộc gọi có thành công hay không. |
code | int | status code dạng số — 0 khi thành công. |
message | string | Thông báo trạng thái. |
Một HTTP 200 không có nghĩa là kiểm tra đã thành công. Hãy đọc success, rồi data.status, rồi đến kết luận.
Mã số thường gặp
| Mã | Thông báo |
|---|---|
0 | Success |
2001002 | Xảy ra lỗi không mong đợi trong quá trình xử lý request bên ngoài. |
2001003 | Ảnh gửi lên server không có khuôn mặt nào. |
2001010 | Không tìm thấy Access ID. |
2001014 | Vượt giới hạn tốc độ đăng ký. |
2001015 | Vượt giới hạn brute-force khi đăng ký. |
2001026 | Các ảnh gửi lên server bị trùng lặp. |
401100 | Bạn không được phép thực hiện hành động này. |
4001000 | Tham số đầu vào vi phạm một ràng buộc. |
4001001 | Header X-TV-Timestamp đã hết hạn, cần một cái mới hơn. |
4041000 | Không tìm thấy image ID trong DB. |
4041001 | Không tìm thấy người dùng. |
4091000 | cus_user_id đã được đăng ký. |
4131000 | Kích thước ảnh đầu vào vượt quá giới hạn cho phép (15MB). |
4151000 | Định dạng ảnh được cung cấp không được hỗ trợ (JPG/PNG). |
4291000 | Số lượng request vượt quá giới hạn throughput của bạn. |
5001000 | Xảy ra lỗi không mong đợi trong quá trình xử lý request. |
Mã lỗi thường gặp
| Mã | Mô tả |
|---|---|
access_id_not_found | Không tìm thấy Access ID. |
access_denied_exception | Bạn không được phép thực hiện hành động này. |
invalid_parameter_exception | Tham số đầu vào vi phạm một ràng buộc. |
request_time_too_skewed | Header X-TV-Timestamp đã hết hạn, cần một cái mới hơn. |
image_not_found_exception | Không tìm thấy image ID trong DB. |
image_too_large_exception | Kích thước ảnh đầu vào vượt quá giới hạn cho phép (15MB). |
invalid_image_format_exception | Định dạng ảnh được cung cấp không được hỗ trợ (JPG/PNG). |
duplicated_image | Các ảnh gửi lên server bị trùng lặp. |
image_has_no_faces | Ảnh gửi lên server không có khuôn mặt nào. |
request_not_found_exception | Không tìm thấy request ID khi poll kết quả theo id. |
request_timeout_exception | Request mất quá nhiều thời gian để xử lý. |
rate_limit_exception | Số lượng request vượt quá giới hạn throughput của bạn. |
internal_server_error | Xảy ra lỗi không mong đợi trong quá trình xử lý request. |
Bước tiếp theo
- Bắt đầu nhanh — chạy phiên đầu tiên của bạn trong khoảng 10 phút với cURL
- Chọn phương thức tích hợp — API, Mobile SDK hay Web SDK
- Tạo giao dịch — mở một giao dịch eKYC và cấp token cho SDK
- Khuyến nghị sử dụng — đối chiếu request, nhãn ảnh và loại thẻ bạn cần làm đúng trước mọi thứ khác
- Tải ảnh lên — lệnh gọi đầu tiên bắt buộc, biến dữ liệu ảnh thành một
image_id - Tải ảnh xuống — lấy lại một ảnh đã tải lên trước đó
- Phát hiện thẻ ID — định vị và phân loại thẻ bên trong một ảnh
- Xác minh sanity thẻ ID — cổng chất lượng trước khi xử lý bất kỳ thẻ ID nào
- Đọc thông tin thẻ ID — trích xuất trường bằng OCR, MRZ, QR và NFC
- Phát hiện giả mạo thẻ ID — phát hiện giả mạo và chỉnh sửa
- Phát hiện khuôn mặt — phát hiện khuôn mặt và vector embedding
- Xác minh sanity khuôn mặt — cổng chất lượng trước khi xử lý bất kỳ khuôn mặt nào
- Xác minh liveness khuôn mặt — phát hiện tấn công giả mạo (presentation attack)
- So sánh khuôn mặt — so khớp 1:1 giữa hai ảnh
- Lập chỉ mục khuôn mặt — đăng ký một khuôn mặt vào một collection
- Tìm kiếm khuôn mặt — tìm kiếm 1:N cho các trường hợp trùng lặp và blocklist
- Xóa khuôn mặt — gỡ các khuôn mặt đã lập chỉ mục khỏi một collection
- Định nghĩa kết luận — ý nghĩa đầy đủ của mọi kết luận sanity, giả mạo và so khớp
- Phân tích thông tin QR — phân tích một chuỗi QR CCCD thô thành các trường có cấu trúc
- Lấy giao dịch — đọc trạng thái hiện tại của một giao dịch
- Xác minh khóa xác thực giao dịch — redeem key và đóng giao dịch
- Mã lỗi — bảng tham chiếu mã lỗi đầy đủ dạng số và dạng chuỗi