> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.thepennyinc.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.thepennyinc.com/_mcp/server.

# Cards & Cardholders

Issuing a card involves three things working together: a **Cardholder** (who the card belongs to), a **Card Product** (the template it's issued from), and the **Card** itself.

## Cardholders

A cardholder is a person or a business you're issuing cards to:

* **Individual** — a natural person, identified by name, email, and address
* **Corporate** — a business, for cards issued to an organization rather than a person

Create one with `POST /cardholders/individual` or `POST /cardholders/corporate`. Requests take an optional `phone_number` and an `address` with `line_1`, `line_2` (optional), `city`, `state_or_province` (an ISO 3166-2 code such as `CA`, required for countries that use subdivisions), `post_code`, and `country` (ISO 3166-1 alpha-2). In responses, the phone number is returned as `phone` and the postal code as `zip_code`.

Cardholder PII — `given_name`, `family_name`, `email`, `phone`, and the address `line_1`, `line_2`, and `zip_code` — is masked by default everywhere a single cardholder is returned (create, get, update, activate, deactivate, terminate, and history). Pass `?reveal_sensitive=true` to get the real values back:

**`GET /cardholders/{cardholder_id} (default, masked)`**

```json title="GET /cardholders/{cardholder_id} (default, masked)"
{
  "cardholder_id": "cardholder_01937e19-4ebb-75bd-8250-4ebb5bd25085",
  "version": 1,
  "version_time": "2026-01-15T18:32:00Z",
  "business_id": "business_01937b95-484e-75af-8c68-484e5afc68d3",
  "business_entity_id": "business_entity_01937c9d-3a1e-72b0-8881-3a1e2b088159",
  "program_id": "program_019377de-7f88-7f02-894f-7f88f0294fcb",
  "status": "active",
  "active": true,
  "address": {
    "line_1": "**********",
    "line_2": "**********",
    "city": "San Francisco",
    "state_or_province": "CA",
    "zip_code": "**********",
    "country": "US"
  },
  "email": "**********",
  "phone": "**********",
  "type": "individual",
  "given_name": "**********",
  "family_name": "**********"
}
```

**`GET /cardholders/{cardholder_id}?reveal_sensitive=true`**

```json title="GET /cardholders/{cardholder_id}?reveal_sensitive=true"
{
  "cardholder_id": "cardholder_01937e19-4ebb-75bd-8250-4ebb5bd25085",
  "version": 1,
  "version_time": "2026-01-15T18:32:00Z",
  "business_id": "business_01937b95-484e-75af-8c68-484e5afc68d3",
  "business_entity_id": "business_entity_01937c9d-3a1e-72b0-8881-3a1e2b088159",
  "program_id": "program_019377de-7f88-7f02-894f-7f88f0294fcb",
  "status": "active",
  "active": true,
  "address": {
    "line_1": "1 Market St",
    "line_2": "Suite 400",
    "city": "San Francisco",
    "state_or_province": "CA",
    "zip_code": "94105",
    "country": "US"
  },
  "email": "jordan.rivera@acme.example",
  "phone": "+15551234567",
  "type": "individual",
  "given_name": "Jordan",
  "family_name": "Rivera"
}
```

`GET /cardholders/` (list) doesn't accept `reveal_sensitive`: list results are always masked, so cardholder PII can't be read in bulk. Fetch a cardholder individually with `reveal_sensitive=true` when you need the real values.

A cardholder moves between `active`, `deactivated`, and `suspended`. Terminating a cardholder (`DELETE /cardholders/{cardholder_id}`) moves it to `deleting` and then `deleted`, which is permanent.

You can attach a [Spend Control](/spend-controls) directly to a cardholder so it applies across every card they hold. Assign or replace it with `PUT /cardholders/{cardholder_id}/spend_control` (body `{"spend_control_id": "..."}`) and remove it with `DELETE /cardholders/{cardholder_id}/spend_control`, both on the Issuing API.

## Card Products

A Card Product is the template a card is issued from. It determines the card's form factor, its usage type, how its expiration date is set, and which BINs and BIN ranges it can be issued under. Card products are configured for your business by Penny; list the ones available to you:

```http
GET /products/
GET /products/{card_product_id}
```

Penny chooses the BIN and BIN range for each card from the product's configuration. The card's `bin_id` and `bin_range_id` show which were used.

### BINs and BIN ranges

A **BIN** (Bank Identification Number) is the first digits of a card number (6–8 digits); it identifies the card's issuer and network. A **BIN range** is a sub-range of card numbers within a BIN, with its own currency and its own capabilities: contactless payments, e-commerce, international acceptance, supported form factors, and supported usage types.

Look these up when you need to know what a card issued from a given BIN or range can do.

```http
GET /products/{card_product_id}/bins/{bin_id}
GET /products/{card_product_id}/bins/{bin_id}/ranges
GET /products/{card_product_id}/bins/{bin_id}/ranges/{bin_range_id}
```

`GET /products/{card_product_id}/bins/{bin_id}` returns the BIN itself. `number` is the same value you see as `bin` on a card:

**`A BIN`**

```json title="A BIN"
{
  "bin_id": "bin_01937000-0592-7190-87e7-05921907e7c5",
  "version": 1,
  "version_time": "2026-01-15T18:32:00Z",
  "number": "424242",
  "country": "US",
  "scheme": {
    "network": "visa",
    "funding_type": "debit",
    "product_type": "classic"
  },
  "active": true,
  "status": "active"
}
```

`GET /products/{card_product_id}/bins/{bin_id}/ranges` lists every range configured for that BIN on the product; `GET .../ranges/{bin_range_id}` returns a single one. Both return the same shape:

**`A BIN range`**

```json title="A BIN range"
{
  "bin_range_id": "bin_range_01937b28-f048-77de-8ef4-f0487deef42d",
  "version": 1,
  "version_time": "2026-01-15T18:32:00Z",
  "bin_id": "bin_01937000-0592-7190-87e7-05921907e7c5",
  "active": true,
  "status": "active",
  "currency": "USD",
  "capabilities": {
    "contactless_payments": true,
    "ecommerce_enabled": true,
    "international": {
      "card_present_enabled": true,
      "card_not_present_enabled": true,
      "cross_border_authorization_enabled": false
    },
    "supported_form_factors": ["virtual"],
    "supported_usage_types": ["reloadable"]
  }
}
```

`supported_form_factors` lists the card form factors a range can issue. Today this is `virtual`.

`status` is one of `reserved`, `active`, `deactivated`, or `deprecated` for both a BIN and a BIN range, alongside an independent `active` flag. Issue new cards only against a BIN and range that are `active`.

## Cards

A card is issued from a product to a cardholder and draws funds from a Capital Account. You can also scope its spend with a Control Account, which holds no balance of its own (see [Accounts](/banking/accounts)). Cards are created with `POST /cards/virtual`, and every card needs a cardholder: pass either an existing `cardholder_id` or an inline `cardholder` object to create the cardholder and the card in one call. See [Issuing a Card](/issuing/issuing-a-card) for the full request shape.

Card reads include the BIN, the last four digits, and the `expiration_date`, but never the full card number or CVV. The unmasked PAN is available only from the separate, highly sensitive `POST /cards/{card_id}/reveal` endpoint, which requires the `card:reveal` permission and returns `card_id`, `pan`, `cvv`, `expiration_month`, and `expiration_year`.

**`A virtual card`**

```json title="A virtual card"
{
  "card_id": "card_019375de-a2a0-7f31-884a-a2a0f3184abd",
  "version": 1,
  "version_time": "2026-01-15T18:32:00Z",
  "issued_time": "2026-01-15T18:32:00Z",
  "expiration_date": "2030-06-30",
  "bin_id": "bin_01937000-0592-7190-87e7-05921907e7c5",
  "bin_range_id": "bin_range_01937b28-f048-77de-8ef4-f0487deef42d",
  "bin": "424242",
  "last_four": "4242",
  "card_product_id": "card_product_01937f5d-a015-7a55-818b-a015a5518b97",
  "business_id": "business_01937b95-484e-75af-8c68-484e5afc68d3",
  "business_entity_id": "business_entity_01937c9d-3a1e-72b0-8881-3a1e2b088159",
  "program_id": "program_019377de-7f88-7f02-894f-7f88f0294fcb",
  "capital_account_id": "account_019372e3-b8dc-7de2-80b6-b8dcde20b6c9",
  "control_account_id": "account_019372e3-9f4a-7c1b-9a3d-9f4a7c1b9a3d",
  "cardholder_id": "cardholder_01937e19-4ebb-75bd-8250-4ebb5bd25085",
  "status": "active",
  "active": true,
  "terminated": false,
  "currency": "USD",
  "country": "US",
  "form_factor": "virtual",
  "usage_type": "reloadable",
  "scheme_details": {
    "network": "visa",
    "funding_type": "debit",
    "product_type": "classic"
  },
  "alias": "Marketing Team Card",
  "spend_control_id": "spend_control_019379d9-a170-796b-867a-a17096b67a21"
}
```

Assign or replace a card's spend control with `PUT /cards/{card_id}/spend_control` (body `{"spend_control_id": "..."}`) and remove it with `DELETE /cards/{card_id}/spend_control`, both on the Issuing API.

### Usage types

A card's `usage_type` comes from its card product and can't be changed after issuance. The product's usage type must be listed in the BIN range's `supported_usage_types`. Penny enforces each usage type on every authorization, alongside the card's spend controls.

| Type            | Behavior                                                                                                                                                                                                                                                                                                                                          |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `single_use`    | The card approves one authorization. If that authorization expires or is cancelled before it settles, the card can be used again. The first settlement terminates the card, and the card is also closed at the card issuer automatically. A settlement that arrives without a prior authorization counts as the card's use.                       |
| `single_reload` | The card has a lifetime budget, set with `load_amount` when the card is created. Approved authorizations and settled spend count against it; authorizations that expire or are cancelled return their amount. An authorization larger than the remaining budget is declined. The budget can't be raised, and the card stays open when it's spent. |
| `reloadable`    | The card can be reused without a usage limit, subject to its spend controls.                                                                                                                                                                                                                                                                      |

Cards with a `single_use` or `single_reload` usage type include a read-only `usage_limits` object:

**`usage_limits on a single_reload card`**

```json title="usage_limits on a single_reload card"
"usage_limits": {
  "authorizations_maximum": null,
  "authorizations_used": null,
  "amount_limit": "250.00",
  "amount_remaining": "180.00"
}
```

On a `single_use` card, `authorizations_maximum` is `1` and `authorizations_used` shows whether the use is taken; the amount fields are `null`. Amounts are in the card's `currency`.

### Lifecycle

A new card is `active` as soon as it's issued, or `deactivated` if you create it with `"active": false`. From there it can move between `active`, `suspended` (temporary), and `deactivated`. Terminating a card (`DELETE /cards/{card_id}`) sets it to `terminated`, which is permanent: use it only when a card should never be used again, not for a temporary pause.

See [Issuing a Card](/issuing/issuing-a-card) for a full walkthrough from cardholder to first transaction.