> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apocor.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Cards

> Issue, manage, and securely reveal cards.

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

## Lifecycle

```mermaid theme={null}
stateDiagram-v2
  [*] --> INACTIVE
  INACTIVE --> ACTIVE: activate / issue
  ACTIVE --> FROZEN: freeze
  FROZEN --> ACTIVE: unfreeze
  ACTIVE --> CLOSED: close
```

## Issue a card

**Prerequisites (in order):**

1. Applicant `status: APPROVED` and **`issuerKycReady: true`**
2. Funding **account** created (`POST /v1/accounts`)
3. **Cardholder** created (`POST /v1/cardholders`)
4. Issue card with body fields below

Supports **virtual** and **physical** cards, **debit (budget)** and **prepaid** programs (`product_type` on the program).

```bash cURL theme={null}
curl -s -X POST 'https://sandbox.apocor.ai/v1/cards' \
  -H 'Authorization: Bearer YOUR_TOKEN' -H 'Content-Type: application/json' \
  -d '{
    "program_id": "prog_abc123",
    "account_id": "acct_abc123",
    "cardholder_id": "ch_abc123",
    "form_factor": "VIRTUAL",
    "spend_limit_cents": 50000
  }'
```

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.

```bash cURL theme={null}
curl -s -X POST 'https://sandbox.apocor.ai/v1/cards/batch' \
  -H 'Authorization: Bearer YOUR_TOKEN' -H 'Content-Type: application/json' \
  -d '{
    "program_id": "prog_abc123",
    "account_id": "acct_abc123",
    "cardholder_id": "ch_abc123",
    "form_factor": "VIRTUAL",
    "cards": [
      { "label": "Ops card 1" },
      { "label": "Ops card 2" }
    ]
  }'
```

Poll batch progress:

```bash cURL theme={null}
curl -s 'https://sandbox.apocor.ai/v1/cards/batch/{task_id}?applicant_id=app_abc123' \
  -H 'Authorization: Bearer YOUR_TOKEN'
```

Delete up to 100 cards at once:

```bash cURL theme={null}
curl -s -X POST 'https://sandbox.apocor.ai/v1/cards/batch-delete' \
  -H 'Authorization: Bearer YOUR_TOKEN' -H 'Content-Type: application/json' \
  -d '{ "card_ids": ["card_1", "card_2"] }'
```

## Spend controls (MCC / consumption scenarios)

Configure issuer-level whitelist/blacklist rules for MCC codes, transaction scenarios, or currencies.

| Action          | Endpoint                                                                      |
| --------------- | ----------------------------------------------------------------------------- |
| List controls   | `GET /v1/cards/spend-controls?applicant_id=...&usage=MCC&list_type=BLACKLIST` |
| Create / update | `POST /v1/cards/spend-controls`                                               |
| Delete          | `DELETE /v1/cards/spend-controls?id=...&applicant_id=...`                     |
| Batch upsert    | `POST /v1/cards/spend-controls/batch`                                         |

`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`.

```bash cURL theme={null}
curl -s -X POST 'https://sandbox.apocor.ai/v1/cards/spend-controls' \
  -H 'Authorization: Bearer YOUR_TOKEN' -H 'Content-Type: application/json' \
  -d '{
    "applicant_id": "app_abc123",
    "usage": "MCC",
    "keywords": "7995",
    "list_type": "BLACKLIST",
    "card_ids": ["card_abc123"]
  }'
```

## Fund cards and accounts

| Action                      | Endpoint                                                                                    |
| --------------------------- | ------------------------------------------------------------------------------------------- |
| Fund prepaid card           | `POST /v1/cards/{id}/fund` — body `{ "amount": "25.00" }`                                   |
| Withdraw from prepaid       | `POST /v1/cards/{id}/defund`                                                                |
| Fund/deplete budget account | `POST /v1/accounts/{id}/transfers` — `{ "applicant_id", "direction": "in\|out", "amount" }` |
| List issuer budgets         | `GET /v1/accounts/{id}/budgets?applicant_id=...`                                            |

## Manage a card

| Action                     | Endpoint                                                                |
| -------------------------- | ----------------------------------------------------------------------- |
| Freeze                     | `POST /v1/cards/{id}/freeze`                                            |
| Unfreeze                   | `POST /v1/cards/{id}/unfreeze`                                          |
| Activate                   | `POST /v1/cards/{id}/activate` (physical: calls issuer activate)        |
| Close                      | `POST /v1/cards/{id}/close`                                             |
| Update label / spend limit | `PATCH /v1/cards/{id}`                                                  |
| Card transactions          | `GET /v1/cards/{id}/transactions` or `GET /v1/transactions?card_id=...` |
| Reveal details             | `GET /v1/cards/{id}/secure-details`                                     |

## Physical cards

| Action          | Endpoint                               |
| --------------- | -------------------------------------- |
| Ship            | `POST /v1/cards/{id}/physical/ship`    |
| Shipping status | `GET /v1/cards/{id}/physical/shipping` |
| Set PIN         | `PUT /v1/cards/{id}/pin`               |

## Cardholders

| Action | Endpoint                     |
| ------ | ---------------------------- |
| Create | `POST /v1/cardholders`       |
| List   | `GET /v1/cardholders`        |
| Get    | `GET /v1/cardholders/{id}`   |
| Update | `PATCH /v1/cardholders/{id}` |

## Sandbox testing

`POST /v1/sandbox/simulate` with `{ "type": "authorization\|refund\|reversal\|kyc_review", "card_id": "..." }` (sandbox issuer only).

## Revealing PAN & CVV securely

Full card numbers never pass through your servers. Request a **short-lived reveal token** and render the sensitive fields inside a PCI-compliant iframe.

```bash cURL theme={null}
curl -s 'https://sandbox.apocor.ai/v1/cards/card_abc123/secure-details' \
  -H 'Authorization: Bearer YOUR_TOKEN'
```

```json theme={null}
{ "data": { "revealToken": "rvl_9f8e...", "expiresIn": 300 } }
```

<Warning>
  A `revealToken` is single-purpose and expires in \~5 minutes. Never log it, and never attempt to fetch or store the raw PAN server-side.
</Warning>
