Quy ước chung
- Tất cả request và response dùng JSON.
- Response thành công có dạng { success: true, data: {...}, timestamp }.
- Response lỗi có dạng { success: false, error: "...", timestamp }.
- Mọi endpoint đều bị giới hạn tần suất; vượt ngưỡng trả về mã 429.
POST /api/leads — Ghi nhận khách tiềm năng
Giới hạn 10 request mỗi giờ cho mỗi địa chỉ IP. Endpoint này kích hoạt gửi email nên ngưỡng đặt thấp có chủ đích.
Người nhận email thông báo luôn lấy từ cấu hình máy chủ, không bao giờ lấy từ nội dung request — đây là biện pháp chống lạm dụng để phát tán thư rác.
| Trường | Kiểu | Bắt buộc | Ghi chú |
|---|---|---|---|
| name | string | Có | Tối đa 120 ký tự |
| phone | string | Có | 6–20 ký tự |
| string | Không | Phải đúng định dạng email nếu có | |
| formType | string | Không | Dùng để phân loại nguồn |
| selectedPackage | string | Không | Gói khách quan tâm |
| notes | string | Không | Tối đa 2000 ký tự |
POST /api/checkout — Tạo đơn hàng
Trả về orderId, statusToken, qrUrl và transferContent. Giới hạn 10 request mỗi phút cho mỗi IP.
statusToken là chìa khoá để tra cứu trạng thái đơn — giữ ở phía trình duyệt của người mua, không ghi vào log.
| Trường | Kiểu | Bắt buộc |
|---|---|---|
| productName | string | Có |
| priceVnd | number nguyên dương | Có |
| customerPhone | string | Có |
| customerEmail | string (email) | Có |
| customerName | string | Không |
| packageType | string | Không |
GET /api/checkout/status — Tra cứu trạng thái
Bắt buộc có cả orderId và token. Thiếu token trả về 400.
Mã đơn chỉ có 4 chữ số nên bản thân nó không đủ bảo vệ; token mới là thứ chứng minh quyền truy cập. Token được so sánh theo cách không rò rỉ thời gian.
GET /api/checkout/status?orderId=LEXI-1234&token=<statusToken>
# Chưa thanh toán
{ "success": true, "data": { "status": "PENDING_PAYMENT" } }
# Đã thanh toán
{ "success": true, "data": { "status": "PAID_AND_FULFILLED", "fulfilledOrder": { ... } } }POST /api/webhooks/sepay — Đối soát thanh toán
Endpoint dành cho cổng thanh toán gọi vào, không dành cho ứng dụng của bạn.
- Bắt buộc kèm bí mật ở header Authorization hoặc x-sepay-secret.
- Máy chủ chưa cấu hình SEPAY_WEBHOOK_SECRET sẽ từ chối mọi request với mã 500 — không có chế độ chạy không xác thực.
- Sai bí mật trả về 401.
- Mỗi mã giao dịch ngân hàng chỉ được xử lý một lần; gọi lại cùng mã trả về reconciled: false.
- Số tiền phải bằng hoặc lớn hơn giá đơn hàng đã lưu, nếu không đơn chuyển sang diện đối soát thủ công.
POST /api/approval-gate — Đánh giá cấp rủi ro
- actionType chỉ nhận 4 giá trị: EMAIL_BULK, FINANCIAL_TRANSACTION, SYSTEM_DEPLOYMENT, SOCIAL_PUBLISH. Giá trị khác trả về 422.
- riskLevel là số nguyên 1–6.
- Cấp 1–2 tự động duyệt, 3–4 duyệt qua Zalo, 5–6 duyệt qua Telegram.
POST /api/approval-gate
{
"actionType": "FINANCIAL_TRANSACTION",
"riskLevel": 3
}
{
"success": true,
"data": {
"riskLevel": 3,
"status": "PENDING_HUMAN_APPROVAL",
"requiresApproval": true,
"approvalChannel": "ZALO"
}
}GET /api/ai-employees/scenarios — Danh mục kịch bản
Trả về danh sách kịch bản demo kèm chỉ tiêu độ trễ và tỉ lệ xử lý ngay lần đầu. Không yêu cầu xác thực, dùng cho trang giới thiệu.
Mã lỗi
| Mã | Ý nghĩa | Cách xử lý |
|---|---|---|
| 400 | Thiếu tham số bắt buộc | Kiểm tra lại tham số trên URL |
| 401 | Sai bí mật xác thực | Đối chiếu lại giá trị bí mật hai đầu |
| 404 | Tính năng chưa bật trên máy chủ này | Kiểm tra biến môi trường tương ứng |
| 422 | Dữ liệu không hợp lệ | Đọc trường error để biết tên trường sai |
| 429 | Vượt giới hạn tần suất | Chờ hết cửa sổ thời gian rồi thử lại |
| 500 | Máy chủ chưa cấu hình hoặc lỗi nội bộ | Kiểm tra nhật ký ứng dụng |