Tổng quan
Tài liệu mô tả tích hợp giữa Baokim và CashPlus cho 2 nghiệp vụ:
- Thu hộ: khách hàng chuyển tiền vào tài khoản ảo, Baokim thông báo giao dịch cho CashPlus.
- Chia sẻ tiền: CashPlus đăng ký số tiền chia cho User, Merchant và CashPlus, sau đó gọi chi tiền cho từng người nhận. Baokim không tự chi tiền khi chưa có lệnh chi.
Môi trường
| Môi trường | {env} | {BASE_URL} |
|---|---|---|
| Test (sandbox) | sanbox | Baokim cung cấp khi bắt đầu tích hợp |
| Production | live | Baokim cung cấp khi go-live |
Phiên bản API chia sẻ tiền
Luồng trong tài liệu này dùng /transaction/v2/*. API /transaction/v1/share-amount cũ (đăng ký xong Baokim tự chi) chạy song song trong giai đoạn chuyển và sẽ ngừng theo lịch Baokim thông báo trước.
- Giao dịch đăng ký qua phiên bản nào thì xử lý theo phiên bản đó đến hết. Không dùng lẫn v1 và v2 cho cùng một giao dịch (mã
143). - Sau ngày ngừng v1, mọi API v1 trả
143.
{env} chỉ có trong URL nhóm API thu hộ (/collection/{env}/...). Các nhóm /transaction/... và /ats/... không có {env}, môi trường được phân biệt bằng {BASE_URL}.
Khóa công khai để verify chữ ký, domain ảnh mã QR ({QR_DOMAIN}), URL webhook thu hộ và URL webhook kết quả chi của CashPlus được trao đổi cùng thời điểm cho từng môi trường.
Thuật ngữ
| Thuật ngữ | Ý nghĩa |
|---|---|
| TransactionId / TransIdBk | Mã giao dịch thu hộ do Baokim sinh. Cùng một giá trị: TransIdBk trong webhook thu hộ, TransactionId trong các API chia sẻ tiền |
| N | Số tiền khả dụng để chia của giao dịch thu hộ: TransAmount − TransFeeAmount. Nếu giao dịch được miễn phí thu hộ thì TransFeeAmount = 0 và N = TransAmount |
| U, M, P | Số tiền chia cho User, Merchant và CashPlus, đăng ký một lần ở Đăng ký số tiền chia sẻ |
| Receiver | Người nhận: 1 = User, 2 = Merchant, 3 = CashPlus |
| Type | Hình thức chi: 1 = realtime, 2 = T+1 |
| ReferenceId | Mã lệnh chi do CashPlus sinh, duy nhất. Dùng để chống tạo lệnh trùng. (Trong response của webhook thu hộ, ReferenceId là mã giao dịch phía CashPlus — khác nghĩa) |
| TransIdPayment | Mã lệnh chi do Baokim sinh. Không đổi trong suốt vòng đời lệnh |
| Lệnh hiệu lực | Lệnh chi đang ở Status 0, 99 hoặc 200 |
| Ngày T | Ngày Baokim nhận tiền của giao dịch thu hộ, giờ Việt Nam (GMT+7) |
| Cutoff | 23:50:59 ngày T, theo giờ hệ thống Baokim lúc nhận request |
| T+1 | Kỳ quyết toán của ngày T: ngày làm việc kế tiếp (giao dịch thứ Sáu, thứ Bảy, Chủ nhật quyết toán vào thứ Hai) |
| Source | Nguồn lệnh: PARTNER = CashPlus gọi, AUTO = Baokim tự tạo sau cutoff (00:05 ngày T+1), MANUAL = Baokim chi tay |
Luồng tích hợp
| Bước | API | Ghi chú |
|---|---|---|
| 1 | Webhook thu hộ | IsFull=0 khi chưa có tài khoản người trả, IsFull=1 khi đã có |
| 2 | Đăng ký số tiền chia sẻ | 1 lần / TransactionId, trước cutoff. Chỉ ghi nhận số chia, không chuyển tiền |
| 3, 4, 5 | Lệnh chi | Mỗi request một lệnh cho một người nhận, Amount bằng đúng số đã đăng ký. Các người nhận không chặn nhau |
| 6 | Webhook kết quả chi | Khi lệnh có kết quả cuối |
| * | Tra cứu lệnh chi | Theo ReferenceId (một lệnh) hoặc TransactionId (mọi lệnh của giao dịch) |
Quy tắc chia và chi
Đăng ký:
- Mỗi giao dịch thu hộ đăng ký 1 lần, không sửa.
U + M + P ≤ N. - Phần dư
N − U − M − Pkhông gọi chi được và được quyết toán về Merchant tại cutoff.
Lệnh chi:
Amountcủa lệnh phải bằng đúng số đã đăng ký cho người nhận đó.- Mỗi người nhận chỉ có 1 lệnh hiệu lực: chỉ gọi được khi người nhận chưa có lệnh ở
Status0, 99 hoặc 200. - Lệnh thất bại (
Status=11) được gọi lại bằng lệnh mới (ReferenceIdmới) trước cutoff, trừ khiRetryable=false. - Lệnh của người nhận này không chặn lệnh của người nhận khác. Ví dụ lệnh Merchant đang
99thì CashPlus vẫn gọi chi User và CashPlus được.
| Receiver | Type hợp lệ | Phí chi |
|---|---|---|
| 1 (User) | Luôn 1 (realtime) | Theo biểu phí realtime |
| 2 (Merchant) | Đúng Merchant.Type đã đăng ký | Realtime: theo biểu phí, được miễn theo chính sách miễn phí. T+1: miễn phí |
| 3 (CashPlus) | Luôn 2 (T+1) | Miễn phí |
Cutoff 23:50:59 ngày T
Từ 23:50:59 ngày T, Baokim không nhận đăng ký số tiền chia sẻ và lệnh chi mới cho các giao dịch thu hộ của ngày T (mã 141). Gọi lại một ReferenceId đã có và tra cứu vẫn dùng được.
Lúc 00:05 ngày T+1, Baokim tự tạo 1 lệnh T+1 về Merchant (Source = AUTO, không có ReferenceId, miễn phí) cho mỗi giao dịch thu hộ của ngày T, kể cả giao dịch nhận tiền sau cutoff, với số tiền:
Lệnh AUTO = N − Tổng Amount các lệnh hiệu lực của giao dịch, tính theo trạng thái lúc 23:50:59
Gồm: toàn bộ N nếu chưa đăng ký; phần của người nhận chưa được gọi chi; phần của lệnh thất bại; phần dư chưa chia. Bằng 0 thì không tạo. Lệnh AUTO nằm trong cùng kỳ quyết toán T+1 với các lệnh T+1 khác của ngày T, và có webhook kết quả chi như mọi lệnh.
- Giao dịch nhận tiền từ 23:50:59 đến 23:59:59 ngày T: không nhận đăng ký, toàn bộ N về Merchant T+1.
- Lệnh đang
Status=99lúc 23:50:59 không gộp vào lệnhAUTO(kể cả khi ra kết quả trước 00:05), mà chờ kết quả cuối:200: kết thúc.11: Baokim gửi webhookStatus=11của lệnh, rồi Baokim chi tay trong ngày làm việc kế tiếp:- Lệnh có
Retryable=true: chi lại cho đúng người nhận (với User: dùng tài khoản của lệnh gốc). - Lệnh có
Retryable=false(ví dụ lỗi tài khoản User), hoặc chi lại cho người nhận gốc không được: chi phần đó về Merchant. - Kết quả chi tay được báo qua webhook với
Source = MANUAL,ReferenceIdcủa lệnh gốc,TransIdPaymentmới vàReceiverlà người thực nhận (có thể là2dù lệnh gốc là User).
- Lệnh có
- Lệnh T+1 (Merchant
Type=2, CashPlus,AUTO) thất bại khi Baokim quyết toán: Baokim gửi webhookStatus=11của lệnh, rồi chi tay lại cho đúng người nhận (Merchant, hoặc CashPlus với lệnh CashPlus) và báo kết quả qua webhookSource = MANUAL. Baokim không tự đưa lệnh này vào kỳ quyết toán sau. - Nên gọi API trước 23:45 để tránh request bị xử lý sau cutoff.
Gọi lại và xử lý lỗi
Baokim không tự gọi lại lệnh chi thất bại. Baokim chỉ trả Status=11 khi chắc chắn tiền chưa ra; chưa chắc thì lệnh giữ Status=99.
| Tình huống | CashPlus nên làm |
|---|---|
| Timeout / không nhận được response của lệnh chi | Gọi lại cùng ReferenceId hoặc tra cứu theo ReferenceId. Chỉ dùng ReferenceId mới khi tra cứu trả 137 và còn trước cutoff |
Lệnh Status=99 | Chờ webhook hoặc tra cứu. Không gọi lệnh mới cho người nhận này (sẽ bị 134). Vẫn gọi chi cho người nhận khác |
Lệnh Status=11, Retryable=true | Gọi lệnh mới với ReferenceId mới trước cutoff. Không gọi → phần đó về Merchant T+1 |
Lệnh User Status=11, Retryable=false (lỗi tài khoản User) | Không gọi lại (sẽ bị 119). Báo cho khách. Phần U về Merchant T+1 |
Bị 134 | Tra cứu lệnh cũ và xử lý theo Status thật của nó |
Bị 141 (quá cutoff) | Dừng, không gọi lại. Phần đó về Merchant T+1 |
| Không đăng ký số tiền chia sẻ trước cutoff | Toàn bộ N về Merchant T+1. CashPlus nhận webhook của lệnh AUTO |
Ví dụ
Giao dịch thu hộ BK6AB9B10B92C04SZ, N = 14.010.
Kịch bản 1 — Chi đủ 3 bên
| # | Thao tác | Kết quả |
|---|---|---|
| 1 | Đăng ký U = 7.000, M = 6.860, P = 150 | 200, dư 0 |
| 2 | Lệnh chi Merchant 6.860 (Ref#1, Type 1) | Status 200 |
| 3 | Lệnh chi User 7.000 (Ref#2) | Status 200 |
| 4 | Lệnh chi CashPlus 150 (Ref#3, Type 2) | Status 0 → webhook 200 sau kỳ T+1 |
| 5 | Cutoff | Không tạo lệnh AUTO (đã chi đủ) |
Kịch bản 2 — Không có tài khoản User, CashPlus không gọi chi phần mình
| # | Thao tác | Kết quả |
|---|---|---|
| 1 | Đăng ký U = 7.000, M = 6.860, P = 150 | 200 |
| 2 | Lệnh chi Merchant 6.860 | Status 200 |
| 3 | Cutoff | Lệnh AUTO 7.150 về Merchant (U 7.000 + P 150) → webhook Source=AUTO |
Kịch bản 3 — Lệnh User thất bại, CashPlus gọi lại
| # | Thao tác | Kết quả |
|---|---|---|
| 1 | Lệnh chi User 7.000 (Ref#2) | Status 11, Retryable=true |
| 2 | Lệnh chi User 7.000 (Ref#4, ReferenceId mới) | Status 200 |
Kịch bản 4 — Các lệnh bị chặn
| # | Thao tác | Kết quả |
|---|---|---|
| 1 | Lệnh chi Merchant 6.860 (Ref#1) | Status 99 |
| 2 | Lệnh chi Merchant 6.860 (Ref#5) khi Ref#1 còn 99 | Từ chối 134 |
| 3 | Lệnh chi User 5.000 (đăng ký 7.000) | Từ chối 136 |
| 4 | Lệnh chi CashPlus 150 với Type=1 | Từ chối 107 |
| 5 | Lệnh chi User lúc 23:51 | Từ chối 141 |
Bảo mật
Mọi request giữa Baokim và CashPlus đều được ký số. Xem Bảo mật.