Bắt đầu nhanh API VA theo đơn hàng

Hướng dẫn tạo VA theo đơn hàng, nhận thanh toán khớp số tiền chính xác qua webhook với SePay API. Hỗ trợ ngân hàng BIDV, Sacombank, Vietcombank, VietinBank.

||

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.

Thử nghiệm không cần tài khoản ngân hàng thật

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ảnDoanh 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
BIDV cho phép đơn hàng mở

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ảnCá 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ầnKhô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.

Sacombank 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.

Vietcombank

Loại tài khoảnDoanh 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ầnKhông
Lưu ý khi tích hợp Vietcombank

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ảnDoanh 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ầnCó (không nhận chuyển vượt)
Hoàn tiền
VietinBank cần đăng ký dịch vụ thu hộ qua tài khoản định danh

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

Trạng thái đơn hàng
Rendering diagram...
Trạng thái VA
Rendering diagram...

Đơ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.

Trạng thái hoàn tiền của đơn hàng
Rendering diagram...

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

GET
https://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/orders
POST
https://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/orders
GET
https://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/orders/{order_xid}
DELETE
https://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/orders/{order_xid}
POST
https://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/orders/{order_xid}/va
DELETE
https://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/orders/{order_xid}/va/{va_number}
GET
https://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/prefixes
GET
https://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/prefixes/{va_prefix}
GET
https://userapi.sepay.vn/v2/bank-accounts/{ba_xid}/terminals

Luồ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 xác thực thanh toán qua VA theo đơn hàng
Rendering diagram...

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.

Luồng hoàn tiền cho đơn hàng
Rendering diagram...

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)

BIDV không cần bước này. Bỏ qua và chuyển sang bước tiếp theo.

Tạo đơn hàng

cURL
1
2
3
4
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"}'
Response 201
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"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_code hoặc qr_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

Bash
1
2
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án
  • Paid: đã thanh toán
  • Partially: thanh toán một phần (BIDV và VietinBank)
  • Cancelled: đã hủy

Tham số chính

Tham sốBắt buộcMô tả
va_prefix (Sacombank)Tiền tố VA. Không dùng cho BIDV, Vietcombank và VietinBank.
tid (Vietcombank)Terminal ID gốc do Vietcombank cấp. Không dùng cho BIDV, Sacombank và VietinBank.
order_codeKhôngMã đơ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 (Sacombank, Vietcombank, VietinBank)Số tiền (VND). Chỉ BIDV cho phép tùy chọn.

Xem đầy đủ tham số


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ầnThanh 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 đầuPaidPartially
VA sau lần chuyển đầuChuyển Paid, ngừng nhậnVẫn nhận tới khi đủ amount
Ngân hàng hỗ trợBIDV, Sacombank, Vietcombank, VietinBankBIDV, VietinBank

Hỗ trợ theo ngân hàng

BIDVVietinBank 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.

SacombankVietcombank 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ở của BIDV là cơ chế khác

Đơ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 đủ.

Xem API tạo VA


Hủy đơn hàng hoặc VA

Chỉ hủy được đơn hàng Pending và VA Unpaid. Response: 204 No Content.

Hủy đơn hàng | Hủy VA


Xem thêm