Nhảy tới nội dung

Các API của luồng Định danh khách hàng

Định danh khách hàng (eKYC - Electronic Know Your Customer), sau đây gọi là luồng eKYC, là luồng xác minh danh tính khách hàng từ xa, hoàn toàn trên thiết bị của người dùng và không cần gặp trực tiếp. Luồng dùng để xác định người đang thực hiện giao dịch có đúng là chủ của giấy tờ tuỳ thân mà họ cung cấp hay không, thường áp dụng ở bước mở tài khoản hoặc đăng ký sử dụng dịch vụ lần đầu.

Luồng này khác với luồng Xác thực khuôn mặt: eKYC dùng cho lần định danh đầu tiên, có đọc giấy tờ để lấy thông tin và ảnh chân dung. Xác thực khuôn mặt dùng cho các lần sau, chỉ so khớp khuôn mặt với dữ liệu đã được xác thực và lưu sẵn.

Mỗi lần định danh, hệ thống FPT AI eKYC thực hiện các bước sau, theo thứ tự:

  • Đọc giấy tờ (OCR - Optical Character Recognition, nhận dạng ký tự quang học): chụp ảnh giấy tờ tuỳ thân (CCCD, CMND, hộ chiếu, giấy phép lái xe...) và tự động bóc tách thông tin như họ tên, ngày sinh, số giấy tờ.
  • Kiểm tra mã QR trên CCCD gắn chip: khi ảnh giấy tờ không đọc được mã QR, người dùng quét mã trực tiếp để đối chiếu với thông tin vừa bóc tách.
  • Đọc và xác thực chip NFC (Near Field Communication, công nghệ đọc chip không tiếp xúc): đọc dữ liệu trong chip của CCCD gắn chip, kiểm tra dữ liệu có toàn vẹn, không bị sao chép hay chỉnh sửa.
  • Kiểm tra thực thể sống (liveness): xác định khuôn mặt trong ảnh hoặc video là của người thật đang đứng trước camera, không phải ảnh in, ảnh hoặc video phát lại trên màn hình, mặt nạ hay khuôn mặt giả mạo bằng công nghệ.
  • So khớp khuôn mặt (face match): so khớp khuôn mặt vừa chụp với ảnh chân dung trên giấy tờ, trả về kết quả khớp hoặc không khớp cùng độ tương đồng (similarity).

Tuỳ nhu cầu, khách hàng có thể bỏ bớt một số bước (ví dụ chỉ đọc giấy tờ, hoặc chỉ kiểm tra khuôn mặt). Các biến thể này được mô tả ở mục Các biến thể luồng.

Một số tình huống sử dụng điển hình

  • Mở tài khoản ngân hàng, ví điện tử hoặc tài khoản chứng khoán hoàn toàn trực tuyến.
  • Đăng ký dịch vụ tài chính, bảo hiểm hoặc vay tiêu dùng mà vẫn đáp ứng yêu cầu định danh khách hàng.
  • Đăng ký tài khoản hoặc dịch vụ của các doanh nghiệp cần xác minh người dùng là người thật và đúng chủ giấy tờ, ví dụ đại lý, cộng tác viên, đối tác.

Điều kiện áp dụng

  • Khách hàng đã có api-key do FPT cấp và đã cấu hình luồng trên portal. Cấu hình này quyết định các bước nào sẽ chạy trong mỗi phiên (xem mục Cấu hình phiên).
  • Bước đọc chip NFC chỉ áp dụng khi thiết bị của người dùng hỗ trợ NFC và giấy tờ là CCCD gắn chip.
  • Ứng dụng phía khách hàng phải gọi các API đúng thứ tự và dùng chung một mã phiên trong suốt luồng.

Mỗi lần định danh là một phiên eKYC do backend cấp qua API khởi tạo phiên. Mọi API sau đó gửi kèm mã phiên trong header. Tài liệu này dành cho khách hàng tích hợp trực tiếp qua API và mô tả cấu hình không mã hoá payload: request và response ở dạng thường (JSON, form-data), được bảo vệ bằng HTTPS. Với mỗi API, tài liệu nêu thứ tự gọi, header và nội dung (payload).

  1. Tổng quan: luồng chuẩn, các biến thể luồng, base URL, header chung, danh sách API và cấu hình phiên.

  2. Chi tiết từng API:

  3. Xử lý kết quả và mã lỗi: cách đọc kết quả, mã HTTP và mã liveness thường gặp.

  4. Phụ lục A. Checklist tích hợp: các lỗi hay gặp khi tích hợp.

Tổng quan​

Luồng chuẩn​

Luồng mặc định: giấy tờ → (QR) → (NFC) → khuôn mặt.

Sơ đồ tuần tự gọi các API trong luồng Định danh khách hàng

Các bước

  • Gọi API 1. Lưu lại session-id và sdk_config trong response.
  • Chụp ảnh giấy tờ, gửi API 2. errorCode = "0" là thành công.
  • Nếu giấy tờ là CCCD gắn chip (trường Type trong kết quả OCR bằng 8 hoặc 9), OCR không đọc được QR (trường QRcode trống hoặc N/A) và sdk_config.scan_qr_mode = 1: cho người dùng quét mã QR trên thẻ, gửi API 3.
  • Nếu sdk_config.ekyc_flow khác 1, thiết bị có NFC và giấy tờ là CCCD gắn chip: đọc chip, gửi API 4.
  • Chụp ảnh hoặc quay video khuôn mặt theo sdk_config.liveness_type, gửi API 5. code = "200" là đạt.

Các biến thể luồng​

