Tích hợp API bằng PHP
Hướng dẫn giới hạn IP, Domain dự án, chữ ký HMAC theo Event, tạo phiếu, kiểm tra trạng thái và nhận webhook.
1. Quy trình bắt đầu
- Đăng ký tài khoản và gửi yêu cầu cấp API, khai báo đúng Domain dự án, Webhook URL thuộc domain đó và có thể nhập trước IP outbound dự kiến (không bắt buộc).
- Khi duyệt, admin sẽ kiểm tra/chỉnh sửa danh sách IP và chỉ cấp API Client khi đã có ít nhất một IP được phép.
- Lưu API Key, API Secret và Webhook Secret ngoài thư mục public.
- Kiểm tra kết nối bằng
GET /api/v1/ping. - Tạo phiếu bằng
POST /api/v1/payment-requests, lưupayment_idvà dữ liệu thanh toán trả về. - Nhận webhook
payment.approvedvà chống xử lý trùng theoevent_id.
2. IP được phép và Domain dự án
Khi gửi yêu cầu cấp API, bạn có thể khai báo trước IPv4/IPv6 outbound hoặc để trống để admin bổ sung. Yêu cầu chỉ được duyệt khi admin đã thiết lập ít nhất một IP hợp lệ. Mỗi API Client chỉ chấp nhận request từ các IP đã được cấp quyền. Client không cần gửi Domain dự án trong header; hệ thống ràng buộc Domain dự án với API Client và Webhook URL đã đăng ký.
Nếu máy chủ không có outbound IP cố định, có thể sử dụng VPS, NAT Gateway, HTTP Proxy hoặc SOCKS5 Proxy có IP tĩnh. Hãy cung cấp IP egress thực tế của proxy/VPS cho admin. Không nên dùng proxy công cộng hoặc proxy tự đổi IP.
3. Xác thực HMAC theo Event
Mỗi request gửi bốn header:
X-API-Key: YOUR_API_KEY X-API-Event: payment.request.create X-API-Signature: HMAC_SHA256_SIGNATURE X-API-Signature-Alg: HMAC-SHA256
Không cần Timestamp, Nonce, Project-Domain hoặc Signature-Version.
Chuỗi ký:
canonical = EVENT + "\n" + RAW_BODY signature = HMAC_SHA256(canonical, API_SECRET)
Với request GET, RAW_BODY là chuỗi rỗng. Phải ký đúng raw body byte-for-byte trước khi gửi.
4. Event của từng endpoint
| Endpoint | Event |
|---|---|
GET /api/v1/ping | system.ping |
GET /api/v1/payment-methods | payment.methods.list |
POST /api/v1/payment-requests | payment.request.create |
GET /api/v1/payment-requests/{payment_id} | payment.request.status |
5. Kiểm tra kết nối
GET /api/v1/ping X-API-Event: system.ping
GET có raw body rỗng, vì vậy chữ ký được tính trên system.ping + "\n".
6. Phương thức thanh toán đang hoạt động
GET /api/v1/payment-methods X-API-Event: payment.methods.list
Response trả phương thức đang hoạt động. Có thể bỏ payment_method_code khi tạo phiếu để hệ thống tự sử dụng phương thức hiện hành.
7. Tạo phiếu nạp
POST /api/v1/payment-requests
X-API-Event: payment.request.create
Idempotency-Key: order-ABC123ABCB
Content-Type: application/json
{
"merchant_invoice_id": "ABC123ABCB",
"amount": 100000,
"description": "Nạp số dư"
}merchant_invoice_id: 6–10 ký tự chữ hoa và số, duy nhất theo API Client.amount: số nguyên VND trong hạn mức cho phép.description: tối đa 255 ký tự.Idempotency-Key: giữ nguyên khi retry cùng một nghiệp vụ để tránh tạo trùng. Vì cơ chế xác thực không dùng Timestamp/Nonce, idempotency là lớp bắt buộc để request lặp không tạo thêm phiếu.
8. Kiểm tra trạng thái phiếu
GET /api/v1/payment-requests/{payment_id}
X-API-Event: payment.request.statusNếu payment_ready=false, hãy gọi lại endpoint trạng thái. Khi thông tin thanh toán sẵn sàng, response cung cấp snapshot ngân hàng, số tài khoản, tên tài khoản, nội dung chuyển khoản, QR và expires_at nếu có. Website tích hợp nên sử dụng trực tiếp expires_at do API trả về.
Các trạng thái public thường gặp: preparing_payment, pending_payment, payment_reported, approved, expired, rejected, cancelled.
9. Webhook
Khi phiếu được hệ thống xác nhận thành công, webhook được gửi tới URL đã đăng ký. Nếu lần gửi đầu tiên chưa thành công, hệ thống sẽ tự động thử gửi lại.
X-Webhook-ID: evt_xxx X-Webhook-Event: payment.approved X-Webhook-Timestamp: UNIX_TIMESTAMP X-Webhook-Signature: HMAC_SHA256(TIMESTAMP + "." + RAW_BODY, WEBHOOK_SECRET)
Website nhận webhook phải xác minh timestamp, chữ ký bằng hash_equals(), đối chiếu payment_id, merchant_invoice_id, amount, transfer_content và chỉ ghi nhận một lần theo event_id. Trả HTTP 2xx sau khi xử lý thành công.
10. Dùng Proxy để giữ IP ổn định
Nếu hosting thay đổi IP outbound, cấu hình backend PHP đi qua proxy có IP tĩnh rồi gửi IP đó cho admin để cấp quyền. Với HTTP proxy dùng CURLOPT_PROXY/CURLOPT_PROXYPORT. Với SOCKS5 nên dùng CURLPROXY_SOCKS5_HOSTNAME để DNS được resolve qua proxy. Nếu API Base URL là HTTPS, luôn giữ kiểm tra TLS.
11. Mã lỗi xác thực thường gặp
| Mã | Ý nghĩa | Cách xử lý |
|---|---|---|
API_AUTH_HEADERS_MISSING | Thiếu header xác thực | Kiểm tra API Key, Event, Signature và Signature-Alg. |
API_IP_DENIED | IP chưa được cấp quyền | Kiểm tra IP egress thực tế hoặc IP proxy tĩnh và yêu cầu admin thêm đúng IP. |
API_DOMAIN_CONFIG_INVALID | Domain/Webhook cấu hình không khớp | Liên hệ admin kiểm tra Domain dự án và Webhook URL của API Client. |
API_EVENT_INVALID | Event không đúng endpoint | Dùng đúng Event trong bảng endpoint. |
API_SIGNATURE_ALG_INVALID | Thuật toán chữ ký không hỗ trợ | Gửi X-API-Signature-Alg: HMAC-SHA256. |
API_SIGNATURE_INVALID | Chữ ký sai | Kiểm tra Event, raw body và API Secret. |
API_CLIENT_DISABLED | API Client bị khóa | Liên hệ quản trị viên. |
12. Checklist triển khai
- Domain dự án và Webhook URL đã đăng ký đúng.
- IP outbound/proxy tĩnh đã được admin cho phép.
- API Secret/Webhook Secret không nằm trong public webroot.
- Event đúng endpoint và HMAC ký đúng
EVENT + "\n" + RAW_BODY. - POST có Idempotency-Key ổn định khi retry.
- Webhook có kiểm tra chữ ký và event idempotency.
- Ưu tiên HTTPS; chỉ dùng HTTP khi môi trường buộc phải tương thích và hiểu rằng nội dung sẽ không được mã hóa trên đường truyền.