Tài liệu API Endpoints
API Endpoints — EKYC Middleware
Tài liệu endpoints theo từng module. Base URL:/api/v1API Docs (OpenAPI 3.0):http://at.ekyc.test/docs/api— tự động sinh từ code bởi Scramble
Module: Partner (Bank → BE)
Yêu cầu mTLS + JWT (header Authorization: Bearer <JWT>)
POST /partner/init-session
Khởi tạo session EKYC, trả webview URL cho Bank redirect user.
Request:
{
"partner_tx_id": "TXN2026072901001",
"user_id": "USER_123456",
"account_number": "1903681845018",
"bank_name": "Ngân hàng TMCP Việt Nam Thịnh Vượng",
"bank_code": "VPB",
"account_holder_name": "NGUYEN VAN A",
"commission_status": "accumulated",
"identity_info": {
"full_name": "Nguyễn Văn A",
"id_number": "079201012345",
"date_of_birth": "1990-01-01",
"phone": "0901234567",
"email": "nguyenvana@email.com"
},
"contract_ref": "HD/2026/07/001",
"expired_minutes": 30
}
Response 200:
{
"status": "success",
"data": {
"session_id": "ekyc_abc123def456",
"partner_code": "VPBANK",
"partner_name": "VPBank",
"webview_config": {
"brand_name": "VPBank",
"logo_url": "https://vpbank.com/logo.png",
"theme": "#0d6efd",
"theme_color": "#0d6efd",
"language": "vi",
"support_phone": null,
"terms_url": null
},
"webview_url": "https://ekyc-middleware.example.com/webview/ekyc_abc123def456",
"webview_token": "eyJhbGciOiJIUzI1NiIs...",
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"access_token_expires_at": "2026-07-29T13:15:00+07:00",
"expires_in": 900,
"refresh_token": "refr_123456...",
"refresh_token_expires_at": "2026-07-30T13:00:00+07:00",
"session_expired_at": "2026-07-29T13:30:00+07:00"
},
"meta": {
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2026-07-29T13:00:00+07:00",
"response_time_ms": 185
}
}
Validation rules:
| Field | Rules |
|---|---|
| partner_tx_id | required, string, max:100, unique_in_partner |
| user_id | required, string, max:100 |
| account_number | nullable, string, max:50 |
| bank_name | nullable, string, max:150 |
| bank_code | nullable, string, max:50 |
| account_holder_name | nullable, string, max:150 |
| identity_info | required, array |
| identity_info.full_name | required, string, max:255 |
| identity_info.id_number | required, regex:/^\d{9,12}$/ |
| identity_info.date_of_birth | required, date_format:Y-m-d |
| expired_minutes | integer, min:5, max:1440 |
GET /partner/session/{session_id}
Tra cứu trạng thái session.
Response 200:
{
"status": "success",
"data": {
"session_id": "ekyc_abc123def456",
"partner_tx_id": "TXN2026072901001",
"user_id": "USER_123456",
"status": "awaiting_ekyc",
"created_at": "2026-07-29T13:00:00+07:00",
"expired_at": "2026-07-29T13:30:00+07:00",
"steps": {
"identity": "completed",
"face_match": "pending",
"ekyc_result": "pending",
"sign_contract": "pending"
}
},
"meta": { "...": "..." }
}
GET /partner/session/{session_id}/result
Lấy kết quả EKYC sau khi hoàn tất.
Response 200:
{
"status": "success",
"data": {
"session_id": "ekyc_abc123def456",
"partner_tx_id": "TXN2026072901001",
"status": "completed",
"ekyc_result": {
"core_ekyc_tx_id": "core_tx_xyz789",
"identity_verified": true,
"face_matched": true,
"liveness_passed": true,
"score": 95.5,
"verified_at": "2026-07-29T13:25:00+07:00"
},
"contract": {
"contract_ref": "HD/2026/07/001",
"status": "signed",
"signed_at": "2026-07-29T13:28:00+07:00"
}
},
"meta": { "...": "..." }
}
POST /partner/revoke-session
Thu hồi session (hủy quy trình).
Request:
{
"session_id": "ekyc_abc123def456",
"reason": "user_cancelled"
}
POST /partner/webhook-config
Cập nhật webhook URL nhận callback kết quả.
Request:
{
"webhook_url": "https://api.vpbank.com/ekyc/callback",
"secret": "whsec_abc123"
}
Module: Webview (Webview → BE)
Yêu cầu JWT — webview_token (header Authorization: Bearer <token>)
POST /webview/init
Khởi tạo webview, xác thực token và trả thông tin session + nhận diện thương hiệu của Partner cho webview render.
Request:
{
"session_id": "ekyc_abc123def456"
}
Response 200:
{
"status": "success",
"data": {
"session_id": "ekyc_abc123def456",
"partner_code": "VPBANK",
"partner_name": "VPBank",
"webview_config": {
"brand_name": "VPBank",
"logo_url": "https://vpbank.com/logo.png",
"theme": "#0d6efd",
"theme_color": "#0d6efd",
"language": "vi",
"support_phone": null,
"terms_url": null
},
"user_id": "USER_123456",
"status": "pending",
"identity_info": {
"full_name": "Nguyễn Văn A",
"id_number": "079201012345",
"date_of_birth": "1990-01-01",
"email": "nguyenvana@email.com"
},
"bank_info": {
"bank_name": "Ngân hàng TMCP Việt Nam Thịnh Vượng",
"bank_code": "VPB",
"account_number": "1903681845018",
"account_holder_name": "NGUYEN VAN A"
},
"contract_ref": "HD/2026/07/001",
"expired_at": "2026-07-29T13:30:00+07:00",
"ekyc_sdk_url": "https://sdk.ekyc.vendor.vn/frame?token=...",
"ekyc_sdk_token": "...",
"ekyc_sdk_token_name": "...",
"ekyc_sdk_access_token": "...",
"ekyc_sdk_resource_id": "..."
}
}
POST /webview/submit-identity
Webview gửi thông tin định danh (sau khi user chụp CMND/CCCD).
Request:
{
"session_id": "ekyc_abc123def456",
"identity_data": {
"front_image_url": "https://cdn.example.com/cccd_front.jpg",
"back_image_url": "https://cdn.example.com/cccd_back.jpg",
"id_number": "079201012345",
"full_name": "Nguyễn Văn A",
"date_of_birth": "1990-01-01"
}
}
POST /webview/submit-face
Gửi dữ liệu face match + liveness.
Request:
{
"session_id": "ekyc_abc123def456",
"face_data": {
"face_image_url": "https://cdn.example.com/face.jpg",
"liveness_video_url": "https://cdn.example.com/liveness.mp4"
}
}
POST /webview/submit-ekyc-result
Webview gửi kết quả EKYC (sau khi gọi Core EKYC bên phía webview).
Request:
{
"session_id": "ekyc_abc123def456",
"core_ekyc_result": {
"tx_id": "core_tx_xyz789",
"status": "completed",
"identity_verified": true,
"face_matched": true,
"liveness_passed": true,
"score": 95.5,
"raw_response": {}
}
}
POST /webview/sign-contract
User ký hợp đồng.
Request:
{
"session_id": "ekyc_abc123def456",
"sign_method": "otp",
"sign_data": {
"otp_ref": "OTP_20260729_001",
"signed_content": "base64..."
}
}
GET /webview/contract/{session_id}
Lấy nội dung hợp đồng.
GET /webview/session/{session_id}
Lấy thông tin session hiện tại và nhận diện thương hiệu Partner trên Webview.
Response 200:
{
"status": "success",
"data": {
"session_id": "ekyc_abc123def456",
"partner_code": "VPBANK",
"partner_name": "VPBank",
"webview_config": {
"brand_name": "VPBank",
"logo_url": "https://vpbank.com/logo.png",
"theme": "#0d6efd",
"theme_color": "#0d6efd",
"language": "vi",
"support_phone": null,
"terms_url": null
},
"status": "pending",
"bank_info": {
"bank_name": "Ngân hàng TMCP Việt Nam Thịnh Vượng",
"bank_code": "VPB",
"account_number": "1903681845018",
"account_holder_name": "NGUYEN VAN A"
},
"expired_at": "2026-07-29T13:30:00+07:00"
}
}
POST /webview/cancel
Hủy quy trình EKYC từ phía user.
POST /webview/bank-account
Cập nhật / sửa đổi thông tin tài khoản ngân hàng của phiên EKYC từ phía User.
Request:
{
"bank_name": "Ngân hàng TMCP Quân đội",
"bank_code": "MB",
"account_number": "090123456789",
"account_holder_name": "NGUYEN VAN A"
}
Response 200:
{
"status": "success",
"data": {
"session_id": "ekyc_abc123def456",
"bank_name": "Ngân hàng TMCP Quân đội",
"bank_code": "MB",
"account_number": "090123456789",
"account_holder_name": "NGUYEN VAN A",
"updated_at": "2026-08-20T06:45:00+07:00"
}
}
Module: Common (Public)
GET /common/banks
Lấy danh mục ngân hàng tại Việt Nam (chuẩn VietQR / Napas). Hỗ trợ tìm kiếm theo tên, mã code, mã BIN qua query param ?q=.
Response 200:
{
"status": "success",
"data": {
"total": 38,
"banks": [
{
"id": 1,
"name": "Ngân hàng TMCP Ngoại Thương Việt Nam",
"code": "VCB",
"bin": "970436",
"short_name": "Vietcombank",
"logo_url": "https://api.vietqr.io/img/VCB.png",
"is_transfer": true
},
{
"id": 7,
"name": "Ngân hàng TMCP Việt Nam Thịnh Vượng",
"code": "VPB",
"bin": "970432",
"short_name": "VPBank",
"logo_url": "https://api.vietqr.io/img/VPB.png",
"is_transfer": true
}
]
}
}
GET /common/banks/{code}
Lấy chi tiết 1 ngân hàng theo mã CODE (VD: VPB, VCB) hoặc mã BIN (VD: 970432).
Module: Webhook (Core EContract Inbound Callback)
POST /api/v1/webhook/core-ekyc (hoặc /api/v1/webhook/contract)
Tiếp nhận callback cập nhật trạng thái hợp đồng điện tử từ Core EContract / Vendor gửi về Middleware.
- Header bắt buộc:
Content-Type: application/jsonAuthorization: Bearer <CORE_ECONTRACT_CALLBACK_TOKEN>- Request Body (JSON):
{
"contract_id": "HD-20240818-001",
"contract_status": "SIGNED",
"reason": null
}
| Field | Type | Required | Mô tả |
|---|---|---|---|
contract_id | string | Có | Mã định danh hợp đồng (tương ứng contract_ref trong DB) |
contract_status | string | Có | Trạng thái hợp đồng từ Core (SIGNED, PROCESSING, WAITING_TO_SIGN, SUBMIT, FAIL, SUBMIT_FAIL, VOIDED, REJECT, OVERDUE) |
reason | string | Không | Lý do khi hợp đồng bị hủy hoặc từ chối |
- Response 200 (Thành công):
{
"status": "success",
"data": {
"contract_ref": "HD-20240818-001",
"contract_number": "HD-20240818-001",
"status": "signed",
"core_status": "SIGNED",
"reason": null,
"signed_at": "2024-08-20T17:45:00+07:00"
},
"meta": {
"request_id": "848e0fe9-4e7a-4c28-98e3-0d3fe6db3c8b",
"timestamp": "2024-08-20T17:45:00+07:00",
"response_time_ms": 12,
"message": "Cập nhật trạng thái hợp đồng thành công."
}
}
- Mẫu lệnh cURL Test:
curl -X POST "http://localhost:8000/api/v1/webhook/core-ekyc" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer core_cb_token_secret123" \
-d '{
"contract_id": "HD-20240818-001",
"contract_status": "SIGNED",
"reason": null
}'
Session Status Flow
pending → processing → awaiting_ekyc → awaiting_sign → completed
↓
failed
Tất cả các trạng thái → expired (khi hết hạn)
| Status | Mô tả |
|---|---|
pending | Vừa tạo, Bank chờ user vào webview |
processing | Đang xử lý dữ liệu |
awaiting_ekyc | User đang thực hiện EKYC trên webview |
awaiting_sign | EKYC xong, chờ user ký hợp đồng |
completed | Hoàn thành |
failed | Thất bại (user hủy, lỗi, ...) |
expired | Hết thời gian |
📝 Ghi chú: Các endpoint chi tiết (request body đầy đủ, response mẫu, error codes) sẽ được update trong quá trình implement. Scramble tự động sinh docs từ code.