Skip to main content

Payment System Overview

Status: architecture reference (draft)

This documents the xperise corporate payment architecture and how the two new methods (QR-code payment and the xperise card system) fit it. It is still a working draft; endpoint shapes are illustrative sketches, not a frozen API contract.

xperise is a corporate (B2B) payment system: a company funds spending, its employees spend at vendors, and every payment is governed by both a spending policy and a real balance. Understanding that split is the key to the whole design.

Actors​

ActorRole
CompanyOur customer. Holds the company wallet (real balance) and an assigned company credit line. Defines how employees spend.
EmployeeSpends at vendors. Assigned a monthly limit or a cost center (per the company's operating model); may hold an xperise card.
Vendor (merchant)Accepts payments; generates dynamic QR (via API or the merchant app); operates a card reader / scanner.
2c2pExternal payment gateway used when an employee pays by credit card.
xperise platformRuns the ledger, enforces spending policy, authorizes/settles payments, issues xperise cards, and runs risk controls.

The two-layer model (the core concept)​

Every employee payment passes two independent checks, and on success xperise decrements one bucket from each layer:

  • Layer 1 — Spending authority (policy control): how much the employee is allowed to spend. It's a budget/limit, not real money. A company runs one operating model — either monthly limit or cost center, never both:

    • Monthly limit — a per-employee allowance that resets every month.
    • Cost center — a shared budget bucket that resets after a configured period, or is re-topped to a new limit, depending on the company's settings.

    In addition, each xperise card carries a card balance — the spending-authority bucket for payments made with that card. Its reset is configurable: replenished on a day of the month, or no reset (the manager tops it up when it runs empty; top-up is always available). A card payment draws the card balance, plus the cost center only if the company's model is cost center.

    The operating model is chosen per company (see the Corporate Portal).

  • Layer 2 — Funding (the real balance): where the money actually comes from. One of:

    • Company wallet — the company's real internal balance, backed by company credit (a credit line assigned to the wallet that resets after a period, typically 1 month). Spendable from the wallet = wallet balance + remaining company credit.
    • Credit card via 2c2p — an external credit card charged through the 2c2p payment gateway.

    For xperise cards, the funding source is optional: the company wallet, or none — in which case the card balance is stored value (prepaid) and is itself the money, so no wallet is drawn.

If either layer is insufficient — allowance exhausted, or funds/credit unavailable — the payment is declined. Both are decremented together, atomically, only on a successful payment. (An unfunded stored-value card has only Layer 1: the card balance is the money.)

Payment methods​

Four methods share the two-layer model. The difference is which control bucket and which funding source each one touches:

MethodLayer 1 · control decrementedLayer 2 · fundingRail / gatewayStatus
Company walletmonthly limit or cost centercompany walletinternalexisting
Credit cardmonthly limit or cost centercredit card2c2pexisting
QR codemonthly limit or cost centercompany walletinternal, vendor-presented QRnew
xperise cardcard balance (+ cost center under the cost-center model)company wallet or none (stored value)internal closed-group cardnew
  • With credit card, the real money comes from the card (settled via 2c2p) — the company wallet is not drawn; the employee's monthly limit or cost center is still decremented as policy.
  • QR is funded by the company wallet and draws against the operating-model bucket (monthly limit or cost center). The xperise card draws against its card balance (plus the cost center only under the cost-center model); its funding is optional — the company wallet, or none (the card balance is then stored value).
Key rules & remaining assumptions

Confirmed rules:

  • A company uses exactly one operating model — monthly limit or cost center, not both.
  • The xperise card decrements its card balance (Layer 1); its funding (Layer 2) is optional — company wallet or none (stored value). Under the cost-center model it also draws the cost center.
  • Transaction authentication for cards is the Cardholder Verification Method (CVM): a PIN or an OTP — one of the two, never both.
  • A card is assigned to one employee or to no-one. Assigned, it inherits the employee's cost center(s) and stays in sync (the employee's default cost center is used for card payments); unassigned = a bearer card (usable by holder + PIN), optionally linked to one cost center.

Still to confirm:

  • QR funding is the company wallet. If QR should also be payable by credit card (2c2p) or the xperise card, tell us and we'll add those combinations.
  • Credit card payments do not draw the company wallet (2c2p is the funding source).

How a payment is processed​

Every method runs the same authorize-both-layers → fund → commit sequence:

Two invariants keep this safe:

  • Idempotency keys on every state-changing call, so a retried request never double-charges or double-decrements.
  • Atomic dual decrement — the Layer 1 bucket and the Layer 2 balance are reserved together and committed together; a failure in either releases the other, so policy and money never drift apart.

Ledger & data model​

The company wallet is a real, double-entry ledger account (the source of truth for money). The control buckets are budgets/counters enforced at authorization — they cap spending but are not themselves money.

A wallet-funded payment posts at least a two-legged entry, plus the policy decrement:

QR payment: employee pays vendor 150,000₫ (funding = company wallet)
Layer 1 (policy): cost_center.used += 150,000 (or monthly_limit.used += 150,000)
Layer 2 (ledger): DEBIT company.wallet 150,000
CREDIT vendor.receivable 150,000

A credit-card payment records the policy decrement and books the vendor receivable, but the money leg is the 2c2p settlement, not the company wallet.

Services​

Fits the existing api-gateway / microservice style:

ServiceResponsibility
Identity / AuthEmployee & admin sessions, MFA, device binding (reuses the existing session service).
Policy / BudgetMonthly limits, cost centers, card balances: reserve/commit/release, and resets.
Ledger / WalletCompany wallet + company credit. Double-entry postings, balances, reconciliation.
Payment orchestratorThe authorize-both-layers → fund → commit state machine; refunds; reversals.
QR serviceCreates and resolves payment intents and their signed, single-use QR tokens.
Card servicexperise card issuance & lifecycle, tokenization vault, PIN/cryptogram, card balance.
2c2p connectorCredit-card authorization, capture, refund, and 3DS via the 2c2p gateway.
Merchant serviceVendor onboarding, API keys & secrets, webhooks, settlement/payout.
Risk / FraudVelocity & limit checks, step-up decisions, blocklists, freeze/lost-card.
NotificationPush/SMS confirmations & receipts (reuses the existing notification center).

Transaction state machine​

Every payment — wallet, credit card, QR, or xperise card — runs through the same states:

A refund credits both layers back — the vendor receivable/funding is reversed and the employee's allowance (monthly limit or cost center / card balance) is restored.

Where to go next​

  • QR-Code Payment — merchant-presented dynamic QR; deducts allowance + company wallet.
  • Card Payment — the xperise card; deducts card balance + company wallet.
  • Corporate Portal — where companies set the operating model, allowances, and funding.
  • Security & Trade-offs — security layers, 2c2p/credit-card handling, and UX decisions.