Khi endpoint của bạn lỗi, SePay tự gửi lại theo lịch riêng. Bài này tổng hợp lịch retry, cách tự chẩn đoán khi webhook không gửi, và các câu hỏi hay gặp.
Lịch retry
Khi webhook bật "Tự động gửi lại khi server trả lỗi", SePay thử lại nếu:
- Không kết nối được endpoint (DNS, connection refused, timeout)
- Server trả HTTP status ngoài 200-299
Khoảng cách giữa các lần tăng dần theo Fibonacci:
| Lần | Chờ | Tổng |
|---|---|---|
| 1 (ban đầu) | ngay | 0 phút |
| 2 | 1 phút | 1 phút |
| 3 | 1 phút | 2 phút |
| 4 | 2 phút | 4 phút |
| 5 | 3 phút | 7 phút |
| 6 | 5 phút | 12 phút |
| 7 | 8 phút | 20 phút |
| 8 (cuối) | 13 phút | 33 phút |
Tổng cộng 8 lần gửi (1 lần đầu cộng 7 lần retry), kéo dài khoảng 33 phút nếu tất cả đều thất bại. Webhook khi đó được đánh dấu Failed và SePay gửi cảnh báo (nếu bạn đã bật). Webhook cũ hơn 5 giờ sẽ không được cron quét retry tiếp, đây là vùng an toàn dự phòng, bình thường không tới mức này vì 33 phút đã kết thúc trước rồi.
Trả 200 ngay khi nhận được, rồi đẩy payload vào queue xử lý sau. Đừng chặn response khi đang xử lý nặng.
Phân loại lỗi
Lỗi kết nối
| Lỗi | Là gì | Sửa thế nào |
|---|---|---|
| DNS Error | Không tìm thấy domain | Kiểm tra URL, DNS |
| Connection Refused | Server từ chối | Kiểm tra server chạy chưa, port, firewall |
| Timeout | Quá 30 giây không phản hồi | Tối ưu endpoint, trả 200 trước rồi xử lý sau |
| SSL Error | Chứng chỉ hoặc chuỗi CA có vấn đề | Kiểm tra chứng chỉ còn hạn, CA chain đầy đủ, không dùng self-signed |
Lỗi HTTP
| Status | Là gì | Sửa thế nào |
|---|---|---|
| 401 | Sai xác thực | Kiểm tra API Key, Secret Key |
| 403 | Bị chặn | Thêm IP SePay vào whitelist |
| 404 | Sai URL | Kiểm tra đường dẫn (chú ý hoa thường) |
| 405 | Sai method | Endpoint phải nhận POST |
| 500 | Lỗi server | Kiểm tra logs |
| 502/503 | Server không sẵn sàng | Bảo trì hoặc quá tải |
Tốc độ phản hồi
| Thời gian | Nhận xét |
|---|---|
| < 1 giây | Tốt |
| 1-5 giây | Nên cải thiện |
| > 5 giây | Dễ bị timeout |
Mã cURL
Lịch sử gửi ghi error_code (mã cURL) + response_time_ms mỗi lần gửi.
| Mã | Lỗi | Ghi chú |
|---|---|---|
| 6 | DNS | Sai domain hoặc DNS chưa trỏ |
| 7 | Connection Refused | Server tắt, sai port, firewall chặn |
| 28 | Timeout | Phản hồi quá 30 giây |
| 35 | SSL | Lỗi bắt tay TLS |
| 51 | SSL Cert | Chứng chỉ không hợp lệ |
| 55 | Send Error | Mất kết nối khi gửi |
| 56 | Receive Error | Mất kết nối khi nhận |
| 60 | CA Cert | Không xác minh được chuỗi chứng chỉ (CA) |
Chẩn đoán webhook không gửi
Đã bật webhook nhưng server không nhận request? Đi từ trên xuống, lỗi thường ở mấy bước đầu.
1. Webhook còn bật
Dashboard → Webhooks, cột Trạng thái phải là Bật. Lưu webhook không tự bật lại nếu bạn đã tắt, kiểm tra lại công tắc sau mỗi lần sửa.
2. URL có gọi được không
Bấm ⋯ → Gửi thử. SePay gửi payload mẫu và kết quả hiện ra ngay.
| Kết quả | Nguyên nhân thường gặp |
|---|---|
| Thành công | URL ổn, qua bước 3 |
| DNS Error | Domain chưa trỏ, hoặc sai chính tả URL |
| Connection Refused | Server chưa lắng nghe port đó |
| Timeout | Firewall chặn, hoặc server quá chậm |
| SSL Error | Chứng chỉ hết hạn hoặc không hợp lệ |
| HTTP 4xx / 5xx | Server nhận được nhưng trả lỗi, mở chi tiết log |
3. Loại sự kiện có khớp
Webhook có 3 loại: Tất cả (cả vào cả ra), Chỉ tiền vào, Chỉ tiền ra.
Webhook Chỉ tiền vào mà test rút tiền → không gửi.
Chỉ tiền ra thêm ràng buộc: chỉ hỗ trợ Sacombank, TPBank, VietinBank, và phải dùng TKP (VA nội dung, không dùng VA chính thức). Xem Lưu ý khi chọn Chỉ tiền ra.
4. Tài khoản ngân hàng có trong danh sách
Mở webhook → tab Tài khoản.
Chế độ Tất cả tài khoản: mọi tài khoản đều kích hoạt webhook.
Chế độ Chọn cụ thể: tài khoản phát sinh giao dịch phải có trong cột Đã chọn.
Tài khoản liên kết SAU KHI tạo webhook không tự có trong danh sách tuỳ chọn. Mở webhook, thêm tay rồi lưu.
5. Cấu hình VA
Mỗi tài khoản trong danh sách có 3 chế độ VA:
- Tất cả VA: nhận mọi VA, kể cả VA tạo sau.
- Chỉ VA được chọn: chỉ khi giao dịch qua VA trong danh sách tick.
- Không nhận VA: bỏ qua mọi giao dịch qua VA.
Giao dịch đi qua VA? Kiểm tra chế độ:
- Không nhận VA: webhook bỏ qua, đổi chế độ.
- Chỉ VA được chọn: VA đó đã tick chưa?
Ngân hàng chỉ hỗ trợ VA (BIDV, MSB, KienlongBank, OCB) không có tài khoản chính, bắt buộc phải có VA.
6. Mã thanh toán
Nếu Chỉ gửi khi có mã thanh toán bật, giao dịch phải có code nhận diện được. Xem Cấu hình mã thanh toán cho mẫu công ty bạn.
Có bộ lọc Lọc theo mã thanh toán (tiền tố) thì mã phải bắt đầu bằng một trong các tiền tố đó.
Test nhanh: tắt công tắc này, chuyển lại khoản test.
7. Server trả về gì
Mở Lịch sử gửi → dòng mới nhất → tab Response.
Trả HTTP 200/201 với body {"success": true} mới tính thành công. Khác đi bị đánh dấu thất bại dù URL nhận được request. Chi tiết: Phản hồi hợp lệ.
8. Đang bị retry ngầm
Nếu server thỉnh thoảng sập hoặc chậm, SePay sẽ retry. Mỗi lần retry tạo một dòng riêng trong Lịch sử gửi.
Nếu thấy 8 dòng liên tiếp cùng id và đều Failed, nghĩa là giao dịch đó đã mất. Dùng Sự cố để tìm tất cả giao dịch mất và gửi lại.
9. OAuth 2.0 lỗi xác thực
Với OAuth 2.0, SePay phải gọi token endpoint trước rồi mới gọi đến webhook URL kèm Bearer token. Nếu token endpoint hỏng, webhook URL sẽ không nhận được request nào. Lúc debug bạn cần nhìn cả log token, không chỉ log webhook.
Chẩn đoán OAuth 2.0
OAuth 2.0 có thể hỏng ở 5 chỗ. Mở Lịch sử gửi xem log để xác định:
| Chỗ hỏng | Biểu hiện trong log | Hướng kiểm tra |
|---|---|---|
| Không gọi được token endpoint | DNS Error / Timeout / Connection Refused ở bước lấy token | URL token online? Firewall chặn IP SePay? |
| Token endpoint trả sai status | HTTP 4xx/5xx từ URL token | Endpoint phải trả 200 |
| Token endpoint body sai format | "Phản hồi OAuth không đúng định dạng" | Phải có access_token (dạng chuẩn) hoặc data.accessToken (dạng tùy chỉnh) |
| Token OK, webhook URL trả 401 | Đã có token rồi mà webhook từ chối | Server chưa xác minh Bearer đúng, hoặc coi token đã hết hạn |
| Webhook URL trả 200 | Thành công | Không cần làm gì |
Trước khi cấu hình webhook, gọi thử token endpoint bằng curl:
curl -X POST https://your-auth-server/oauth/token \-d "grant_type=client_credentials" \-u "your_client_id:your_client_secret"
Response phải là JSON status 200 có access_token. OK rồi mới cấu hình webhook.
Cấu hình + flow OAuth xem ở Xác thực OAuth 2.0.
Câu hỏi thường gặp
Khi nào cần đối soát
Retry tự động chỉ trong khoảng 33 phút. Endpoint sập lâu hơn thì webhook mất. Lúc đó dùng đối soát giao dịch hoặc Sự cố để xem danh sách bị ảnh hưởng và gửi lại.
Tiếp theo
- Đối soát giao dịch: backup khi webhook mất quá 5 giờ
- Giám sát: lịch sử gửi, cảnh báo, sự cố
- Tích hợp webhook: cách chống trùng lặp
- Bảo mật: checklist bảo mật endpoint