Quy chuẩn API & Mã lỗi
API Standards — EKYC Middleware
Quy chuẩn API chung cho toàn bộ hệ thống. Mọi API đều phải tuân thủ.
- Base URL:
https://ekyc-middleware.example.com/api/v1 - Format:
JSON (Content-Type: application/json) - Encoding:
UTF-8 - Date/Time: ISO 8601 (UTC +7)
1. Response Format Chuẩn
1.1 Thành công (HTTP 2xx)
{
"status": "success",
"data": {},
"meta": {
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2026-07-29T13:00:00+07:00",
"response_time_ms": 125
}
}
1.2 Lỗi nghiệp vụ (HTTP 4xx)
{
"status": "error",
"data": null,
"meta": {
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2026-07-29T13:00:00+07:00",
"response_time_ms": 42
},
"code": "SESSION_EXPIRED",
"message": "Phiên làm việc đã hết hạn"
}
1.3 Lỗi validation (HTTP 422)
{
"status": "fail",
"data": null,
"meta": {
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2026-07-29T13:00:00+07:00",
"response_time_ms": 15
},
"code": "VALIDATION_ERROR",
"message": "Dữ liệu không hợp lệ",
"errors": {
"field_name": [
"Trường này là bắt buộc",
"Định dạng không đúng"
]
}
}
1.4 Lỗi hệ thống (HTTP 5xx)
{
"status": "error",
"data": null,
"meta": {
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2026-07-29T13:00:00+07:00",
"response_time_ms": 2340
},
"code": "INTERNAL_SERVER_ERROR",
"message": "Đã có lỗi xảy ra, vui lòng thử lại sau"
}
2. Field Descriptions
| Field | Xuất hiện | Type | Bắt buộc | Mô tả |
|---|
status | all | string | Có | success / error / fail |
data | all | object|array|null | Có | Dữ liệu chính. null khi có lỗi |
meta | all | object | Có | Metadata |
meta.request_id | all | string | Có | UUID v4, sinh từ Str::uuid() |
meta.timestamp | all | string | Có | ISO 8601, now()->toIso8601String() |
meta.response_time_ms | success | int | Có | Thời gian xử lý (milliseconds) |
meta.pagination | list | object | Không | Thông tin phân trang (nếu có) |
code | error/fail | string | Có | Mã lỗi máy đọc được |
message | error/fail | string | Có | Thông báo cho developer/client |
errors | fail | object | Có | Map field → mảng lỗi, chỉ validation |
Pagination meta (khi response là list)
{
"data": [...],
"meta": {
"request_id": "...",
"timestamp": "...",
"response_time_ms": 50,
"pagination": {
"current_page": 1,
"per_page": 15,
"total": 100,
"last_page": 7,
"has_next": true,
"has_prev": false
}
}
}
3. Error Code System
Mã lỗi được tổ chức theo namespace, mã hóa cứng trong App\Enums\ErrorCode.
3.1 Authentication & Authorization (4xx)
| Code | HTTP | Mô tả |
|---|
AUTHENTICATION_REQUIRED | 401 | Thiếu header Authorization |
AUTHENTICATION_EXPIRED | 401 | JWT đã hết hạn |
AUTHENTICATION_INVALID | 401 | JWT sai format/chữ ký |
MTLS_CERT_INVALID | 401 | mTLS certificate không hợp lệ |
PARTNER_INACTIVE | 403 | Partner đang bị khóa |
PARTNER_IP_NOT_ALLOWED | 403 | IP không nằm trong whitelist |
SCOPE_NOT_PERMITTED | 403 | Token không có quyền truy cập resource này |
3.2 Validation & Request (4xx)
| Code | HTTP | Mô tả |
|---|
VALIDATION_ERROR | 422 | Dữ liệu đầu vào không hợp lệ (kèm errors) |
MALFORMED_REQUEST | 400 | JSON body bị lỗi cú pháp |
RESOURCE_NOT_FOUND | 404 | Endpoint hoặc resource không tồn tại |
METHOD_NOT_ALLOWED | 405 | Method không được hỗ trợ |
RATE_LIMIT_EXCEEDED | 429 | Vượt quá rate limit |
3.3 Business — Session (4xx)
| Code | HTTP | Mô tả |
|---|
SESSION_NOT_FOUND | 404 | session_id không tồn tại |
SESSION_EXPIRED | 410 | Session đã hết hạn |
SESSION_INVALID_STATUS | 409 | Trạng thái session không cho phép hành động |
DUPLICATE_TRANSACTION | 409 | partner_tx_id đã tồn tại |
3.4 Business — Partner (4xx)
| Code | HTTP | Mô tả |
|---|
PARTNER_TX_NOT_FOUND | 404 | Mã giao dịch partner không tồn tại |
CONTRACT_NOT_FOUND | 404 | Hợp đồng không tồn tại |
CONTRACT_ALREADY_SIGNED | 409 | Hợp đồng đã được ký |
IDENTITY_ALREADY_SUBMITTED | 409 | Thông tin định danh đã được gửi trước đó |
3.5 System — Core EKYC (5xx)
| Code | HTTP | Mô tả |
|---|
CORE_EKYC_CONNECTION_FAILED | 502 | Không thể kết nối Core EKYC |
CORE_EKYC_TIMEOUT | 504 | Core EKYC không phản hồi (timeout) |
CORE_EKYC_REJECTED | 502 | Core EKYC từ chối yêu cầu |
CORE_EKYC_INVALID_RESPONSE | 502 | Core EKYC trả dữ liệu không hợp lệ |
3.6 System — Internal (5xx)
| Code | HTTP | Mô tả |
|---|
INTERNAL_SERVER_ERROR | 500 | Lỗi không xác định, không log detail ra production |
DATABASE_ERROR | 500 | Lỗi cơ sở dữ liệu |
QUEUE_FAILED | 500 | Lỗi xử lý job |
ENCRYPTION_ERROR | 500 | Lỗi mã hóa/giải mã dữ liệu |
4. Request Validation
4.1 FormRequest chuẩn
Tất cả validation đều qua FormRequest, custom message tiếng Việt:
class InitSessionRequest extends FormRequest
{
public function authorize(): bool
{
return true; // Auth handled by middleware
}
public function rules(): array
{
return [
'partner_tx_id' => ['required', 'string', 'max:100'],
'user_id' => ['required', 'string', 'max:100'],
'account_number' => ['required', 'string', 'max:50'],
'identity_info' => ['required', 'array'],
'identity_info.full_name' => ['required', 'string', 'max:255'],
'identity_info.id_number' => ['required', 'string', 'regex:/^\d{9,12}$/'],
];
}
public function messages(): array
{
return [
'partner_tx_id.required' => 'Mã giao dịch đối tác là bắt buộc',
'identity_info.full_name.required' => 'Họ tên là bắt buộc',
'identity_info.id_number.regex' => 'Số CMND/CCCD phải là 9-12 chữ số',
];
}
}
4.2 Validation error response mẫu
Khi validation fail, response tự động:
{
"status": "fail",
"data": null,
"meta": { "...": "..." },
"code": "VALIDATION_ERROR",
"message": "Dữ liệu không hợp lệ",
"errors": {
"user_id": ["Trường user_id là bắt buộc"],
"identity_info.id_number": ["Số CMND/CCCD phải là 9-12 chữ số"]
}
}
5. Headers Chuẩn
5.1 Request Headers
| Header | Bắt buộc | Mô tả |
|---|
Content-Type | Có | application/json |
Authorization | Có | Bearer <JWT> hoặc Bearer <webview_token> |
X-Request-ID | Không | UUID để trace, nếu không có BE tự sinh |
Accept | Không | application/json |
5.2 Response Headers
| Header | Mô tả |
|---|
X-Request-ID | Request ID (trace) |
X-RateLimit-Limit | Số request tối đa |
X-RateLimit-Remaining | Số request còn lại |
X-RateLimit-Reset | Thời gian reset (Unix timestamp) |
X-Response-Time-Ms | Thời gian xử lý |
6. Autentication & Authorization
6.1 Partner API (Bank → BE)
| Layer | Phương thức | Xử lý khi fail |
|---|
| Transport | mTLS 1.3 — client cert required | 401 MTLS_CERT_INVALID |
| Token | JWT RS256 — Authorization: Bearer | 401 AUTHENTICATION_* |
| IP | IP Whitelist (cấu hình trong partners) | 403 PARTNER_IP_NOT_ALLOWED |
| Partner | Check partner status | 403 PARTNER_INACTIVE |
6.2 Webview API (Webview → BE)
| Layer | Phương thức | Xử lý khi fail |
|---|
| Token | JWT HS256 — webview_token | 401 AUTHENTICATION_* |
| Session | Check session_id ownership | 403 SCOPE_NOT_PERMITTED |
| Expiry | Check expired_at | 410 SESSION_EXPIRED |
7. Rate Limiting
| API Group | Limit | Key |
|---|
| Partner API | 100 requests/phút | partner:{partner_id} |
| Webview API | 30 requests/phút | session:{session_id} |
Khi vượt quá:
{
"status": "error",
"data": null,
"meta": { "...": "..." },
"code": "RATE_LIMIT_EXCEEDED",
"message": "Vượt quá giới hạn request, vui lòng thử lại sau 45 giây"
}
8. Logging & Audit
Mọi API request đều được ghi log:
// Structured logging
Log::channel('api')->info('Partner API Request', [
'request_id' => $requestId,
'partner_id' => $partnerId,
'endpoint' => $request->path(),
'method' => $request->method(),
'duration_ms' => $duration,
'status_code' => $response->status(),
'ip' => $request->ip(),
]);
Bảng ekyc_logs lưu toàn bộ request/response cho audit.
9. Scramble Integration
Documentation tự động qua Scramble:
// config/scramble.php
return [
'api_path' => 'api/v1',
'info' => [
'title' => 'EKYC Middleware API',
'description' => 'API Middleware giữa các Bank và Core EKYC',
'version' => '1.0.0',
],
];
- URL:
{BASE_URL}/docs/api - Format: OpenAPI 3.0
- Generate từ code (controllers + requests + models)
10. Exception Handling Chain
Request
├── Parse fail (malformed JSON)
│ └── MALFORMED_REQUEST (400)
├── Validation fail
│ └── FormRequest → VALIDATION_ERROR (422)
├── Auth fail
│ ├── No JWT → AUTHENTICATION_REQUIRED (401)
│ ├── JWT expired → AUTHENTICATION_EXPIRED (401)
│ ├── mTLS invalid → MTLS_CERT_INVALID (401)
│ └── IP not allowed → PARTNER_IP_NOT_ALLOWED (403)
├── Business logic fail
│ ├── Session expired → SESSION_EXPIRED (410)
│ ├── Duplicate TX → DUPLICATE_TRANSACTION (409)
│ └── Custom PartnerException → code tương ứng (4xx)
├── Core EKYC fail
│ └── CoreEkycException → CORE_EKYC_* (502/504)
└── Unhandled / System
└── Throwable → INTERNAL_SERVER_ERROR (500)