Biến thểKhi nào dùngChuỗi APIGhi chú
Đầy đủMặc định1 → 2 → (3) → (4) → 5Bước 3, 4 theo điều kiện ở mục Luồng chuẩn
Chỉ giấy tờChỉ cần bóc tách giấy tờ1 → 2 → (3)Gửi header only-engine: true ở API 1 và API 2
Chia hai lầnGiấy tờ và khuôn mặt làm ở hai thời điểm khác nhauLần 1: 1 → 2. Lần 2: 5Lần 2 dùng lại session-id của lần 1, không gọi lại API 1
Chỉ NFC hoặc NFC kèm livenessĐã có số CCCD, ngày sinh, ngày hết hạn để mở chip1 → 4 → (5)Không có bước OCR
Chỉ livenessXác thực khuôn mặt, ekyc_flow = 61 → 6Gọi engine liveness trực tiếp

Thông tin chung​

Base URL​

Môi trườngbase_urlDùng cho
Productionhttps://api.fpt.ai/vision/ekyc-be/Mọi API, trừ API 6
Staginghttps://api.fpt.ai/vision/ekyc/be-stag/Mọi API, trừ API 6
Engine livenesshttps://api.fpt.ai/Chỉ API 6
  • Các đường dẫn trong tài liệu ghép trực tiếp sau base_url (không có dấu / ở đầu), ví dụ base_url + init_session.
  • Nếu đi qua proxy riêng của khách hàng, gọi mọi API, kể cả API 6, qua base URL của proxy.
  • Timeout khuyến nghị: 60 giây cho kết nối, đọc và ghi.

Header chung​

Các header dưới đây xuất hiện ở hầu hết API. Header nào không có giá trị thì bỏ hẳn, không gửi chuỗi rỗng.

HeaderKiểu dữ liệuMô tả
api-keyStringAPI key do FPT cấp. Bắt buộc ở mọi API
session-idStringMã phiên trả về từ API 1
device-typeStringLoại client: android, ios, web-sdk, api. Giữ nguyên một giá trị trong suốt phiên
sdk-versionStringPhiên bản client, ví dụ 3.7.3.5
langStringNgôn ngữ của thông báo và tên trường trong kết quả: vi, en
manual-timeStringThời gian người dùng thao tác ở bước hiện tại, tính bằng mili giây, ví dụ 8423
x-sdk-trace-idStringUUID sinh mới cho mỗi request, dùng để truy vết
x-sdk-trace-valuesStringToken xác thực thiết bị (Play Integrity trên Android), gửi ở mọi request. Chưa có token thì gửi -8
Header tuỳ biếnStringHeader riêng của khách hàng, ví dụ cho proxy hoặc API gateway. Gửi kèm mọi API

Header có dấu gạch dưới

API 1 dùng header client_uuid (gạch dưới). Nhiều proxy bỏ header có gạch dưới theo mặc định (nginx cần underscores_in_headers on;). Nếu đi qua proxy riêng, hãy kiểm tra header này tới được backend.

Danh sách API​

APIMethod và đường dẫnKiểu bodyYêu cầu
1. Khởi tạo phiênPOST init_sessionJSONCó
2. OCR giấy tờPOST ocrform-dataCó, trừ luồng không có OCR
3. Kiểm tra mã QRPOST qrcodeJSONTuỳ chọn
4. Kiểm tra dữ liệu chip NFCPOST check_chipJSONTuỳ chọn
5. Liveness và so khớp khuôn mặtPOST face/livenessform-dataCó
6. Liveness độc lậpPOST dmp/liveness/v3form-dataLuồng chỉ liveness
7. Ghi log và truy vếtPOST logging/tracingJSONTuỳ chọn, chỉ khi enable_tracing = true

Cấu hình phiên​

Response của API 1 trả về cấu hình phiên (trường sdk_config), được thiết lập trên portal theo từng api-key. Client dùng các trường dưới đây để quyết định luồng, tối thiểu cần đọc các trường được đánh dấu ★.

TrườngKiểu dữ liệuÝ nghĩa
ekyc_flow ★Int1: giấy tờ và khuôn mặt, không NFC. 6: chỉ liveness (API 6). Giá trị khác: có thêm bước NFC (khi thiết bị hỗ trợ NFC và giấy tờ là CCCD gắn chip)
liveness_type ★IntKiểu chụp khuôn mặt: 0 PHOTO, 1 VIDEO, 2 ACTIVE_VIDEO, 3 RANDOM, 4 MORE_PHOTO, 5 FLASH. Quyết định payload của API 5 (xem mục 5.3. Request Body)
scan_qr_mode ★Int1: bắt buộc quét QR khi OCR không đọc được QR trên CCCD gắn chip
is_skip_nfcBooleanCho phép người dùng bỏ qua bước NFC
nfc_retry_limitIntSố lần đọc chip thất bại tối đa
limitIntSố lần thử tối đa của phiên (không có trường này thì coi là 5)
is_show_ekyc_resultBooleanHiển thị màn hình kết quả cuối luồng
enable_tracingBooleanBật ghi log sự kiện phía client (xem API 7). Có thể bỏ qua
block_screenshotBooleanChặn chụp màn hình trong luồng
is_upload_imageBooleanCho phép chọn ảnh có sẵn thay vì chụp
show_guide, show_logo, show_label_step, show_action_step, show_switch_button, show_switch_animation, show_exit_dialog, show_nfc_position, font_path, languageNhiều kiểuCấu hình giao diện phía client. Có thể bỏ qua
document_capture_delay, threshold_yaw, count_stable, iou_threshold, enable_accessibility_serviceNhiều kiểuTham số chụp tự động và kiểm tra thiết bị phía client. Có thể dùng làm gợi ý

