Issuing a Card
This walks through issuing a virtual card to a new individual cardholder, drawing funds from an existing Capital Account, and putting a spend control on it. See Cards & Cardholders first if these terms are new.
All requests go to Penny Issuing (https://issuing.sandbox.api.thepennyinc.com in sandbox), except creating the spend control, which lives on Penny Banking. Assigning a spend control to a card or cardholder happens on Penny Issuing.
1. Create a cardholder (optional)
Every card needs a cardholder. Skip this step if you already have a cardholder_id. You can also skip it when creating a new cardholder and card together: in the POST /cards/virtual request in step 3, replace cardholder_id with an inline cardholder object. For an individual, add this object alongside the other card fields:
Supply exactly one of cardholder_id or cardholder. The examples in step 3 use the ID returned by the separate cardholder request below.
The address takes line_1, an optional line_2, city, state_or_province (an ISO 3166-2 code, required for countries that use subdivisions), post_code, and country (ISO 3166-1 alpha-2). You can also pass an optional phone_number. Cardholder responses return these as phone and, in the address, zip_code.
The cardholder is created in your default program and business entity, and the response includes the program_id and business_entity_id it was assigned.
2. Create a spend control (optional)
Skip this if you’re attaching an existing one. This example limits debit transactions to between $10 and $500 — see Spend Controls for the full set of rule types.
3. Issue the card
Cards are issued with POST /cards/virtual. The request needs a card_product_id, a capital_account_id, and a cardholder (cardholder_id or an inline cardholder). Optional fields include control_account_id, spend_control_id, alias, description, expiration_date, and active.
If the card product’s usage_type is single_reload, also send load_amount: the card’s lifetime budget, as a decimal string in USD (for example "250.00"). It’s required for single_reload products and rejected with a 422 for any other usage type. See Usage types for how each type is enforced.
The examples below use the cardholder_id returned by step 1. If you skipped that step, use an existing ID or the inline cardholder payload shown there.
The card number is never part of the request. Penny chooses the BIN and BIN range from the card product and generates the card number, including the last_four you’ll see on the card object afterward.
A new card is active as soon as it’s issued and can authorize transactions straight away. Pass "active": false to issue it deactivated and activate it later.
To change the card’s spend control later, call PUT /cards/{card_id}/spend_control on Penny Issuing with {"spend_control_id": "..."}, or DELETE /cards/{card_id}/spend_control to remove it.
4. Confirm it
Read the card back and check its status:
Revealing full card details (optional)
The card object returned above, like every other card read, includes the expiration_date, bin, and last_four, but never the full card number or CVV. If you need the unmasked PAN (for example, to display it once to the cardholder), call the dedicated reveal endpoint. It requires the card:reveal permission, which wildcards don’t grant:
This is a separate, highly sensitive, separately audited operation — deliberately kept apart from the reveal_sensitive query parameter used elsewhere in the API (see Cards & Cardholders), so that reading a raw card number always requires an explicit, dedicated call rather than a flag on a routine read. Call it only when you need the full number.
Next steps
- Setting Spend Controls — update limits after the fact, or share one control across many cards
- Reading Transactions & Ledger Entries — see the card’s activity as it happens
- Subscribing to Webhooks — get a
card.issuedevent the moment a card like this one comes online, instead of polling for it