Cơ chế hoạt động của SePay IPN Webhook
SePay thông báo kết quả thanh toán đến hệ thống của bạn thông qua HTTP POST Instant Payment Notification (IPN). Để đảm bảo an toàn tuyệt đối cho doanh thu và quyền hạn người dùng, webhook handler bắt buộc phải xử lý xác thực, kiểm tra số tiền và bảo đảm tính idempotent.
Xác thực với Header X-Secret-Key
Mỗi webhook IPN từ SePay được đính kèm secret key trong HTTP header X-Secret-Key. Endpoint của bạn phải xác thực giá trị này bằng thuật toán so sánh chuỗi có độ phức tạp thời gian cố định (timing-safe comparison) để chống tấn công timing attack:
function verifySePayAuth(headerKey: string | undefined, expectedKey: string): boolean {
if (!headerKey || typeof headerKey !== "string") return false;
return crypto.timingSafeEqual(
Buffer.from(headerKey),
Buffer.from(expectedKey)
);
}
Kiểm tra trạng thái ORDER_PAID và khớp số tiền
Khi SePay gửi thông báo, chỉ xử lý kích hoạt đơn hàng khi order_status === "ORDER_PAID":
- Khớp mã đơn hàng (order_invoice_number): Đối chiếu chính xác với mã
Checkoutnội bộ đã tạo. - Khớp đơn vị tiền tệ và số tiền: Kiểm tra đơn vị tiền tệ bắt buộc phải là
VNDvà số tiềnorder_amountphải bằng đúngtotal_amountcủa đơn hàng. Không bao giờ chấp nhận số tiền nhỏ hơn để tránh gian lận thanh toán thiếu.
Idempotency và phòng ngừa Replay Attacks
Cổng thanh toán sẽ thử gửi lại (retry) webhook khi gặp sự cố mạng hoặc phản hồi chậm. Nếu hệ thống không idempotent, việc nhận webhook trùng lặp có thể dẫn đến cấp trùng quyền hoặc gia hạn ngày kết thúc nhiều lần:
- Lưu vết mã giao dịch duy nhất: Ghi nhận
transaction.idhoặcorder_idvào bảng giao dịch. - Nếu giao dịch đã được xử lý trước đó, trả về HTTP
200 OKngay lập tức mà không lặp lại tác vụ cấp quyền.
Chính sách an toàn với TRANSACTION_VOID
Trong một số trường hợp đối soát ngân hàng hoặc khách hàng yêu cầu hoàn tiền, SePay có thể gửi sự kiện có trạng thái hủy giao dịch hoặc chuyển tiền không hợp lệ. VietBilling áp dụng chính sách rõ ràng:
- Khi nhận trạng thái bất thường hoặc
TRANSACTION_VOID, hệ thống ghi nhận log kiểm toán (audit log) và thông báo cho quản trị viên. - Không tự ý hủy ngang subscription đang chạy mà chuyển trạng thái sang cần đối soát thủ công (manual review), tránh làm gián đoạn trải nghiệm của khách hàng do lỗi đồng bộ từ ngân hàng đối tác.