Trường on_device_model_config (cùng cấp với sdk_config) bật hoặc tắt các kiểm tra chất lượng ảnh trên thiết bị: blur, detection, brightness, face_quality, eye_closed. Client có thể dùng làm gợi ý.

1. API khởi tạo phiên​

Áp dụng cho: mọi luồng. Kiểu body: JSON.

Tạo phiên eKYC mới. Trả về mã phiên và cấu hình phiên.

1.1. Request URL​

POST base_url/init_session

1.2. Request Headers​

Tham sốYêu cầuKiểu dữ liệuMô tả
api-keyCóStringAPI key do FPT cấp
device-typeCóStringandroid, ios, web-sdk, api
Content-TypeCóStringapplication/json; charset=utf-8
client_uuidKhôngStringMã do hệ thống khách hàng sinh cho mỗi lần định danh, dùng để đối soát phiên, ví dụ một UUID
sdk-versionKhôngStringPhiên bản client
only-engineKhôngBooleantrue: luồng chỉ giấy tờ. Mặc định false
x-sdk-trace-valuesKhôngStringThường là -8 ở bước này vì token thiết bị chỉ lấy được sau khi có session-id

1.3. Request Body​

Thông tin thiết bị dạng JSON.

Tham sốYêu cầuKiểu dữ liệuMô tả
memoryKhôngStringDung lượng RAM của thiết bị (GB), ví dụ "5.62"
modelKhôngStringChuỗi ghép từ model, phiên bản hệ điều hành và hãng, phân tách bằng ký tự gạch đứng. Xem ví dụ trong mẫu request
nfc_supportKhôngBooleanThiết bị có NFC hay không
rootKhôngBooleanClient phát hiện thiết bị root hoặc jailbreak, hoặc công cụ can thiệp (Frida...)
emulatorKhôngBooleanClient phát hiện đang chạy trên máy ảo
debuggerKhôngBooleanClient phát hiện đang gắn debugger
accessibilityKhôngBooleanCó dịch vụ trợ năng (accessibility) đang bật

1.4. Mẫu request​

curl --location --request POST 'base_url/init_session' \
--header 'api-key: your-api-key' \
--header 'client_uuid: 3f1c2b9e-6a1d-4f0e-9d7a-2b8e5c4a1f90' \
--header 'device-type: android' \
--header 'sdk-version: 3.7.3.5' \
--header 'only-engine: false' \
--header 'x-sdk-trace-values: -8' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
"memory": "5.62",
"model": "SM-S918B|14|samsung",
"nfc_support": true,
"root": false,
"emulator": false,
"debugger": false,
"accessibility": false
}'

1.5. Response​

1.5.1. Mẫu response​

Thành công: http_code = 200

{
"code": "200",
"message": "success",
"session-id": "7760a743-884b-4195-b781-892e72c7b0b6",
"sdk_config": {
"ekyc_flow": 2,
"liveness_type": 4,
"scan_qr_mode": 1,
"is_skip_nfc": false,
"nfc_retry_limit": 3,
"limit": 5,
"is_show_ekyc_result": true,
"enable_tracing": true,
...
},
"on_device_model_config": {
"blur": true,
"detection": true,
"brightness": 0.3,
"face_quality": true,
"eye_closed": true
}
}

Thất bại: http_code != 200

1.5.2. Mô tả response​

Tham sốKiểu dữ liệuMô tả
codeString"200": thành công. Giá trị khác: hiển thị message và dừng luồng
messageStringThông báo trả về
actionStringCó giá trị exit khi phải dừng luồng (xem phần Xử lý kết quả và mã lỗi)
session-idStringMã phiên. Gửi trong header session-id của mọi API sau
sdk_configObjectCấu hình phiên, xem mục Cấu hình phiên
on_device_model_configObjectCấu hình kiểm tra chất lượng ảnh trên thiết bị

1.5.3. Mẫu response lỗi​

HTTPResponseNguyên nhân
200{"code": "<khác 200>", "message": "..."}Không tạo được phiên, hiển thị message
401{"code": "401", "message": "..."}api-key không hợp lệ
422{"detail": [...]}Thiếu header bắt buộc
500–Lỗi hệ thống

2. API OCR giấy tờ​

Áp dụng cho: luồng đầy đủ, luồng chỉ giấy tờ. Kiểu body: form-data.

Bóc tách thông tin trên giấy tờ tuỳ thân. Mặt trước và mặt sau gửi trong một request (cách A, mục 2.4) hoặc hai request riêng (cách B).

2.1. Request URL​

POST base_url/ocr

2.2. Request Headers​

Tham sốYêu cầuKiểu dữ liệuMô tả
api-keyCóStringAPI key do FPT cấp
session-idCóStringMã phiên từ API 1
device-typeCóStringCùng giá trị đã dùng ở API 1
document-typeCóStringLoại giấy tờ, xem bảng ở mục 2.3
countryKhôngStringQuốc gia phát hành giấy tờ. Mặc định vi
langKhôngStringvi, en
only-engineKhôngBooleanCùng giá trị đã dùng ở API 1
side-typeKhôngStringfront hoặc back, chỉ dùng khi gửi từng mặt riêng (mục 2.4, cách B). Ảnh mặt trước phải được gửi trước
sdk-versionKhôngStringPhiên bản client
manual-timeKhôngStringTổng thời gian chụp mặt trước và mặt sau (ms)
x-sdk-trace-id, x-sdk-trace-valuesKhôngStringXem mục Header chung

2.3. Request Body​

FormData, đúng thứ tự sau:

