A detailed walkthrough of issuing a card — the form, its field-level logic, the branching, and
the end-to-end sequence — so a design can be double-checked against it. It builds on the
Card Management spec, the two-layer model,
and card activation. Endpoint shapes are illustrative.
"Issue card" is the process of creating a new card, configuring it, assigning it (or leaving it as
a bearer card), and activating it. It has two entry points that can combine:
Issue virtual card — created instantly, lives in the app.
Order physical cards — a production batch; can be single or bulk.
A card's form can be physical, virtual, or both.
Role
Issue cards?
Super admin / Card manager
✅ create, configure, assign, activate
Finance / approver
approves balance/limit above threshold & large orders
Assignment is a binary choice: bind the card to one employee, or leave it unassigned = a
bearer card (usable by whoever holds it + knows the PIN). Never more than one employee. Picking
bearer forces cvm = pin and shows the optional single cost-center picker; picking an
employee enforces the hard cap and inherits the employee's default cost center.
Field
Required
Options
Conditional / validation
assignment
Yes
employee | bearer (bearer = no-one)
—
employeeId
if employee
employee picker
employee must be active; hard cap on cards/employee enforced
C. Cost center (Layer 1, only under the cost-center operating model)
Field
Required
Options
Conditional / validation
costCenters
auto
—
assigned → inherited from the employee (read-only, picker hidden, kept in sync); if the employee has several, the default cost center is used
costCenterId
optional
single cost-center picker
bearer only (picker shown only here); at most one; hidden under the monthly-limit model
The form's answers drive the outcome. Key rules (enforced server-side, not just UI):
form — at least one of physical/virtual; both may be selected for one card.
assignment = employee → require employeeId; check the hard cap; inherit the
employee's cost center(s) and hide the cost-center picker — if the employee has several, use
the default; allow employee_claim / admin_full.
assignment = bearer → no employee; force cvm = pin; show the cost-center picker for
an optional singlecostCenterId (cost-center model only); activation is bearer_admin.
Operating model — cost-center fields apply only under the cost-center model; under the
monthly-limit model they are hidden (a card never draws the monthly limit).
cvm = otp requires an assigned employee with a registered channel → invalid for bearer.
fundingSource = none → the card is stored value; allocating the balance / topping up
debits the company wallet and loads value onto the card; at spend time no wallet is drawn.
fundingSource = company_wallet → the card balance is a spend limit; funds are drawn from
the wallet at spend time (the wallet/credit must have headroom).
Approval — cardBalance or limits above the configured threshold, or a large physical
quantity, routes to a finance/approver before the card is created/activated.
Virtual cards reveal credentials only in the app; physical cards enter production and
ship (ISSUED under a batchId).
For bearer and physical variants the tail differs: a bearer card skips the employee claim
(admin sets the PIN → ISSUED → ACTIVE); a physical card is produced and shipped before activation
(see card activation).
A physical card is produced in a batch and shipped, so issuing it is a longer, asynchronous
flow than a virtual card: assignment and activation usually happen after the cards are in hand.
Every card in the batch stays ISSUED (inactive) through production and shipping — it can't move
money until it is delivered, assigned (or left bearer), and activated.
This is the customer / admin side
For what happens inside xperise behind these milestones — token provisioning, HSM key
management, the personalization bureau, and logistics — see
Physical Card Production (issuer side).
Place the order — quantity; personalization (blank vs pre-printed name); shipping
address(es) + contact; per-card policy defaults (balance + reset, funding source, CVM,
limits, channels); and an optional pre-assignment CSV (card slot → employee).
Approval — a large quantity or high aggregate value routes to a finance/approver first.
Create the batch — cards are created ISSUED under a batchId; the batch enters production.
Track fulfillment — the batch moves through the states below; the admin can watch progress in
the portal.
Receive & distribute — on delivery the admin marks the batch Delivered and hands cards
out.
Assign — map each card to one employee (single or bulk CSV) → ASSIGNED, or leave it
a bearer card. (Skipped if the batch was pre-assigned at order time.)
Activate — employee-claim (scan/tap + OTP + set PIN), admin full-activation, or, for bearer,
admin sets the PIN → ACTIVE. Only now is the card spendable.
The same form runs in bulk via CSV (one row per card: form, employee-or-bearer, balance, reset,
funding, CVM, limits). Validation returns a per-row report (created / pending-approval / error);
the hard cap and CVM/funding rules are enforced per row.
Under the cost-center model, if an employee has multiple cost centers, which one does a card
payment draw?Resolved: the employee's default cost center.
For a stored-value (unfunded) card, is the balance loaded from the company wallet at issue,
or can it be loaded from another source?
Should bulk issue support mixing employee-assigned and bearer cards in one file (assumed
yes)?
A self-contained, interactive copy of the screen is kept in the repo at
design-mockups/issue-virtual-card.html (open it locally in a browser). It is intentionally
not part of the deployed site build.
A two-column screen inside the corporate portal shell (top bar with company switcher + admin, left
nav with Cards active, breadcrumb Cards › Issue virtual card):
Left — the form, in 4 numbered steps:
Employee — searchable dropdown; shows a live "holds N of 3 cards" line and a red
hard-cap warning when the employee is at the cap (Issue disabled).
Card balance & funding — initial balance ($); Funding source = Company wallet(spend limit drawn at pay time) / None(prepaid stored value); Balance reset =
Day of month / No reset, with "Top-up is always available regardless of reset setting."
Limits & controls — per-transaction / daily / monthly caps; Cost center(inherited,
read-only on the employee path; a picker only for bearer cards); CVM = PIN / OTP
("one of two, never both"); Payment channels = contactless tap,
printed QR, manual entry (tap + QR on by default).
Right — sticky summary: a virtual card preview (holder + balance) and a Summary panel
(employee, card form, balance, funding, reset, CVM, cost center, activation), an info note that
credentials appear only in the employee's app after they claim it, and Issue card +
Save as draft buttons. An approval note appears when the balance is above the threshold.
✅ Consistent with this flow: hard cap, funding (wallet/none/stored-value), reset
(day-of-month/none + always-available top-up), CVM (PIN/OTP), channels, activation variants, and
the "credentials only in-app" rule.
✅ Resolved (cost center): for an employee-assigned card the cost center is inherited and
the picker is hidden (option a); the manual picker is shown only for bearer cards
(option c). When the employee belongs to multiple cost centers, one is the default and the
card uses that default. The mockup now shows an inherited, read-only "Cost center (inherited)"
field on the employee path.
Scope: the mock is the virtual + employee path. It doesn't cover bearer cards,
physical orders, the card-form (physical/virtual/both) selector, or expiry — those are
in this spec and the Card Management spec and would extend the screen.