Cards link a bank account to the Visa or Mastercard rails. Banking issues both virtual cards (number generated immediately, usable for online purchases or pushed to a digital wallet) and physical cards (printed and shipped to the cardholder). Both types are linked to a checking-style account and operate against its available balance.
Card issuing requires sponsor bank support. Some sponsors only support virtual; some support both. Both Visa and Mastercard branding are configurable per card via cardBrand.
Issuing a card
/banking/cardsJWT| Field | Type | Description |
|---|---|---|
| bankAccountId* | string | The funding account. Must be |
| cardType* | 'virtual' | 'physical' | Virtual cards are issued instantly. Physical cards ship and require activation. |
| cardBrand* | 'visa' | 'mastercard' | Network branding. Must match what your sponsor supports. |
| cardholderName | string | Name as it appears on the card. Defaults to the holder's legal name. |
| dailySpendLimit | number | Max spend per UTC day. |
| monthlySpendLimit | number | Max spend per calendar month. |
| shippingAddress | object | Required for physical. |
curl -X POST https://appengine.appmint.io/banking/cards \
-H "orgid: $ORG" \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{
"bankAccountId": "acc_abc",
"cardType": "virtual",
"cardBrand": "visa",
"cardholderName": "Alice Doe",
"dailySpendLimit": 500.00,
"monthlySpendLimit": 5000.00
}'
A virtual card returns immediately with full PAN and CVV in the response (one-time exposure — store it client-side or push to the cardholder's wallet straight away). A physical card returns metadata only; the PAN never leaves the card factory.
Card types
Virtual
- PAN issued instantly.
- Usable for e-commerce, recurring billing, and digital-wallet provisioning.
- Can be replaced (re-issued with a new PAN) without shipping anything.
- A common pattern is to issue one virtual card per merchant or vendor for fraud isolation.
Physical
- Printed by the sponsor's card vendor.
- Status is
pendingfrom issuance until activated. - Activation requires the cardholder to confirm the last 4 digits printed on the physical card.
Activation (physical only)
/banking/cards/{id}/activateJWTBody: { last4: string }. Confirms the cardholder physically has the card. Until activation, the card cannot authorise transactions even with full PAN.
Virtual cards skip this step — they are active from issue.
Spend limits
/banking/cards/{id}/limitsJWTUpdate any of the four limits:
{
"dailySpendLimit": 1000.00,
"monthlySpendLimit": 10000.00,
"perTransactionLimit": 500.00,
"dailyAtmLimit": 300.00
}
| Limit | Meaning |
|---|---|
dailySpendLimit | Total purchase + cash-back per UTC day. |
monthlySpendLimit | Total per calendar month, resets at midnight UTC on the 1st. |
perTransactionLimit | Max single transaction. |
dailyAtmLimit | ATM withdrawal cap per day. |
Limits are enforced at authorisation time. A card with a $500 daily limit will decline the second of two $300 same-day transactions before the rail even sees it.
Card controls
Toggles that gate categories of transactions:
/banking/cards/{id}/controlsJWT{
"atmEnabled": true,
"onlineEnabled": true,
"internationalEnabled": false,
"contactlessEnabled": true
}
| Control | Effect when false |
|---|---|
atmEnabled | ATM withdrawals declined. |
onlineEnabled | Card-not-present (e-commerce) transactions declined. |
internationalEnabled | Non-domestic merchants declined. |
contactlessEnabled | NFC tap-to-pay declined; magstripe/chip still works. |
Defaults vary by sponsor — typically all enabled. The cardholder dashboard can flip these in real time, useful for travel or fraud-suspicion lockdown.
Lifecycle
pending → active → frozen ↔ active
↓
cancelled (terminal)
Freeze and unfreeze
/banking/cards/{id}/freezeJWTBody: { reason?: string }. A frozen card declines all authorisations but retains its number — useful for "I lost my card, but I might find it" cases. Customer-facing apps usually expose this as a toggle.
/banking/cards/{id}/unfreezeJWTRestores active.
Cancel
/banking/cards/{id}/cancelJWTBody: { reason: string }. Terminal — the card cannot be revived. Pending authorisations finish out, but no new authorisations succeed.
Replace
/banking/cards/{id}/replaceJWT{
"reason": "lost",
"shippingAddress": { "line1": "100 Main St", "city": "Brooklyn", "state": "NY", "postalCode": "11201", "country": "US" }
}
reason is lost | stolen | damaged. Replacing a card cancels the old one (terminal) and issues a new card with a new PAN. The new card inherits the old card's limits and controls. For stolen cards, the platform also tags the cancellation with a fraud flag for downstream review.
Reads
/banking/cardsJWT?accountId=acc_abc lists cards for a specific account; without it, returns aggregate stats.
/banking/cards/{id}JWTSingle card record with status, limits, controls, and last-4. Full PAN is never returned post-issuance — the only window is the original create response.
Authorisation flow
When a card is presented at a merchant:
- 1
Authorisation request
Network sends an authorisation message to the sponsor.
- 2
Limit and control checks
The platform's
CardAuthorizationServicechecks: status, limits (daily, monthly, per-transaction), controls (ATM/online/international/contactless), and available balance on the linked account. - 3
Hold placement
On approve, a hold equal to the auth amount is placed on the linked account. Available balance drops immediately.
- 4
Settlement
Hours to days later, the merchant captures. The hold converts to a posted debit. If the merchant doesn't capture, the hold expires (typically 7 days) and the balance is restored.
The card-authorisation service runs synchronously inside the request — it must respond within the network's authorisation window (typically under 2 seconds).
Stats
The list endpoint without accountId returns aggregate stats: total cards, by status, by type, by brand. Useful for admin dashboards.