Cards
Managing the credit and debit card lifecycle through ORCA. The workflow covers cardholder verification, card issuance, activation, status management (lock / unlock), maintenance (limits, PIN), and transaction retrieval.
Business context
Card lifecycle management is traditionally fragmented across Core Banking systems, card processors (Fiserv, FIS, etc.), and network switches. Building card features — instant issuance of virtual cards, real-time freeze/unfreeze, dynamic limit changes — usually requires bespoke integrations against each of these systems.
ORCA exposes /cards and related endpoints as a single normalized REST surface. The fintech writes one integration to manage card issuance, status, limits, and transaction retrieval; ORCA fans out to the appropriate Core or processor.
Project decoupling
The full Cards capability is structured into two projects:
- Project 1 — Card Issuance & Activation (Steps 1–3): the "Day 1" experience of getting card credentials to the user.
- Project 2 — Card Servicing / Maintenance (Steps 4–5): "Day 2+" operations — lock/unlock, limit management, transaction history.
This page documents both, with Step 3 marking the boundary.
Scope
In-scope for this use case:
- Cardholder verification — locate the
personId(ororganizationIdfor business cards) - Card issuance — primary, authorized, joint cardholder types; credit, debit, prepaid funding sources; physical and digital (virtual-first) cards
- Card activation — transition from
IssuedtoActive - Status management — Lock (
Restricted,Suspended,Blocked), Unlock (Active), Close (Closed), Report lost/stolen (Lost,Stolen,HotCarded) - Maintenance — update limits (credit, daily withdrawal, daily purchase, ATM), PIN management (if supported by Core), update card art, update card metadata
- Card search — by
personId,accountId, masked PAN, status - Transaction retrieval — card-specific transactions for spend analysis
Out-of-scope (handled elsewhere):
- Physical card printing and fulfillment — the Core or card processor handles physical production and mailing; ORCA exposes only the issuance instruction
- End-user UI — mobile/web frontends consuming this API are the fintech's responsibility
- Network authorization / decline behavior at the switch — declines for locked cards happen at the switch layer based on the status ORCA has propagated; ORCA does not authorize transactions
- Fraud monitoring — performed by the Core, processor, or a dedicated fraud system
- Disputes and chargebacks — separate process, not covered here
- Card network rule conformance — Visa/Mastercard/AmEx specifications are enforced by the processor
Architecture context
sequenceDiagram
autonumber
participant FT as Fintech
participant ORCA as ORCA API
participant Core as FI Core /<br/>Card Processor
Note over FT: Step 1: Cardholder verification
FT->>ORCA: GET /persons (lookup)
ORCA->>Core: Customer read
Core-->>ORCA: Person data
ORCA-->>FT: 200 [Persons]
Note over FT,Core: Step 2: Issuance (Project 1)
FT->>ORCA: POST /persons/{personId}/cards (PaymentCardRequest)
ORCA->>Core: Issue card record
Core-->>ORCA: cardId, status=Issued
ORCA-->>FT: 202 {cardId, status: "Issued"}
Note over FT,Core: Step 3: Activation (Project 1)
FT->>ORCA: POST /cards/{cardId}/activations
ORCA->>Core: Activate card at switch
Core-->>ORCA: status=Active
ORCA-->>FT: 202 {status: "Active"}
opt Status changes (Project 2 — Lock/Unlock)
FT->>ORCA: PATCH /cards/{cardId} (status, statusReason)
ORCA->>Core: Update status at switch
Core-->>ORCA: Updated
ORCA-->>FT: 200 {PaymentCard}
end
opt Limit updates (Project 2)
FT->>ORCA: PATCH /cards/{cardId} (limits[])
ORCA->>Core: Update limits
Core-->>ORCA: Updated
ORCA-->>FT: 200 {PaymentCard}
end
opt Card lookup
FT->>ORCA: GET /persons/{personId}/cards
FT->>ORCA: GET /accounts/{accountId}/cards
FT->>ORCA: GET /cards/{cardId}
end
opt Transaction history
FT->>ORCA: GET /cards/{cardId}/transactions
ORCA->>Core: Card transactions read
Core-->>ORCA: Transactions
ORCA-->>FT: 200 [Transaction[]]
end
Endpoints used
| Step | Method | Path | Purpose |
|---|---|---|---|
| 1 | GET |
/persons |
Locate the cardholder |
| 2 | POST |
/persons/{personId}/cards |
Issue a card to a person |
| 2 | GET |
/persons/{personId}/cards |
List cards for a person |
| 2 | GET |
/accounts/{accountId}/cards |
List cards funded from an account |
| 2 | GET |
/cards |
Search cards (by masked PAN, etc.) |
| 3 | POST |
/cards/{cardId}/activations |
Activate an issued card |
| 4 | PATCH |
/cards/{cardId} |
Update status, limits, metadata |
| 4 | GET |
/cards/{cardId} |
Retrieve card detail |
| 4 | GET |
/cards/{cardId}/owner |
Retrieve the card's owner party |
| 4 | GET |
/cards/{cardId}/accounts |
Retrieve accounts linked to this card |
| 5 | GET |
/cards/{cardId}/transactions |
Card-specific transaction history |
Common headers
| Header | Purpose |
|---|---|
idempotencyId |
Required for all POST and PATCH (issuance, activation, status changes). Prevents duplicate cards from network retries. |
servicerId |
Identifies the servicing institution. |
Step 1 — Verify the cardholder
Cards are linked to a personId (or organizationId for business cards). Locate the cardholder before issuing. Same approach as Account Opening Step 1.
GET /persons?firstName.eq=Jane&lastName.eq=Doe&ssn.last4=6789 HTTP/1.1
The resulting personId is used in Step 2's path.
Step 2 — Issue the card (Project 1)
POST /persons/{personId}/cards → 202 Accepted with PaymentCard in the body.
Key request fields (PaymentCardRequest)
| Field | Required | Description |
|---|---|---|
productId |
recommended | Core- or processor-defined card product (e.g., PD_VISA_PLATINUM, PROD-DEBIT-VISA). |
cardHolderType |
recommended | Primary, Additional, Authorized, Guarantor. |
fundingSourceType |
recommended | Credit, Debit, Prepaid, Charge, DeferredDebit, CreditGateway, External. |
nameOnCard |
recommended | How the cardholder's name is embossed. |
businessNameOnCard |
conditional | Required for business cards (businessIndicator: true). |
businessIndicator |
no | true if this is a business card. |
digitalIndicator |
no | true for virtual-first issuance (no physical card mailed). |
relatedAccounts[] |
recommended | The funding/reference account(s). Each entry: accountId, accountRelationType: "FundingSource". |
relationshipId |
no | Customer relationship grouping ID (see Account Opening — Customer relationships). |
expiryDate |
no | YYYY-MM — typically assigned by the Core. |
startDate |
no | Effective date. |
limits[] |
recommended | Per-card limits — credit limit, daily withdrawal limit, daily purchase limit, etc. |
art |
no | Card art / visual design reference. |
pricingStrategyId |
no | Core-defined pricing strategy. |
securityCode |
no | CVV/CSC — typically generated by the Core, not supplied. |
pIN |
no | Initial PIN. Many Cores require separate PIN-set flow; supplying here is discouraged. |
codes[] |
no | Classifiers — ClassCode. |
supplementaryData |
no | Flex fields passed through to the Core. |
cardHolderType values
| Value | Meaning |
|---|---|
Primary |
Main cardholder for the account. |
Additional |
Additional card issued to the primary cardholder. |
Authorized |
Authorized user — a separate person with charging privileges, typically liable to the primary. |
Guarantor |
Cardholder whose creditworthiness backs the card. |
fundingSourceType values
| Value | Meaning |
|---|---|
Debit |
Debits the linked deposit account in real time. |
Credit |
Posts charges against a credit account; balance tracked separately. |
Prepaid |
Funded in advance; balance decremented at use. |
Charge |
Balance must be paid in full each cycle. |
DeferredDebit |
Debit with delayed settlement. |
CreditGateway |
Routes through a separate credit issuer. |
External |
Card issued by a third party, just registered in this Core. |
Limits structure
Each entry in limits[] is a Limit object:
- name: "CreditLimit" # PascalCase. Common: CreditLimit, DailyWithdrawalLimit,
# DailyPurchaseLimit, DailyATMLimit, MonthlyPurchaseLimit,
# SinglePurchaseLimit, NSF, UncollectedFunds, Overdraft.
limitType: "Maximum" # Maximum, Minimum, Notification
amount: "5000.00"
currency: "USD"
channelType: "OnlineATM" # Optional. OnlineATM, OfflineATM, POS, eCommerce, MOTO, etc.
enableIndicator: true
periodicity: "Daily" # Optional. Daily, Weekly, Monthly, Annually.
temporaryIndicator: false
Debit card example
POST /persons/person-7f3a8c92-4b1e-4d2f-9a0c-1b2c3d4e5f60/cards HTTP/1.1
Host: api.portx.io
Content-Type: application/json
idempotencyId: b2c3d4e5-f6a7-8b9c-0d1e-2f3a4b5c6d7e
servicerId: bank-001
{
"productId": "PROD-DEBIT-VISA",
"cardHolderType": "Primary",
"fundingSourceType": "Debit",
"nameOnCard": "Jane M Doe",
"digitalIndicator": true,
"relatedAccounts": [
{
"accountId": "acct-003-chk-1f2e3d4c",
"accountRelationType": "FundingSource"
}
],
"limits": [
{
"name": "DailyWithdrawalLimit",
"amount": "500.00",
"currency": "USD",
"channelType": "OnlineATM",
"periodicity": "Daily",
"enableIndicator": true
},
{
"name": "DailyPurchaseLimit",
"amount": "2500.00",
"currency": "USD",
"periodicity": "Daily",
"enableIndicator": true
}
]
}
{
"cardId": "card-2e3f4a5b-6c7d-8e9f-0a1b-2c3d4e5f6a78",
"cardHolderId": "person-7f3a8c92-4b1e-4d2f-9a0c-1b2c3d4e5f60",
"productId": "PROD-DEBIT-VISA",
"cardHolderType": "Primary",
"fundingSourceType": "Debit",
"nameOnCard": "Jane M Doe",
"digitalIndicator": true,
"number": "****-****-****-4321",
"expiryDate": "2030-05",
"startDate": "2026-05-19",
"brand": "Visa",
"status": "Issued",
"statusDate": "2026-05-19T14:42:11Z",
"relatedAccounts": [
{
"accountId": "acct-003-chk-1f2e3d4c",
"accountRelationType": "FundingSource"
}
]
}
Credit card example (with credit limit)
{
"productId": "PD_VISA_PLATINUM",
"cardHolderType": "Primary",
"fundingSourceType": "Credit",
"nameOnCard": "Jane M Doe",
"digitalIndicator": true,
"limits": [
{
"name": "CreditLimit",
"amount": "5000.00",
"currency": "USD",
"enableIndicator": true
}
]
}
Business card example
{
"productId": "PD_BIZ_MASTERCARD",
"cardHolderType": "Primary",
"fundingSourceType": "Credit",
"businessIndicator": true,
"nameOnCard": "Maria Garcia",
"businessNameOnCard": "Acme Industries LLC",
"relatedAccounts": [
{
"accountId": "acct-acme-op-001",
"accountRelationType": "FundingSource"
}
],
"limits": [
{ "name": "CreditLimit", "amount": "25000.00", "currency": "USD" }
]
}
Authorized user (additional cardholder)
{
"productId": "PD_VISA_PLATINUM",
"cardHolderType": "Authorized",
"fundingSourceType": "Credit",
"nameOnCard": "John Q Smith",
"relationshipId": "rel-1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"relatedAccounts": [
{
"accountId": "acct-credit-1234",
"accountRelationType": "FundingSource"
}
],
"limits": [
{ "name": "DailyPurchaseLimit", "amount": "1000.00", "currency": "USD", "periodicity": "Daily" }
]
}
Card statuses
| Status | Meaning |
|---|---|
AssignPIN |
Issued; awaiting PIN assignment. |
Issued |
Card record created. Not yet usable. |
Active |
Activated. Authorizations permitted. |
Inactive |
Pre-activation or deliberately inactive. |
Restricted |
Restricted from new authorizations (user-initiated lock). |
Blocked |
Blocked at the switch (typically issuer-initiated). |
Suspended |
Suspended pending review. |
Lost |
Reported lost. |
Stolen |
Reported stolen. |
HotCarded |
Hot-listed for immediate decline at the network. |
Expedite |
Expedited replacement in progress. |
Renewed |
Replaced by a renewed card. |
Expired |
Past expiry date. |
Closed |
Permanently closed. |
Denied |
Issuance denied. |
Step 3 — Activate the card (Project 1)
POST /cards/{cardId}/activations → 202 Accepted. Transitions the card from Issued to Active.
For virtual-first cards (digitalIndicator: true), activation typically runs immediately after issuance. For physical cards, activation is triggered when the user receives the card and confirms (via mobile app, IVR, or web).
POST /cards/card-2e3f4a5b-6c7d-8e9f-0a1b-2c3d4e5f6a78/activations HTTP/1.1
Content-Type: application/json
idempotencyId: c3d4e5f6-a7b8-9c0d-1e2f-3a4b5c6d7e8f
{
"identifiers": [
{ "schemeName": "ActivationCode", "number": "8842" }
]
}
{
"cardId": "card-2e3f4a5b-6c7d-8e9f-0a1b-2c3d4e5f6a78",
"status": "Active",
"statusDate": "2026-05-19T14:55:03Z",
"activationDates": [
"2026-05-19T14:55:03Z"
]
}
Activation code
Some Cores require an activation code (last 4 digits of SSN, CVV, etc.) supplied in identifiers[]. Others accept activation without a code when called from an authenticated channel. Check the Core's requirements.
Step 4 — Lifecycle management (Project 2)
All Day 2+ operations use PATCH /cards/{cardId} with application/merge-patch+json. The body contains only the fields being changed.
4.1 Lock a card (Disable / Freeze)
User-initiated lock when a card is misplaced. Switches to Restricted — new authorizations decline; existing recurring charges may or may not be blocked depending on statusReason.
PATCH /cards/card-2e3f4a5b-6c7d-8e9f-0a1b-2c3d4e5f6a78 HTTP/1.1
Content-Type: application/merge-patch+json
idempotencyId: d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f9a
{
"status": "Restricted",
"statusReason": "CardLostOrStolen"
}
{
"cardId": "card-2e3f4a5b-6c7d-8e9f-0a1b-2c3d4e5f6a78",
"status": "Restricted",
"statusReason": "CardLostOrStolen",
"statusDate": "2026-05-19T15:12:48Z"
}
4.2 Unlock a card (Enable / Unfreeze)
User found the card. Re-enable for authorizations.
{
"status": "Active",
"statusReason": "CustomerRequest"
}
4.3 Report lost / stolen
A more permanent status than Restricted. The card cannot be re-enabled; a replacement must be issued.
{
"status": "Lost",
"statusReason": "CardLostOrStolen"
}
For active fraud, HotCarded triggers immediate decline at the network across all merchants.
{
"status": "HotCarded",
"statusReason": "FraudSuspected"
}
4.4 Update limits
Replace the limits array. Like all merge-patch arrays, sending limits[] replaces the whole array — include any limits you want to keep.
{
"limits": [
{
"name": "DailyWithdrawalLimit",
"amount": "1000.00",
"currency": "USD",
"periodicity": "Daily",
"enableIndicator": true
},
{
"name": "DailyPurchaseLimit",
"amount": "5000.00",
"currency": "USD",
"periodicity": "Daily",
"enableIndicator": true
}
]
}
4.5 Temporary limit increase
Limit supports temporaryIndicator: true and a validityPeriod window:
{
"limits": [
{
"name": "DailyPurchaseLimit",
"amount": "10000.00",
"currency": "USD",
"periodicity": "Daily",
"enableIndicator": true,
"temporaryIndicator": true,
"validityPeriod": {
"fromDateTime": "2026-06-01T00:00:00Z",
"upToDateTime": "2026-06-15T23:59:59Z"
}
}
]
}
4.6 Close a card
{
"status": "Closed",
"statusReason": "CustomerRequest"
}
A closed card cannot be re-activated.
statusReason values
ActivationBeforeAvailableDate, CardRecordNotFound, CardLostOrStolen, NoActivationRequired, ActivationRequired, ExpDateNotMatch, CustomerRequest, FraudSuspected, DisputeInProgress, BlockedByPolicy, ReplacementIssued, AccountClosed.
Lookups
GET /cards/{cardId} # Card detail
GET /cards/{cardId}/owner # The cardholder party
GET /cards/{cardId}/accounts # Accounts linked to the card (funding sources)
GET /persons/{personId}/cards # All cards for a person
GET /accounts/{accountId}/cards # All cards funded from an account
GET /cards?status.eq=Active&cardHolderId.eq=person-... # General search
Step 5 — Card transaction history (Project 2)
GET /cards/{cardId}/transactions — useful for spend analysis on a per-card basis, especially for accounts with multiple cards (additional cards, joint cardholders, business cards).
Common query parameters
| Parameter | Description |
|---|---|
creationDate.gte, creationDate.lte |
Date range filter. |
amount.gte, amount.lte |
Amount range filter. |
status.eq |
Filter by transaction status (Booked, Pending, Memo). |
transactionType.eq |
Filter by transaction type. |
cursor, limit |
Cursor-based pagination. |
GET /cards/card-2e3f4a5b-6c7d-8e9f-0a1b-2c3d4e5f6a78/transactions?creationDate.gte=2026-05-01&limit=20 HTTP/1.1
[
{
"transactionId": "txn-card-9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d",
"amount": "42.18",
"currency": "USD",
"creditDebitIndicator": "Debit",
"status": "Booked",
"transactionType": "Purchase",
"creationDate": "2026-05-18T18:23:04Z",
"merchant": {
"name": "Acme Coffee Co",
"mcc": "5814",
"city": "Austin",
"country": "US"
}
},
{
"transactionId": "txn-card-8b7c6d5e-4f3a-2b1c-0d9e-8f7a6b5c4d3e",
"amount": "200.00",
"currency": "USD",
"creditDebitIndicator": "Debit",
"status": "Booked",
"transactionType": "ATMWithdrawal",
"creationDate": "2026-05-15T11:08:55Z"
}
]
Error handling
| Status | When |
|---|---|
400 Bad Request |
Schema validation failure: missing required field, invalid fundingSourceType, malformed limits[]. |
404 Not Found |
cardId or personId doesn't exist. |
409 Conflict |
Idempotency collision; activation attempt on an already-active card. |
422 Unprocessable Entity |
Business-rule rejection: status transition not allowed (e.g., reactivate a Closed card), limit exceeds product ceiling. |
500 Internal Server Error |
Unexpected ORCA or Core failure. |
502 Bad Gateway |
Card processor unreachable. |
Edge cases and caveats
Idempotency is required
Network retries on POST /persons/{personId}/cards without an idempotencyId cause duplicate cards to be issued. The Core may or may not deduplicate. Always send idempotencyId.
Status transitions are not all allowed
The Core enforces a state machine. Common forbidden transitions: Closed → anything else, Lost / Stolen → Active, Expired → Active. To recover from a terminal state, issue a replacement card and link via supplementaryData if needed.
Limits array replaces wholly
Merge patch on limits[] replaces the entire array. Always send the complete list, not just changed entries — otherwise pre-existing limits are lost.
PIN management varies by Core
Many Cores route PIN set/change through a separate secure channel (HSM-backed) and reject pIN field on the issuance request. Don't supply PINs unless the integration team confirms the Core supports it.
Activation propagation lag
POST /cards/{cardId}/activations returns 202 once the Core accepts the activation. The card may be in Active state in the Core but the network switch may take a few seconds to propagate. Time-sensitive Day-1 spend may see early declines; advise users accordingly.
Card art and physical fulfillment
art and digitalIndicator: false configure how the physical card is produced and mailed by the Core or its fulfillment vendor. ORCA does not manage fulfillment timelines or shipment tracking; check the Core's fulfillment status separately if needed.
Authorized users and account ownership
cardHolderType: "Authorized" issues a card to a person who is not the account owner. The authorized user's spend posts to the primary cardholder's account. The authorized user does not automatically gain account-level access.
Masked PAN only
PaymentCard.number is the masked Primary Account Number (PAN), typically formatted as ****-****-****-1234. The full PAN is never returned by ORCA. Card production/delivery surfaces the full PAN through a secure channel (printed card, virtual card display in a PCI-compliant viewer).
Related building blocks
- Account Opening — Linking a card to a funding account requires the account to exist first. See Account Opening.
- Customer Relationships —
relationshipIdgroups cards under a household or business relationship. See Account Opening — Customer relationships.