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 (or organizationId for business cards)
  • Card issuance — primary, authorized, joint cardholder types; credit, debit, prepaid funding sources; physical and digital (virtual-first) cards
  • Card activation — transition from Issued to Active
  • 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}/cards202 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}/activations202 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 / StolenActive, ExpiredActive. 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