Skip to main content

Overview

This documentation describes the integration between Baokim and CashPlus for two business operations:

  • Collection: customers transfer money to a virtual account; Baokim notifies CashPlus of the transaction.
  • Revenue sharing: CashPlus registers the amounts to be shared with User, Merchant, and CashPlus, then calls a disbursement order for each receiver. Baokim does not disburse any funds on its own until a disbursement order is received.

Environments​

Environment{env}{BASE_URL}
Test (sandbox)sanboxProvided by Baokim when integration begins
ProductionliveProvided by Baokim when go-live

API version for revenue sharing​

The flow in this documentation uses /transaction/v2/*. The old /transaction/v1/share-amount API (Baokim disburses automatically after registration) runs in parallel during the transition period and will be shut down according to a schedule announced in advance by Baokim.

  • A transaction registered through a given version is processed with that version until completion. Do not mix v1 and v2 for the same transaction (code 143).
  • After the v1 shutdown date, every v1 API returns 143.

{env} appears only in the Collection API group URLs (/collection/{env}/...). The /transaction/... and /ats/... groups do not include {env}; environments are differentiated by {BASE_URL}.

Public keys for signature verification, QR image domain ({QR_DOMAIN}), the CashPlus collection webhook URL, and the CashPlus disbursement result webhook URL are exchanged at the same time for each environment.

Terminology​

TermMeaning
TransactionId / TransIdBkCollection transaction ID generated by Baokim. Same value appears as: TransIdBk in collection webhook, TransactionId in revenue sharing APIs
NAmount available for sharing in a collection transaction: TransAmount − TransFeeAmount. If the transaction qualifies for the collection fee waiver, then TransFeeAmount = 0 and N = TransAmount
U, M, PAmounts shared with User, Merchant, and CashPlus, registered once at Share amount registration
ReceiverRecipient: 1 = User, 2 = Merchant, 3 = CashPlus
TypeDisbursement type: 1 = realtime, 2 = T+1
ReferenceIdDisbursement order ID generated by CashPlus, must be unique. Used to prevent duplicate orders. (In the collection webhook response, ReferenceId is the CashPlus-side transaction ID — a different meaning)
TransIdPaymentDisbursement order ID generated by Baokim. Remains unchanged throughout the order lifecycle
Active orderA disbursement order at Status 0, 99, or 200
Day TThe day Baokim receives the funds of the collection transaction, Vietnam time (GMT+7)
Cutoff23:50:59 on day T, in Baokim system time when the request is received
T+1Settlement period of day T: the next business day (transactions on Friday, Saturday, and Sunday are settled on Monday)
SourceOrder source: PARTNER = called by CashPlus, AUTO = created automatically by Baokim after cutoff (00:05 on day T+1), MANUAL = disbursed manually by Baokim

Integration Flow​

StepAPINotes
1Collection webhookIsFull=0 when payer account not yet available, IsFull=1 when available
2Share amount registrationOnce per TransactionId, before cutoff. Only records the split, does not transfer funds
3, 4, 5Disbursement orderEach request is one order for one receiver, Amount exactly equal to the registered amount. Receivers do not block each other
6Disbursement result webhookWhen the order reaches a final result
*Look up disbursement orderBy ReferenceId (one order) or TransactionId (all orders of the transaction)

Sharing and disbursement rules​

Registration:

  • Each collection transaction is registered once, with no modification. U + M + P ≤ N.
  • The remainder N − U − M − P cannot be disbursed by order and is settled to the Merchant at cutoff.

Disbursement orders:

  • The order's Amount must be exactly equal to the amount registered for that receiver.
  • Each receiver can have only 1 active order: an order can be called only when the receiver has no order at Status 0, 99, or 200.
  • A failed order (Status=11) can be retried with a new order (new ReferenceId) before cutoff, unless Retryable=false.
  • One receiver's order does not block another receiver's orders. For example, while the Merchant order is at 99, CashPlus can still call disbursement for User and CashPlus.
ReceiverValid TypeDisbursement fee
1 (User)Always 1 (realtime)Per realtime fee schedule
2 (Merchant)Exactly the registered Merchant.TypeRealtime: per fee schedule, waived under the fee waiver policy. T+1: free
3 (CashPlus)Always 2 (T+1)Free

Cutoff 23:50:59 on day T​

From 23:50:59 on day T, Baokim does not accept new share amount registrations or new disbursement orders for collection transactions of day T (code 141). Re-calling an existing ReferenceId and look-ups still work.

At 00:05 on day T+1, Baokim automatically creates 1 T+1 order to the Merchant (Source = AUTO, no ReferenceId, free of charge) for each collection transaction of day T, including transactions whose funds are received after cutoff, with the amount:

AUTO order = N − Sum of Amount of the transaction's active orders, as of 23:50:59

This includes: the whole N if not registered; the share of any receiver not yet called; the share of failed orders; and the unallocated remainder. If it equals 0, no order is created. The AUTO order is part of the same T+1 settlement period as other T+1 orders of day T, and has a disbursement result webhook like any other order.

  • Transactions whose funds are received between 23:50:59 and 23:59:59 on day T: registration is not accepted, the whole N goes to the Merchant on T+1.
  • Orders at Status=99 at 23:50:59 are not included in the AUTO order (even if they get a result before 00:05); they wait for their final result:
    • 200: done.
    • 11: Baokim sends the order's Status=11 webhook, then Baokim disburses manually on the next business day:
      • Order with Retryable=true: disbursed again to the same receiver (for User: using the account of the original order).
      • Order with Retryable=false (e.g. User account error), or re-disbursement to the original receiver fails: that share is disbursed to the Merchant.
      • The manual disbursement result is reported via webhook with Source = MANUAL, the original order's ReferenceId, a new TransIdPayment, and Receiver set to the actual recipient (may be 2 even if the original order was for User).
  • T+1 orders (Merchant Type=2, CashPlus, AUTO) that fail during Baokim settlement: Baokim sends the order's Status=11 webhook, then disburses manually to the same receiver (the Merchant, or CashPlus for a CashPlus order) and reports the result via a Source = MANUAL webhook. Baokim does not automatically move such an order into a later settlement period.
  • Call the APIs before 23:45 to avoid requests being processed after cutoff.

Retry and Error Handling​

Baokim does not automatically retry failed disbursement orders. Baokim only returns Status=11 when it is certain the funds have not been sent; if not certain, the order stays at Status=99.

SituationCashPlus should do
Timeout / no response received for disbursement orderRetry with the same ReferenceId or look up by ReferenceId. Only use a new ReferenceId if lookup returns 137 and it is still before cutoff
Order with Status=99Wait for webhook or look up. Do not call a new order for this receiver (it will be rejected with 134). Disbursement for other receivers can still be called
Order with Status=11, Retryable=trueCall a new order with a new ReferenceId before cutoff. If not called → that share goes to the Merchant on T+1
User order with Status=11, Retryable=false (User account error)Do not retry (it will be rejected with 119). Notify the customer. The U share goes to the Merchant on T+1
Rejected with 134Look up the previous order and handle according to its actual Status
Rejected with 141 (past cutoff)Stop, do not retry. That share goes to the Merchant on T+1
Share amounts not registered before cutoffThe whole N goes to the Merchant on T+1. CashPlus receives the webhook of the AUTO order

Examples​

Collection transaction BK6AB9B10B92C04SZ, N = 14,010.

Scenario 1 — All three recipients disbursed

#ActionResult
1Register U = 7,000, M = 6,860, P = 150200, remainder 0
2Disbursement order Merchant 6,860 (Ref#1, Type 1)Status 200
3Disbursement order User 7,000 (Ref#2)Status 200
4Disbursement order CashPlus 150 (Ref#3, Type 2)Status 0 → webhook 200 after the T+1 period
5CutoffNo AUTO order created (fully disbursed)

Scenario 2 — No User account, CashPlus does not call disbursement for its own share

#ActionResult
1Register U = 7,000, M = 6,860, P = 150200
2Disbursement order Merchant 6,860Status 200
3CutoffAUTO order 7,150 to Merchant (U 7,000 + P 150) → webhook Source=AUTO

Scenario 3 — User order failed, CashPlus retries

#ActionResult
1Disbursement order User 7,000 (Ref#2)Status 11, Retryable=true
2Disbursement order User 7,000 (Ref#4, new ReferenceId)Status 200

Scenario 4 — Blocked orders

#ActionResult
1Disbursement order Merchant 6,860 (Ref#1)Status 99
2Disbursement order Merchant 6,860 (Ref#5) while Ref#1 is 99Rejected 134
3Disbursement order User 5,000 (registered 7,000)Rejected 136
4Disbursement order CashPlus 150 with Type=1Rejected 107
5Disbursement order User at 23:51Rejected 141

Security​

All requests between Baokim and CashPlus are digitally signed. See Security.