Thứ tựPartYêu cầuKiểuMô tả
1filesCóFileẢnh mặt trước, image/jpeg
2filesTheo giấy tờFileẢnh mặt sau

Giá trị của document-type và số ảnh tương ứng:

document-typeGiấy tờSố ảnh
idrCCCD / CMND2 (mặt trước, mặt sau)
dlrGiấy phép lái xe2 khi country = vi, 1 (mặt trước) với quốc gia khác
passportHộ chiếu1 (trang thông tin)
umidrUMID (Philippines)1
tinidrTIN ID (Philippines)1

Ảnh: JPEG, khuyến nghị thu nhỏ về tối đa 1080 × 1080.

2.4. Mẫu request​

Cách A (khuyến nghị): gửi hai mặt trong một request.

curl --location --request POST 'base_url/ocr' \
--header 'api-key: your-api-key' \
--header 'session-id: 7760a743-884b-4195-b781-892e72c7b0b6' \
--header 'device-type: android' \
--header 'document-type: idr' \
--header 'country: vi' \
--header 'lang: vi' \
--header 'only-engine: false' \
--header 'sdk-version: 3.7.3.5' \
--header 'manual-time: 8423' \
--header 'x-sdk-trace-id: 0b6e1f43-2a52-4c1b-9b0e-5f4d3c2a1b00' \
--header 'x-sdk-trace-values: <token>' \
--form 'files=@"front.jpg";type=image/jpeg' \
--form 'files=@"back.jpg";type=image/jpeg'

Cách B: gửi từng mặt, mỗi request một ảnh kèm header side-type, mặt trước gửi trước. Nếu document-type là passport thì mỗi request chỉ gửi 1 ảnh.

2.5. Response​

2.5.1. Mẫu response​

Thành công

{
"errorCode": "0",
"errorMessage": "",
"data": [
{ "key": "ID", "name": "Số/ No", "value": "0010xxxxxxxx", "score": "98.66", "locale": "vn" },
{ "key": "Name", "name": "Họ và tên", "value": "NGUYEN VAN A", "score": "99.71", "locale": "vn" },
{ "key": "Date of birth", "name": "Ngày sinh", "value": "01/01/1990", "score": "98.41", "locale": "vn" },
{ "key": "Type", "name": "Loại thẻ", "value": "8", "score": "", "locale": "vn" },
{ "key": "QRcode", "name": "QR code", "value": "0010xxxxxxxx|...", "score": "", "locale": "vn" },
...
]
}

2.5.2. Mô tả response​

Tham sốKiểu dữ liệuMô tả
errorCodeString"0" là thành công. Giá trị khác là lỗi, hiển thị errorMessage cho người dùng chụp lại. Chi tiết xem tài liệu mã lỗi
errorMessageStringThông báo lỗi theo ngôn ngữ của header lang
actionStringexit: dừng luồng, không cho chụp lại
dataArrayCác trường bóc tách, mỗi phần tử gồm key, name, value, score, locale. Danh sách trường phụ thuộc loại giấy tờ
total_dataArrayDanh sách trường mở rộng (nếu có), cùng cấu trúc data
list_tables, table_titleArray, StringDữ liệu dạng bảng (nếu có)

Các key dùng để điều hướng luồng (so khớp không phân biệt hoa thường):

keyDùng để
Type8 hoặc 9: CCCD gắn chip, có thể sang bước QR (API 3) hoặc NFC (API 4)
QRcodeTrống hoặc N/A: OCR không đọc được QR, quét QR nếu scan_qr_mode = 1
ID, Date of birth, Expired Date, MRZLấy khoá mở chip NFC (số CCCD, ngày sinh, ngày hết hạn)

2.5.3. Mẫu response lỗi​

Lỗi nghiệp vụ: HTTP 200, errorCode khác "0"

{
"errorCode": "3",
"errorMessage": "Không tìm thấy tài liệu đã chọn trong ảnh"
}

Phiên làm việc hết hạn: trả về khi phiên không hợp lệ, ví dụ phiên chưa được đăng ký, phiên hết thời gian chờ, không khớp loại thiết bị...

{
"errorCode": "403",
"errorMessage": "Phiên làm việc đã hết hạn"
}

Các trường hợp lỗi theo mã HTTP:

HTTPResponseNguyên nhân
403{"errorCode": "403", "errorMessage": "Your device is not secure..."}Thiết bị không an toàn theo token xác thực thiết bị
403{"errorCode": "403", ...}Phiên không tồn tại, hết hạn hoặc đã kết thúc
422{"detail": [...]}Thiếu part hoặc header bắt buộc

3. API kiểm tra mã QR​

Áp dụng cho: CCCD gắn chip. Kiểu body: JSON. Yêu cầu: tuỳ chọn.

Gửi chuỗi QR quét được trên CCCD gắn chip, dùng khi ảnh OCR không đọc được QR. Hệ thống so khớp dữ liệu QR với kết quả OCR ở bước trước.

3.1. Request URL​

POST base_url/qrcode

3.2. Request Headers​

Tham sốYêu cầuKiểu dữ liệuMô tả
api-keyCóStringAPI key do FPT cấp
session-idCóStringMã phiên từ API 1
device-typeCóStringCùng giá trị đã dùng ở API 1
Content-TypeCóStringapplication/json; charset=utf-8
langKhôngStringvi, en
sdk-version, manual-time, x-sdk-trace-id, x-sdk-trace-valuesKhôngStringXem mục Header chung

3.3. Request Body​

JSON.

Tham sốYêu cầuKiểu dữ liệuMô tả
qrcodeCóStringNguyên văn chuỗi đọc được từ mã QR trên CCCD

