Card provisioning — business rules
The constraints, state-machine rules, and validation logic governing card provisioning to a wallet.
These rules govern the Card Provisioning API. For the operations themselves and sample requests, see Card Provisioning.
LINKED vs COSMETIC
The state parameter on /register controls how strictly the card is bound to the wallet:
| State | Behaviour |
|---|---|
| LINKED (default) | Hard binding. The PAN / account number can't be registered to any other MSISDN until it's delinked from this one. Use for cards a customer has confirmed they own. |
| COSMETIC | Soft binding. The card appears in the wallet, but the same PAN can still be registered to other MSISDNs. Auto-promoted to LINKED after the first successful transaction. Use when you want to display a card before validation is complete. |
If you don't specify state, it defaults to LINKED.
Validation methods
The validationMethod parameter controls how the customer confirms ownership of the card when registering:
| Method | Behaviour |
|---|---|
| (not sent) | No validation. Card is linked immediately and silently. The simplest path — use when the wallet has already authenticated the cardholder elsewhere (e.g. a bank app authenticating from its own session). |
| SIMPLE | Customer is prompted with a yes/no confirmation. "Yes" → card moves to LINKED. "No" → card is delinked, and the PAN becomes available for other wallets. |
| DOB | Customer is prompted to enter their date of birth. Compared against the dateOfBirth supplied on /register. Match → LINKED. Mismatch → delinked. |
If you send validationMethod: DOB, you must supply dateOfBirth on the same request. Sending DOB without dateOfBirth is rejected.
Already-linked behaviour
The platform distinguishes between three "already exists" cases:
| Scenario | Result returned |
|---|---|
Same accountNumber + same msisdn | CARD LINKED TO PROFILE — idempotent no-op |
Same accountNumber + different msisdn, current state LINKED | ALREADY LINKED — registration rejected |
Same accountNumber + different msisdn, current state COSMETIC | Allowed — the new registration overrides if its state is LINKED |
This means a customer can't add a card that's hard-linked to someone else's wallet, but COSMETIC placeholders don't block legitimate ownership claims.
Update constraints
| Field | Updatable via /update? |
|---|---|
expiryDate | Yes |
imageId | Yes |
cardholderName | Yes |
node | No — register-time only |
validationMethod | No — register-time only |
state | No — use /block//unblock to transition |
accountNumber | No — delink and re-register |
msisdn | No — delink and re-register under the new MSISDN |
The update request must supply at least one of expiryDate, imageId, or cardholderName. A request with none of these is rejected.
State transitions
The card-state machine has four states. Only certain transitions are allowed:
| From | To | Trigger |
|---|---|---|
| (new) | LINKED | /register with state: LINKED or no state |
| (new) | COSMETIC | /register with state: COSMETIC |
COSMETIC | LINKED | First successful transaction on the card |
LINKED | BLOCKED | /block |
BLOCKED | LINKED | /unblock |
LINKED | DELINKED | /delink |
BLOCKED | DELINKED | /delink |
DELINKED | (any) | Re-/register (creates a fresh link) |
/update on a BLOCKED card returns SUCCESS but the card remains BLOCKED. The mutation is applied; the state isn't changed.
/update on a DELINKED card returns CARD DELINKED — no mutation. Re-register first.
Account-type requirements
Some BINs (typically debit cards) require an account type at register-time. The behaviour is:
account supplied? | BIN requires it? | Behaviour |
|---|---|---|
Yes, valid (10/20/30) | Yes | Honoured |
| Yes, valid | No | Stored but ignored |
| Yes, invalid value | Yes | Defaults to 30 (Credit) |
| No | Yes | Returns MISSING ACCOUNT |
| No | No | Card registered without an account type |
Use /binLookup (on the Remote API) to discover whether a BIN requires an account type before calling /register.
Brand indicators (card art)
| Rule | Detail |
|---|---|
| Scope | Each imageId is scoped to your wallet provider. Other wallets can't see yours. |
| Reusable | One imageId can be referenced by many /register calls — typically one image per card product / tier. |
| Description limit | 30 characters max. Anything longer is rejected. |
| Recommended dimensions | 300×190 px, PNG, < 100 KB |
| Format | Base64-encoded byte array on the wire |
Once registered, an imageId can be referenced for the life of your wallet provider profile. There's no expiry, but you can replace the underlying image by uploading a new indicator with the same description (a new imageId is generated).
Node assignment
The node parameter tells the platform which acquirer / bank scheme the card should route through.
| Rule | Detail |
|---|---|
| Optional | If not sent, the platform infers a node from the BIN. |
| Auto-create | If the supplied node doesn't exist, it's created dynamically on the MRA backend. |
| Consult your service provider | Don't guess node names. Speak to your account manager before using a node value that isn't in your existing config. |
| Common values | SBSA (Standard Bank), ABSA, NEDBANK, FNB, CAPITEC |
Once a card is registered with a node, it can't be changed via /update. To move a card to a different node, delink and re-register.
Limits and quotas
| Limit | Default |
|---|---|
| Cards per wallet (MSISDN) | Set per-wallet-brand by Operations. Typical default: 5 |
| Brand indicators per provider | No hard cap, but practical recommendation: < 100 |
| Concurrent registration requests for same MSISDN | Serial — second request blocks until first completes |
If a customer hits the cards-per-wallet limit, MAX CARDS LINKED is returned. The wallet UI should offer to delink an existing card before registering another.
PII and data handling
| Rule | Detail |
|---|---|
| PAN is stored hashed and BIN-tagged | Scan to Pay vaults the PAN. Your wallet only needs to keep the last 4 digits client-side for display. |
| No CVV at provisioning | CVV is not collected by Card Provisioning. The wallet supplies CVV at purchase time (if the BIN requires it). |
| PCI scope | Treat any handling of accountNumber in your wallet as PCI-relevant. Use a PCI-compliant SDK / tokenisation flow if you don't want PCI scope. |
| Cardholder name | Treated as PII. Don't log on the client. |
| Date of birth | When used with validationMethod: DOB, store as transient — discard after the validation flow completes. |
Sharing card details with the support team for debugging must follow the PII restrictions documented in Query resolution — business rules.
What's next
- Operations and sample requests → Card Provisioning
- Use a provisioned card to pay → Purchase flow
- Remote API authentication → Authentication
- Card data restrictions in support tickets → Query resolution — business rules
Updated 2 days ago
