Skip to main content
A card is issued to a cardholder against a funding account. Cards can be virtual or physical, and move through a simple lifecycle.

Lifecycle

Each transition emits a webhook (card.activated, card.frozen, card.unfrozen, card.blocked, card.closed) — but only when the status actually changes. Freezing an already-frozen card returns 200 without a duplicate event.

Issue a card

Prerequisites (in order):
  1. Applicant status: APPROVED (poll GET /v1/applicants/{id}/kyc-status or subscribe to applicant.status_changed). The applicant needs real firstName / lastName in data — the issuer rejects cardholders with empty or non-Latin names.
  2. Funding account created (POST /v1/accounts)
  3. Funds in place — issuance charges an opening fee from the card’s budget. Deposit stablecoins, then a single POST /v1/accounts/{id}/transfers direction: "in" converts the deposit and fills the budget. See Card funding.
  4. Cardholder created (POST /v1/cardholders)
  5. Issue card with body fields below
Supports virtual and physical cards, debit (budget) and prepaid programs (product_type on the program).
cURL
Issuance is asynchronous — you get 202 with an issuance_id:
202 Accepted
Then either poll GET /v1/cards/issuances/{issuance_id} or wait for the webhook: card.created on success, card.issuance.failed (with error, issuance_id, reference_id) on failure.
  • Idempotency-Key is required — omitting it returns 400 IDEMPOTENCY_KEY_REQUIRED. Retries with the same key + body replay the original response for 72 hours; a same-key request while issuance is in flight returns 409 with the issuance_id.
  • reference_id is optional — your own unique id per program + environment. Look up later with GET /v1/cards?reference_id=.
  • budget_id is optional (debit programs) — bind the card to a specific named budget; defaults to the applicant’s default budget. See Budgets.
Physical cards are created INACTIVE until shipped and activated.

Batch issue and delete

Batch issuance is asynchronous — the issuer returns a task_id you can poll. Up to 100 cards per request.
cURL
Poll batch progress:
cURL
Delete up to 100 cards at once:
cURL

Spend controls (MCC / consumption scenarios)

Configure issuer-level whitelist/blacklist rules for MCC codes, transaction scenarios, or currencies. usage is one of MCC, SCENARIO, or TRANSACTION_CURRENCY. For MCC rules, keywords must be a 4-digit MCC string (e.g. "7995"). Optionally scope rules to specific Apocor card_ids or issuer card_bin_ids.
cURL

Fund cards and accounts

fund, fund-from-wallet, and defund require an Idempotency-Key header. Successful funding emits card.funded; failures emit card.funding_failed.

Manage a card

Physical cards

Cardholders

Sandbox testing

POST /v1/sandbox/simulate (TEST keys / sandbox issuer only) drives fake spend through a real card so you can exercise your webhook handlers end to end.
cURL
Get relatedTransactionId from the transaction.authorized event’s data.cardTransactionId, or from GET /v1/cards/{id}/transactions.

Viewing full card details (PAN / CVV)

List and get card responses never include full PAN or CVV — only lastFour and similar safe fields. Apocor supports two reveal methods: Full walkthrough (SDK URLs, bootstrap example, RSA decrypt sample): Viewing card details (PAN / CVV). API Reference: group Cards — reveal PAN/CVV.