3.4. Mẫu request​

curl --location --request POST 'base_url/qrcode' \
--header 'api-key: your-api-key' \
--header 'session-id: 7760a743-884b-4195-b781-892e72c7b0b6' \
--header 'device-type: android' \
--header 'lang: vi' \
--header 'sdk-version: 3.7.3.5' \
--header 'manual-time: 3120' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
"qrcode": "0010xxxxxxxx|0123456789|NGUYEN VAN A|01011990|Nam|...|01012021"
}'

3.5. Response​

3.5.1. Mẫu response​

Thành công: http status = 200 và errorCode = 0

{
"errorCode": "0",
"errorMessage": ""
}

Thất bại

Lỗi dữ liệu QR không khớp:

{
"errorCode": "QR01",
"errorMessage": "Dữ liệu trong mã QR không khớp"
}

Phiên làm việc hết hạn: trả về khi phiên không hợp lệ, ví dụ phiên chưa được đăng ký, phiên hết thời gian chờ, không khớp loại thiết bị...

{
"errorCode": "403",
"errorMessage": "Phiên làm việc đã hết hạn"
}

3.5.2. Mô tả response​

Tham sốKiểu dữ liệuMô tả
errorCodeString"0" là hợp lệ. Giá trị khác là lỗi, chi tiết xem tài liệu mã lỗi
errorMessageStringThông báo lỗi (nếu có). Ngôn ngữ của thông báo được đặt bởi tham số lang trong headers
actionStringexit: dừng luồng

4. API kiểm tra dữ liệu chip NFC​

Áp dụng cho: luồng có NFC. Kiểu body: JSON. Yêu cầu: tuỳ chọn.

Gửi dữ liệu đọc từ chip CCCD (chuẩn ICAO 9303) để backend xác thực tính toàn vẹn (SOD), chống sao chép chip (Active Authentication, Chip Authentication) và trả dữ liệu trên chip.

4.1. Request URL​

POST base_url/check_chip

4.2. Request Headers​

Tham sốYêu cầuKiểu dữ liệuMô tả
api-keyCóStringAPI key do FPT cấp
session-idCóStringMã phiên từ API 1
device-typeCóStringCùng giá trị đã dùng ở API 1
Content-TypeCóStringapplication/json; charset=utf-8
langKhôngStringvi, en
sdk-version, manual-time, x-sdk-trace-id, x-sdk-trace-valuesKhôngStringXem mục Header chung

4.3. Request Body​

Body JSON gồm các trường dưới đây. Trường nào không đọc được thì bỏ hoặc để null. Các trường Base64 là Base64 chuẩn, đã bỏ ký tự xuống dòng (trừ face).

Tham sốYêu cầuKiểu dữ liệuMô tả
sodCóString (Base64)EF.SOD, chữ ký số của dữ liệu chip
comCóString (Base64)EF.COM
dg1CóString (Base64)DG1, dữ liệu MRZ
dg2CóString (Base64)DG2, ảnh khuôn mặt trên chip
dg13CóString (Base64)DG13, thông tin công dân
dg14KhôngString (Base64)DG14, thông tin Chip Authentication
dg15KhôngString (Base64)DG15, khoá công khai Active Authentication
challengeKhôngString (Base64)8 byte ngẫu nhiên client gửi vào chip khi Active Authentication
aAResultKhôngString (Base64)Chữ ký chip trả về cho challenge (Active Authentication, SHA256withRSA)
eACCAResultKhôngString (Base64)Kết quả Chip Authentication (EAC-CA)
faceKhôngString (Base64)Ảnh khuôn mặt giải mã từ DG2, JPEG
idKhôngStringSố CCCD (12 số)
nameKhôngStringHọ và tên
dobKhôngStringNgày sinh, dd/MM/yyyy
sexKhôngStringGiới tính
nationalityKhôngStringQuốc tịch
nationKhôngStringDân tộc
religionKhôngStringTôn giáo
homeKhôngStringQuê quán
addressKhôngStringNơi thường trú
issue-dateKhôngStringNgày cấp
expired-dateKhôngStringNgày hết hạn
featuresKhôngStringĐặc điểm nhận dạng
prev-numberKhôngStringSố CMND cũ
father, mother, partnerKhôngStringHọ tên cha, mẹ, vợ hoặc chồng
qrcodeKhôngStringChuỗi QR của CCCD (nếu có)

4.4. Mẫu request​

Body (file check_chip.json):

{
"id": "0010xxxxxxxx",
"name": "NGUYỄN VĂN A",
"dob": "01/01/1990",
"sex": "Nam",
"nationality": "Việt Nam",
"nation": "Kinh",
"religion": "Không",
"home": "...",
"address": "...",
"issue-date": "01/01/2021",
"expired-date": "01/01/2030",
"features": "...",
"prev-number": "0123456789",
"father": "...",
"mother": "...",
"partner": "",
"qrcode": "...",
"face": "/9j/4AAQSkZJRgABAQ...",
"com": "YBhfAQIwMDAwMDBcBGF1...",
"sod": "d4IG8DCCBuwGCSqGSIb3DQEHAqCC...",
"dg1": "YV1fH1pJRFZOTTAxMDA...",
"dg2": "dYIa0X9hghrLAgEBf2CC...",
"dg13": "bYIBzzCCAcsCAQEwDBMK...",
"dg14": "bh0xGzAZBgoEAH8ABwIC...",
"dg15": "b4IBJDCCASAwDQYJKoZI...",
"challenge": "q83vEjRWeJA=",
"aAResult": "Rk9PQkFSQkFa...",
"eACCAResult": "..."
}

Lệnh curl:

