VA theo đơn hàng là số tài khoản ảo riêng cho từng đơn hàng. Khách chuyển khoản vào VA đó, SePay khớp giao dịch với đơn hàng theo đúng số tiền và gửi webhook về hệ thống của bạn.
Sandbox cấp tài khoản giả lập để chạy thử toàn bộ luồng tạo đơn hàng, thanh toán và webhook.
Ngân hàng hỗ trợ
Tài khoản BIDV, Sacombank, Vietcombank và VietinBank đã liên kết trên SePay đều tạo được đơn hàng VA qua cùng một endpoint, nhưng khác nhau ở loại tài khoản, tham số bắt buộc và cách nhận tiền. Đọc phần của ngân hàng bạn đang tích hợp.
BIDV
| Loại tài khoản | Doanh nghiệp |
Số tiền (amount) | Tùy chọn |
Mã đơn hàng (order_code) | 6-50 ký tự, ^[a-zA-Z0-9]+$ (chỉ chữ cái không dấu và chữ số, không khoảng trắng hay ký tự đặc biệt) |
| Thanh toán một phần | Có |
Bỏ trống amount thì VA nhận bất kỳ số tiền nào. BIDV là ngân hàng duy nhất hỗ trợ kiểu đơn hàng này.
Khách trả chưa đủ amount thì đơn hàng chuyển Partially và VA vẫn nhận tiếp cho tới khi đủ.
Tài khoản BIDV doanh nghiệp có thể đặt tên chủ VA riêng qua va_holder_name, nhưng cần bật tính năng trước. Liên hệ SePay nếu bạn cần.
Sacombank
| Loại tài khoản | Cá nhân hoặc hộ kinh doanh |
Tiền tố VA (va_prefix) | Bắt buộc |
Số tiền (amount) | Bắt buộc |
Mã đơn hàng (order_code) | 6-50 ký tự, ^[a-zA-Z0-9]+$ (chỉ chữ cái không dấu và chữ số, không khoảng trắng hay ký tự đặc biệt) |
| Thanh toán một phần | Không |
Mỗi đơn hàng Sacombank phải gắn với một tiền tố VA. Gọi Tiền tố VA để lấy va_prefix đang hoạt động trước khi tạo đơn hàng. Merchant phải được kích hoạt, nếu chưa thì lệnh tạo trả 400.
Đơn hàng chỉ chuyển Pending sang Paid hoặc Cancelled, không có trạng thái Partially.
Vietcombank
| Loại tài khoản | Doanh nghiệp hoặc hộ kinh doanh |
Terminal ID (tid) | Bắt buộc |
Số tiền (amount) | Bắt buộc |
Mã đơn hàng (order_code) | 6-15 ký tự, ^[a-zA-Z0-9]+$ (chỉ chữ cái không dấu và chữ số, không khoảng trắng hay ký tự đặc biệt) |
| Thanh toán một phần | Không |
Mỗi đơn hàng cần một tid
Mỗi đơn hàng Vietcombank phải gắn với một terminal cụ thể qua tham số tid. Nếu chưa có terminal, xem cách thêm terminal cho tài khoản Vietcombank doanh nghiệp/hộ kinh doanh. Gọi Danh sách terminal để lấy tid hợp lệ trước khi tạo đơn hàng. tid là Terminal ID gốc do Vietcombank cấp (ví dụ 20933557), không phải xid UUID của SePay.
Chỉ nhận đúng số tiền
Đơn hàng chỉ chuyển Pending sang Paid hoặc Cancelled, không có trạng thái Partially. Lưu ý thêm order_code tối đa 15 ký tự, ngắn hơn các ngân hàng còn lại.
VietinBank
| Loại tài khoản | Doanh nghiệp |
Số tiền (amount) | Bắt buộc |
Mã đơn hàng (order_code) | 6-50 ký tự, ^[a-zA-Z0-9]+$ (chỉ chữ cái không dấu và chữ số, không khoảng trắng hay ký tự đặc biệt) |
| Thanh toán một phần | Có (không nhận chuyển vượt) |
| Hoàn tiền | Có |
Tài khoản VietinBank doanh nghiệp phải đăng ký dịch vụ thu hộ qua tài khoản định danh với VietinBank thì mới tạo được đơn hàng. Tài khoản chưa đăng ký nhận 422 vietinbank_va_order_not_enabled. Nếu bạn gặp lỗi này, vui lòng liên hệ SePay để được hỗ trợ.
Đơn hàng VietinBank luôn phải có amount, nhưng khách trả thiếu vẫn được ghi nhận: đơn hàng chuyển Partially và VA tiếp tục nhận cho tới khi đủ. VA đã hết hạn, đã thanh toán hoặc đã hủy không nhận thêm tiền.
Giao dịch lớn hơn amount của VA không được khớp: tiền vẫn vào tài khoản thật nhưng đơn hàng không chuyển sang Paid. Thu nhiều đợt trên VietinBank thì mỗi đợt phải nhỏ hơn hoặc bằng số tiền của VA.
Khoản đã thu trên VietinBank có thể hoàn tiền qua API.
Trạng thái
Đơn hàng còn mang trường refund_status riêng, null cho tới khi có lệnh hoàn tiền đầu tiên. Trường này chỉ đổi giá trị trên ngân hàng có hỗ trợ hoàn tiền.
Khác status, trường này tính lại từ toàn bộ lệnh hoàn của đơn hàng nên lùi được. Xem ý nghĩa từng giá trị.
Các endpoint
https://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/ordershttps://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/ordershttps://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/orders/{order_xid}https://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/orders/{order_xid}https://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/orders/{order_xid}/vahttps://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/orders/{order_xid}/va/{va_number}https://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/prefixeshttps://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/prefixes/{va_prefix}https://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/terminalsLuồng xác thực thanh toán qua VA theo đơn hàng
order_code là sợi dây nối đơn hàng bên bạn với đơn hàng trên SePay. Website tự sinh mã khi khách đặt hàng, truyền vào lệnh tạo đơn hàng, rồi webhook trả mã đó lại trong trường code để bạn đối chiếu. Bỏ trống thì SePay tự sinh, nhưng khi đó bạn phải tự lưu mã trả về để khớp ngược.
SePay chuẩn hoá order_code về chữ in hoa trước khi lưu. Gửi dh20250001 vẫn hợp lệ nhưng đơn hàng được lưu là DH20250001, và đó cũng là giá trị mà response và webhook trả về. Nếu hệ thống bạn dùng mã có chữ thường, hãy so khớp không phân biệt hoa thường, hoặc lưu lại đúng giá trị trong response thay vì giá trị bạn đã gửi.
Luồng hoàn tiền
Khi đơn hàng đã Paid hoặc Partially, bạn trả lại phần đã thu bằng API hoàn tiền. Hiện chỉ tài khoản VietinBank doanh nghiệp đã được SePay bật hoàn tiền mới dùng được.
Hoàn tiền không đổi status hay paid_amount của đơn hàng; thay vào đó đơn hàng mang thêm trường refund_status. Xem Hoàn tiền theo đơn hàng để biết tham số, sơ đồ trạng thái và bảng lỗi.
Các bước tích hợp
Chuẩn bị
- Tạo API Token
- Tài khoản ngân hàng đã liên kết trên SePay:
- BIDV: tài khoản doanh nghiệp
- Sacombank: tài khoản cá nhân hoặc hộ kinh doanh, merchant đã kích hoạt
- Vietcombank: tài khoản doanh nghiệp hoặc hộ kinh doanh, đã có ít nhất một terminal (xem cách thêm terminal hoặc lấy danh sách qua Danh sách terminal)
- VietinBank: tài khoản doanh nghiệp đã đăng ký dịch vụ thu hộ qua tài khoản định danh với VietinBank
- Lấy UUID tài khoản từ API Tài khoản ngân hàng
Lấy tiền tố VA (Sacombank) hoặc terminal (Vietcombank)
Tạo đơn hàng
curl -X POST "https://userapi.sepay.vn/v2/bank-accounts/{ba_uuid}/orders" \-H "Content-Type: application/json" \-H "Authorization: Bearer YOUR_API_TOKEN" \-d '{"amount": 500000, "order_code": "DH20250001", "with_qrcode": "1"}'
{"status": "success","message": "Order created successfully","data": {"id": "b2c3d4e5-f6a7-8901-bcde-f12345678902","order_code": "DH20250001","va_number": "963NQDORD1234567890AB","va_holder_name": "CONG TY CP TECH VINA","amount": 500000,"status": "Pending","bank_name": "BIDV","account_holder_name": "CONG TY CP TECH VINA","account_number": "1234567890","expired_at": null,"qr_code": "data:image/png;base64,...","qr_code_url": "https://vietqr.app/img?acc=963NQDORD1234567890AB&bank=BIDV&amount=500000&template=compact"}}
Hiển thị cho khách hàng
Từ response, hiển thị cho khách hàng:
- Số tài khoản:
va_number(số VA để chuyển khoản) - Số tiền:
amount - Mã QR:
qr_codehoặcqr_code_url - Thời hạn:
expired_at(nếu có)
Nhận thông báo thanh toán
Khi khách hàng chuyển khoản thành công, SePay gửi webhook đến URL bạn đã cấu hình. Giao dịch sẽ chứa trường code khớp với order_code của đơn hàng.
Xem chi tiết cấu hình webhook.
Kiểm tra trạng thái đơn hàng
curl -X GET "https://userapi.sepay.vn/v2/bank-accounts/{ba_uuid}/orders/{order_uuid}" \-H "Authorization: Bearer YOUR_API_TOKEN"
Trạng thái đơn hàng:
Pending: chờ thanh toánPaid: đã thanh toánPartially: thanh toán một phần (BIDV và VietinBank)Cancelled: đã hủy
Tham số chính
| Tham số | Bắt buộc | Mô tả |
|---|---|---|
va_prefix | Có (Sacombank) | Tiền tố VA. Không dùng cho BIDV, Vietcombank và VietinBank. |
tid | Có (Vietcombank) | Terminal ID gốc do Vietcombank cấp. Không dùng cho BIDV, Sacombank và VietinBank. |
order_code | Không | Mã đơn hàng, 6-50 ký tự (Vietcombank tối đa 15), theo ^[a-zA-Z0-9]+$ tức chỉ chữ cái không dấu và chữ số. SePay chuẩn hoá về chữ in hoa. Tự sinh nếu bỏ qua, mã tự sinh dài 10 ký tự in hoa. |
amount | Có (Sacombank, Vietcombank, VietinBank) | Số tiền (VND). Chỉ BIDV cho phép tùy chọn. |
Thanh toán một phần
Thanh toán một phần là khi khách chuyển ít hơn amount của đơn hàng mà SePay vẫn ghi nhận khoản đó, thay vì chỉ khớp khi số tiền đúng bằng amount. Đơn hàng thu dần qua nhiều lần chuyển khoản cho tới khi đủ.
Lần chuyển đầu chưa đủ amount đẩy đơn hàng sang Partially, trường paid_amount ghi tổng đã thu. VA vẫn nhận tiếp, mỗi lần chuyển cộng thêm vào paid_amount. Khi paid_amount đạt amount, đơn hàng chuyển Paid. Bạn cũng tạo thêm VA được cho đơn hàng đang Pending hoặc Partially để thu phần còn thiếu.
So với thanh toán toàn phần
| Thanh toán toàn phần | Thanh toán một phần | |
|---|---|---|
| Số tiền khách chuyển | Đúng amount | Ít hơn amount |
| Trạng thái sau lần chuyển đầu | Paid | Partially |
| VA sau lần chuyển đầu | Chuyển Paid, ngừng nhận | Vẫn nhận tới khi đủ amount |
| Ngân hàng hỗ trợ | BIDV, Sacombank, Vietcombank, VietinBank | BIDV, VietinBank |
Hỗ trợ theo ngân hàng
BIDV và VietinBank ghi nhận trả thiếu: đơn hàng dừng ở Partially cho tới khi thu đủ.
Riêng VietinBank có thêm một ràng buộc ở chiều ngược lại: giao dịch lớn hơn số tiền của VA không được khớp. Tiền vẫn vào tài khoản thật nhưng đơn hàng đứng nguyên. Nên khi thu làm nhiều đợt trên VietinBank, mỗi đợt phải nhỏ hơn hoặc bằng số tiền của VA.
Tạo thêm VA để thu nốt phần thiếu thì phải tự tính và truyền amount. Bỏ trống amount là VA lấy amount của đơn hàng gốc, không phải phần còn thiếu, kể cả trên BIDV. Với đơn hàng mở của BIDV (amount null) thì VA bổ sung mặc định amount bằng 0.
Sacombank và Vietcombank không hỗ trợ Partially: đơn hàng chuyển thẳng từ Pending sang Paid khi nhận thanh toán. Hai ngân hàng này vẫn tạo thêm VA được cho đơn hàng Pending, nhưng VA bổ sung là kênh thanh toán song song cho cùng số tiền, không phải để thu phần còn thiếu.
Đơn hàng mở bỏ trống amount, tức đơn hàng không có mốc số tiền để so, VA nhận bao nhiêu cũng được và không phát sinh phần còn thiếu. Thanh toán một phần thì ngược lại: amount cố định từ đầu, đơn hàng theo dõi paid_amount cho tới khi thu đủ.
Hủy đơn hàng hoặc VA
Chỉ hủy được đơn hàng Pending và VA Unpaid. Response: 204 No Content.