Virtual card issuance is the easy-looking part. The hard part is the ledger.
While building card support for ChinaWHAPI, we had to separate three balances that look similar but behave differently:
- Wallet balance — funds the user can still spend or withdraw.
- Card-locked funds — money committed to card funding.
- Live issuer balance — the authoritative available, frozen and pending balance on the card.
Combining those values creates broken equity displays and duplicate refunds.
Read-only actions should remain free
Revealing an authenticated card number is not a card-network authorization. Charging an authorization fee for that action is conceptually wrong. We changed card-detail viewing to be free and limited per-event fees to real transaction, authorization and decline webhooks.
Money math cannot use naive floating point
A 3.5% fee on $100 must be exactly $3.50. In JavaScript, multiplying a floating-point rate and then rounding can occasionally produce $3.51. Integer basis points avoid that class of error.
Every external event needs an idempotency key
Issuers retry webhooks. A transaction ID must protect movement fees, refund fees, declines and close events from being applied twice. Missing IDs should not trigger automatic charges.
Failure paths matter as much as success
If a top-up fails before reaching the issuer, both principal and service fee should roll back. If a card closes, its locked funds should be released exactly once. We now test those paths in an isolated database before deployment.
The product now supports live Visa/Mastercard BIN discovery, USDT-funded platform balances, real-time balance components and card lifecycle controls.
Disclosure: I work on ChinaWHAPI. See the virtual-card workflow and transparent terms.
Top comments (0)