curl --location --request POST 'base_url/check_chip' \
--header 'api-key: your-api-key' \
--header 'session-id: 7760a743-884b-4195-b781-892e72c7b0b6' \
--header 'device-type: android' \
--header 'lang: vi' \
--header 'sdk-version: 3.7.3.5' \
--header 'manual-time: 15230' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-binary '@check_chip.json'

4.5. Response​

4.5.1. Mẫu response​

Thành công: HTTP 200

{
"errorCode": "0",
"errorMessage": "",
"message": "...",
"valid": true,
"verifyCode": "1",
"verifyMessage": "...",
"rar_request_id": "...",
"chip_check": {
"integrity_check": "True",
"clone_check": "True",
"authentication_check": "True"
},
"data": [
{ "key": "id", "name": "Số CCCD", "value": "0010xxxxxxxx" },
{ "key": "name", "name": "Họ và tên", "value": "NGUYỄN VĂN A" },
...
]
}

4.5.2. Mô tả response​

Tham sốKiểu dữ liệuMô tả
errorCodeString"0": dữ liệu chip hợp lệ. Giá trị khác: hiển thị errorMessage. Chi tiết xem tài liệu mã lỗi
errorMessageStringThông báo lỗi. Ngôn ngữ của thông báo được đặt bởi tham số lang trong headers
actionStringexit: dừng luồng
validBooleanKết quả xác thực chip
verifyCodeString1: xác thực thành công. 0: xác thực thất bại. 2: chưa xác thực
verifyMessageStringThông báo xác thực
rar_request_idStringMã tham chiếu yêu cầu xác thực
chip_checkObjectKết quả kiểm tra chip, gồm 3 trường integrity_check, clone_check, authentication_check bên dưới
integrity_checkStringTrue: dữ liệu toàn vẹn. False: dữ liệu không toàn vẹn
clone_checkStringTrue: dữ liệu gốc, không bị sao chép. False: dữ liệu bị sao chép. N/A: không thể kiểm tra
authentication_checkStringTrue: dữ liệu hợp lệ, xác thực thông tin C06 thành công. False: dữ liệu không hợp lệ, xác thực thông tin C06 thất bại. N/A: chưa xác thực thông tin C06
dataArrayDữ liệu trên chip, cấu trúc {key, name, value} như OCR. Nên ưu tiên hiển thị dữ liệu này thay cho dữ liệu OCR

5. API liveness và so khớp khuôn mặt​

Áp dụng cho: luồng đầy đủ, luồng chia hai lần (bước cuối). Kiểu body: form-data.

Kiểm tra người thật (liveness) và so khớp khuôn mặt với ảnh chân dung trên giấy tờ đã OCR trong phiên. Payload phụ thuộc sdk_config.liveness_type: gửi nhiều ảnh selfie, hoặc một video.

5.1. Request URL​

POST base_url/face/liveness

5.2. Request Headers​

Tham sốYêu cầuKiểu dữ liệuMô tả
api-keyCóStringAPI key do FPT cấp
session-idCóStringMã phiên từ API 1
device-typeCóStringCùng giá trị đã dùng ở API 1
mobileKhôngBooleantrue khi gửi từ ứng dụng di động
submit-resultKhôngBooleanCờ submit kết quả phiên, gửi false
langKhôngStringvi, en
sdk-version, manual-time, x-sdk-trace-id, x-sdk-trace-valuesKhôngStringXem mục Header chung

5.3. Request Body​

FormData, gửi đúng thứ tự part trong bảng.

liveness_typeThứ tự part
0 PHOTO, 5 FLASH2 part selfies (2 ảnh: chính diện, nghiêng)
4 MORE_PHOTO3 part selfies
2 ACTIVE_VIDEO2 part selfies cho 2 ảnh chụp xa, rồi near_face (ảnh chụp gần)
1 VIDEO, 3 RANDOMvideo. Có thể thêm near_face trước video
PartKiểuMô tả
selfiesFile, image/jpegẢnh selfie, khuyến nghị tối đa 1080 × 1440, khoảng 1 MB
near_faceFile, image/jpegẢnh khuôn mặt chụp gần
videoFile, video/mp4Video khuôn mặt
cmnd hoặc file[]File, image/jpegẢnh mặt trước giấy tờ để so khớp (kiểu video hoặc kiểu ảnh)

5.4. Mẫu request​

Kiểu MORE_PHOTO (3 ảnh):

curl --location --request POST 'base_url/face/liveness' \
--header 'api-key: your-api-key' \
--header 'session-id: 7760a743-884b-4195-b781-892e72c7b0b6' \
--header 'device-type: android' \
--header 'submit-result: false' \
--header 'mobile: true' \
--header 'lang: vi' \
--header 'sdk-version: 3.7.3.5' \
--header 'manual-time: 6890' \
--header 'x-sdk-trace-id: 5a8e2c71-3f9d-4b0a-8c6e-1d2f3a4b5c6d' \
--header 'x-sdk-trace-values: <token>' \
--form 'selfies=@"selfie.jpg";type=image/jpeg' \
--form 'selfies=@"selfie_left.jpg";type=image/jpeg' \
--form 'selfies=@"selfie_right.jpg";type=image/jpeg'

Kiểu VIDEO:

curl --location --request POST 'base_url/face/liveness' \
--header 'api-key: your-api-key' \
--header 'session-id: 7760a743-884b-4195-b781-892e72c7b0b6' \
--header 'device-type: android' \
--header 'submit-result: false' \
--header 'mobile: true' \
--header 'lang: vi' \
--header 'sdk-version: 3.7.3.5' \
--header 'manual-time: 9120' \
--form 'video=@"video.mp4";type=video/mp4'

5.5. Response​

5.5.1. Mẫu response​

Đạt: HTTP 200

{
"code": "200",
"message": "Kiểm tra thực thể sống thành công",
"liveness": {
"code": "200",
"message": "liveness check successful",
"is_live": "true",
"spoof_prob": "N/A",
"need_to_review": "N/A",
"is_deepfake": "N/A",
"deepfake_prob": "N/A",
"warning": "N/A"
},
"face_match": {
"code": "200",
"message": "face matching successful",
"isMatch": "true",
"similarity": "95.84",
"warning": "N/A"
},
"is_complete_session": true
}

5.5.2. Mô tả response​

Tham sốKiểu dữ liệuMô tả
codeString"200": đạt. Mã khác: không đạt, hiển thị message. Chi tiết xem tài liệu mã lỗi
messageStringThông báo theo ngôn ngữ của header lang
actionStringexit: dừng luồng ngay, không cho thử lại
livenessObjectcode, message, is_live, spoof_prob, need_to_review, is_deepfake, deepfake_prob, warning, error_frame_url. Các giá trị là chuỗi
face_matchObjectcode, message, isMatch, similarity (%), warning
is_complete_sessionBooleantrue: phiên đã kết thúc, không thử lại được. false: còn lượt thử (trong giới hạn sdk_config.limit)
video_face_url, compared_face_urlStringẢnh khuôn mặt trích từ selfie hoặc video và ảnh dùng để so khớp. Có thể hiển thị cho người dùng khi không đạt
public_url, custom_dataStringDữ liệu bổ sung (nếu có)

5.5.3. Mẫu response lỗi​

Khuôn mặt không khớp với giấy tờ: trả về khi khuôn mặt trong ảnh selfie không khớp với khuôn mặt trong ảnh giấy tờ.

{
"code": "303",
"message": "Khuôn mặt không khớp với giấy tờ",
"liveness": {
"code": "200",
"is_live": "true",
...
},
"face_match": {
"code": "303",
"isMatch": "false",
"similarity": "5.84",
...
},
"is_complete_session": false
}

Có 2 khuôn mặt: trả về khi hệ thống phát hiện nhiều hơn một khuôn mặt trong ảnh selfie.

{
"code": "407",
"message": "2 faces exist",
"liveness": {
"code": "200",
"message": "liveness check successful",
"is_live": "true",
"spoof_prob": "N/A",
"need_to_review": "N/A",
"is_deepfake": "N/A",
"deepfake_prob": "N/A",
"warning": "N/A"
},
"face_match": {
"code": "407",
"message": "2 faces exist",
"isMatch": "N/A",
"similarity": "N/A",
"warning": "N/A"
},
"is_complete_session": false
}

6. API liveness độc lập​

Áp dụng cho: luồng chỉ liveness (ekyc_flow = 6). Kiểu body: form-data.

Dùng cho luồng chỉ xác thực khuôn mặt, không có bước giấy tờ.

6.1. Request URL​

POST https://api.fpt.ai/dmp/liveness/v3

Khi dùng proxy riêng: base_url_proxy/dmp/liveness/v3.

6.2. Request Headers, Request Body​

Giống hệt API 5: cùng header, cùng cách chọn part theo liveness_type.

6.3. Response​

Cấu trúc giống API 5. Không có bước giấy tờ nên kết quả so khớp khuôn mặt (face_match) có thể không có.

7. API ghi log và truy vết​

Áp dụng cho: SDK khi enable_tracing = true. Kiểu body: JSON.

API này được thiết kế để phục vụ việc ghi log và truy vết exception ở phía SDK. Thông thường, SDK không gửi bất kỳ dữ liệu nào. Việc ghi log chỉ được kích hoạt thông qua cấu hình ở Portal.

Trong quá trình gọi API khởi tạo phiên, server có thể trả về một cờ:

{ "enable_tracing": true }
  • Nếu enable_tracing = true, SDK bắt đầu gửi thông tin log và exception qua API này.
  • Nếu enable_tracing = false (hoặc không có cờ này), SDK không được phép gửi thông tin log và exception.

Cơ chế này đảm bảo việc ghi log chỉ được kích hoạt trong các trường hợp debug hoặc lỗi, giúp lập trình viên thu thập thông tin truy vết chi tiết mà không gây tốn tài nguyên trong quá trình vận hành thông thường.

7.1. Request URL​

POST base_url/logging/tracing

7.2. Request Headers​

Tham sốYêu cầuKiểu dữ liệuMô tảChú ý
session-idKhôngStringID duy nhất của phiên eKYC nhận được từ bước khởi tạo phiên
api-keyCóStringAPI key để sử dụng hệ thống FPT AI eKYC
device-typeKhôngStringThiết bị đang sử dụng, các giá trị cho phép bao gồm: android, ios, web-sdkCần thêm tham số này nếu thông tin log được gửi từ nhiều client khác nhau
langKhôngStringNgôn ngữ sử dụng, các giá trị cho phép bao gồm: en, viCần thêm tham số này nếu thông tin log được gửi từ nhiều client khác nhau. Mặc định: en
sdk-versionKhôngStringPhiên bản của FPT AI eKYC SDKCần thêm tham số này nếu thông tin log được gửi từ nhiều client khác nhau
Content-TypeCóStringXác định loại nội dung của request bodyBắt buộc là application/json

7.3. Request Body​

Tham sốLoại dữ liệuYêu cầuMô tả
eventstringKhôngTên hoặc hành động của sự kiện (ví dụ: face.liveness.start)
levelstringKhôngMức độ log: debug, info, warn, error, fatal
messagestringKhôngThông điệp mô tả
timestampstring (ISO 8601)KhôngThời điểm xảy ra sự kiện phía client. Server sẽ tự gán giá trị nếu không có
duration_msnumberKhôngThời gian thực hiện cho các tác vụ có đo thời gian (mili giây)
attributesobjectKhôngTập các cặp key-value tuỳ chỉnh (ví dụ: thông tin thiết bị, ngữ cảnh người dùng)
session_metaobjectKhôngMetadata bổ sung của phiên eKYC, ví dụ {"sdk": "android", "version": "1.2.3"}
trace_idstringKhôngMã định danh liên kết cho việc truy vết
span_idstringKhôngMã định danh của span trong trace (nếu có)
exceptionobjectKhôngChi tiết exception hoặc lỗi (xem bảng bên dưới)

Đối tượng exception:

Tham sốLoại dữ liệuYêu cầuMô tả
typestringKhôngLoại exception hoặc tên class (ví dụ: NullPointerException)
messagestringKhôngThông điệp mô tả
stacktracestringKhôngThông tin stack trace
filestringKhôngTên source file nơi xảy ra lỗi
linenumberKhôngSố dòng trong file nơi xảy ra lỗi
codestringKhôngMã lỗi (nếu có)
handledbooleanKhôngtrue nếu exception đã được truy vết hoặc xử lý, false nếu chưa
detailobjectKhôngObject JSON tự do chứa thông tin bổ sung (nếu SDK có thể gửi thêm dữ liệu)

7.4. Mẫu request​

curl --location --request POST 'base_url/logging/tracing' \
--header 'api-key: your-api-key' \
--header 'session-id: 7760a743-884b-4195-b781-892e72c7b0b6' \
--header 'Content-Type: application/json' \
--data '{
"event": "face.match",
"level": "error",
"message": "Face match failed on SDK",
"timestamp": "2025-10-03T04:15:23.412Z",
"attributes": {
"device_type": "android",
"os_version": "14",
"sdk_version": "2.4.0"
},
"exception": {
"type": "IllegalArgumentException",
"message": "Invalid image format",
"stacktrace": "com.fpt.sdk.FaceMatch.process(FaceMatch.java:102)\ncom.fpt.sdk.MainActivity.onResult(MainActivity.kt:45)",
"file": "FaceMatch.java",
"line": 102,
"handled": true,
"detail": {}
}
}'

7.5. Response​

7.5.1. Mẫu response​

Thành công: http_code = 200

{
"code": "200",
"message": "Success"
}

Thất bại: http_code != 200

Xử lý kết quả và mã lỗi​

Một response có thể mang lỗi ở hai tầng: mã HTTP và mã nghiệp vụ trong body. Client cần kiểm tra cả hai.

Quy tắc đọc kết quả​

APIThành công khiKhông thành công
  1. Khởi tạo phiên | code = "200" | Hiển thị message, dừng luồng
  2. OCR, 3. QR, 4. NFC | errorCode = "0" | Hiển thị errorMessage, cho người dùng làm lại bước đó 5, 6. Liveness | code = "200" | Hiển thị message. Cho thử lại nếu is_complete_session = false

action = "exit" luôn được ưu tiên

Ở bất kỳ API nào, nếu response có action: "exit" thì client phải dừng luồng ngay và không cho thử lại, kể cả khi mã lỗi trông như lỗi tạm thời. Hiển thị message cho người dùng rồi kết thúc luồng.

Mã HTTP​

HTTPÝ nghĩaXử lý
200Thành công hoặc lỗi nghiệp vụĐọc mã nghiệp vụ trong body
400Dữ liệu gửi lên không hợp lệKiểm tra lại payload
401api-key không hợp lệDừng luồng
403Thiết bị không an toàn; phiên không tồn tại, hết hạn hoặc đã kết thúcDừng luồng. Với liveness, code = "403" nghĩa là phiên đã kết thúc
422Thiếu header hoặc trường bắt buộcSửa request
500, 502, 503Lỗi hệ thống hoặc gateway, body có thể rỗng hoặc HTMLBáo "hệ thống bận", cho thử lại

Mã liveness thường gặp​

codeÝ nghĩa
200Đạt liveness và khớp khuôn mặt
303Khuôn mặt không khớp với giấy tờ. Có thể hiển thị ảnh video_face_url và compared_face_url cho người dùng
403Phiên đã kết thúc, không thử lại được
Mã khácKhông đạt liveness, xem message và liveness.code

Danh sách đầy đủ mã lỗi OCR và liveness xem tại trang Mã lỗi của luồng eKYC.

Phụ lục A. Checklist tích hợp​

Các lỗi hay gặp khi tích hợp.

STTKiểm traHậu quả nếu sai
1Lưu session-id của API 1; luồng chia hai lần dùng lại session-id này, không gọi lại API 1Lần 2 tạo phiên mới, không gắn được với kết quả giấy tờ của lần 1
2Gửi part theo đúng thứ tự của bảng ở mục 2.3 (OCR) và bảng ở mục 5.3 (liveness, theo liveness_type)Backend xử lý nhầm ảnh, ví dụ đọc mặt sau thành mặt trước
3device-type giữ nguyên một giá trị trong suốt phiênRequest bị từ chối
4Proxy chuyển tiếp được header có gạch dưới (client_uuid)Mất mã đối soát phiên
5Ưu tiên xử lý action: "exit" trước mọi mã lỗi khácCho người dùng thử lại khi backend đã khoá phiên
6api-key không nằm trong mã nguồn công khai hoặc logLộ thông tin bảo mật