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

# Create a virtual card

POST https://issuing.sandbox.api.thepennyinc.com/cards/virtual
Content-Type: application/json

Issue a virtual card under an existing card product. For a `single_reload` product, set `load_amount` to the card's lifetime budget.

Required permissions: `card:create`.

Reference: https://docs.thepennyinc.com/issuing/api-reference/cards/virtual/create

## Authentication

- `Authorization` header (bearer token, required) — Bearer authentication of the form `Bearer <token>`, where token is your auth token.

## Servers

- `https://issuing.sandbox.api.thepennyinc.com` (Sandbox — safe for testing, no real cards or money movement., default)
- `https://issuing.live.api.thepennyinc.com` (Live — real cards, real money movement.)

## Request

### Body (application/json)

This endpoint expects a CreateVirtualCardRequest.

- `card_product_id` (string, required) — The card product to issue the card under.
- `capital_account_id` (string, required) — The capital account that funds the card's spending.
- `cardholder_id` (string, optional) — Existing cardholder that owns the card. Exactly one of cardholder_id or cardholder must be supplied.
- `cardholder` (CreateCardCardholderRequest, optional, nullable) — Inline cardholder-creation payload; the cardholder is created first and then assigned to the new card. Exactly one of cardholder_id or cardholder must be supplied.
- `control_account_id` (string, optional) — A control account to delegate control of this card's spending to. Funds still come from `capital_account_id`.
- `spend_control_id` (string, optional) — A spend control to assign to the card. Its rules apply to every authorization on the card.
- `expiration_date` (date, optional, nullable) — Expiration date for the card. Omit to use the product's `default_expiration_months`; must fall within its `max_expiration_months`, when set.
- `alias` (string, optional, nullable) — A display name for the card, such as "Marketing team".
- `description` (string, optional, nullable) — A longer description of what the card is for.
- `active` (boolean, optional, default: true) — Whether the card should be active on issuance.
- `load_amount` (string, optional, nullable) — The total the card can ever spend, as a decimal string in the card's currency (`USD`). Required when the card product's `usage_type` is `single_reload`, and rejected for any other usage type. Pending authorizations and settled spend count against it, authorizations that expire or are cancelled return their amount, and it cannot be raised after issuance.

## Response

### 201

The newly issued virtual card.

- `card_id` (string, required) — Penny's unique identifier for this card.
- `version` (integer, required) — A number that increases each time this card's details change. Use it to confirm you are looking at the latest information.
- `version_time` (datetime, required) — The date and time this card's details were last changed.
- `issued_time` (datetime, required) — The date and time this card was issued.
- `expiration_date` (date, required) — The date this card expires and can no longer be used.
- `bin_id` (string, required) — The BIN this card was issued under.
- `bin_range_id` (string, required) — The BIN range this card was issued under.
- `card_product_id` (string, required) — The card product this card was issued under.
- `business_id` (string, required) — The business that owns this card.
- `business_entity_id` (string, required) — The business entity associated with this card.
- `program_id` (string, required) — The program this card was issued under.
- `capital_account_id` (string, required) — The account this card draws funds from.
- `cardholder_id` (string, required) — The cardholder this card is issued to.
- `status` (enum, required) — This card's current lifecycle status.
  - Allowed values: `pending`, `active`, `deactivated`, `suspended`, `terminated`
- `active` (boolean, required) — Whether this card is currently able to authorize transactions.
- `terminated` (boolean, required) — Whether this card has been permanently terminated.
- `currency` (enum, required) — The currency this card transacts in.
  - Allowed values: `USD`
- `country` (string, required) — The country this card was issued in, as an ISO 3166-1 alpha-2 code.
- `usage_type` (enum, required) — The usage type this card was issued for.
  - Allowed values: `single_use`, `single_reload`, `reloadable`
- `scheme_details` (CardSchemeResponse, required) — The card network scheme details for this card.
- `terminated_time` (datetime, optional, nullable) — The date and time this card was terminated, if it has been.
- `bin` (string, optional, nullable) — The first 6-8 digits of the card number, as displayed to end users.
- `last_four` (string, optional, nullable) — The last four digits of the card number, as displayed to end users.
- `control_account_id` (string, optional, nullable) — The control account controlling this card's spend, if one is delegated.
- `usage_limits` (CardUsageLimitsResponse, optional, nullable) — The limits enforcing `usage_type` and how much of them is used. Present on single_use and single_reload cards only.
- `alias` (string, optional, nullable) — A human-readable name for this card, if one has been set.
- `description` (string, optional, nullable) — A description of this card's purpose, if one has been set.
- `spend_control_id` (string, optional, nullable) — The spend control policy applied to this card, if one is set.
- `client_reference` (ReferenceResponse, optional, nullable) — An opaque reference the client attached to this card for their own tracking purposes.
- `form_factor` (enum, optional, default: virtual) — The form of this card.
  - Allowed values: `virtual`

## Errors

### 400 Bad Request Error

The request was malformed: a required field is missing or a value has the wrong type or format.

- `type` (string, required) — The name of the exception that was raised.
- `message` (string, required) — A human-readable description of the error.
- `details` (map from string to any, optional, nullable) — Structured context about the error, if any.
- `trace_id` (string, optional, nullable) — Identifier for correlating this error with server-side logs.
- `errors` (list of map from string to any, optional, nullable) — Sub-errors that contributed to this failure, if any.

### 401 Unauthorized Error

Authentication failed.

- `type` (string, required) — The name of the exception that was raised.
- `message` (string, required) — A human-readable description of the error.
- `details` (map from string to any, optional, nullable) — Structured context about the error, if any.
- `trace_id` (string, optional, nullable) — Identifier for correlating this error with server-side logs.
- `errors` (list of map from string to any, optional, nullable) — Sub-errors that contributed to this failure, if any.

### 403 Forbidden Error

The caller does not have permission to perform this action.

- `type` (string, required) — The name of the exception that was raised.
- `message` (string, required) — A human-readable description of the error.
- `details` (map from string to any, optional, nullable) — Structured context about the error, if any.
- `trace_id` (string, optional, nullable) — Identifier for correlating this error with server-side logs.
- `errors` (list of map from string to any, optional, nullable) — Sub-errors that contributed to this failure, if any.

### 404 Not Found Error

A required dependency was not found.

- `type` (string, required) — The name of the exception that was raised.
- `message` (string, required) — A human-readable description of the error.
- `details` (map from string to any, optional, nullable) — Structured context about the error, if any.
- `trace_id` (string, optional, nullable) — Identifier for correlating this error with server-side logs.
- `errors` (list of map from string to any, optional, nullable) — Sub-errors that contributed to this failure, if any.

### 422 Unprocessable Entity Error

The request was well-formed but could not be processed because it breaks a business rule.

- `type` (string, required) — The name of the exception that was raised.
- `message` (string, required) — A human-readable description of the error.
- `details` (map from string to any, optional, nullable) — Structured context about the error, if any.
- `trace_id` (string, optional, nullable) — Identifier for correlating this error with server-side logs.
- `errors` (list of map from string to any, optional, nullable) — Sub-errors that contributed to this failure, if any.

### 429 Too Many Requests Error

Too many requests; retry after the Retry-After header.

- `type` (string, required) — The name of the exception that was raised.
- `message` (string, required) — A human-readable description of the error.
- `details` (map from string to any, optional, nullable) — Structured context about the error, if any.
- `trace_id` (string, optional, nullable) — Identifier for correlating this error with server-side logs.
- `errors` (list of map from string to any, optional, nullable) — Sub-errors that contributed to this failure, if any.

### 500 Internal Server Error

An unexpected error occurred.

- `type` (string, required) — The name of the exception that was raised.
- `message` (string, required) — A human-readable description of the error.
- `details` (map from string to any, optional, nullable) — Structured context about the error, if any.
- `trace_id` (string, optional, nullable) — Identifier for correlating this error with server-side logs.
- `errors` (list of map from string to any, optional, nullable) — Sub-errors that contributed to this failure, if any.

## Types

### CreateCardCardholderRequest

A new cardholder to create along with the card. Supply exactly one of `individual` or `corporate`.

- `individual` (CreateIndividualCardholderRequest, optional, nullable) — Individual cardholder to create and assign to the new card.
- `corporate` (CreateCorporateCardholderRequest, optional, nullable) — Corporate cardholder to create and assign to the new card.

### CardSchemeResponse

The card network scheme configuration for this card: the network brand, funding type, and product type used in authorization and clearing.

- `network` (enum, required) — The card network for this card, such as Visa or Mastercard.
  - Allowed values: `visa`, `mastercard`
- `funding_type` (enum, optional, nullable) — This card's funding type, if defined.
  - Allowed values: `debit`, `credit`, `prepaid`
- `product_type` (enum, optional, nullable) — This card's network product category, if defined.
  - Allowed values: `consumer`, `corporate`, `commercial`

### CardUsageLimitsResponse

The limits enforcing this card's usage type, and how much of them is used. Amounts are in the card's currency.

- `authorizations_maximum` (integer, optional, nullable) — How many authorizations the card permits. Set on single_use cards.
- `authorizations_used` (integer, optional, nullable) — How many authorizations are counted against `authorizations_maximum`. An authorization that expires or is cancelled before settling is no longer counted.
- `amount_limit` (string, optional, nullable) — The lifetime spend budget set by `load_amount` at issuance. Set on single_reload cards; it cannot be raised.
- `amount_remaining` (string, optional, nullable) — The budget still available. Pending authorizations and settled spend reduce it; authorizations that expire or are cancelled return it.

### ReferenceResponse

An opaque reference the client attached to this card for their own tracking purposes.

- `id` (string, optional, nullable) — The client's own identifier for this card in their system.
- `data` (map from string to string, optional, nullable) — Additional metadata the client attached to this card.

### CreateIndividualCardholderRequest

An individual cardholder: a person who holds cards in their own name.

- `given_name` (string, required) — The first name of the cardholder.
- `family_name` (string, required) — The last name of the cardholder.
- `email` (string, required) — The email address of the cardholder.
- `address` (CardholderAddressRequest, required) — The address of the cardholder.
- `phone_number` (string, optional, nullable) — The phone number of the cardholder.
- `spend_control_id` (string, optional) — The ID of the spend control associated with the cardholder.

### CreateCorporateCardholderRequest

A corporate cardholder: a business that holds cards in its own name.

- `business_name` (string, required) — The business name of the cardholder.
- `email` (string, required) — The email address of the cardholder.
- `address` (CardholderAddressRequest, required) — The address of the business.
- `phone_number` (string, optional, nullable) — The phone number of the cardholder.
- `spend_control_id` (string, optional) — The ID of the spend control associated with the cardholder.

### CardholderAddressRequest

A cardholder's postal address, using ISO country and subdivision codes.

- `line_1` (string, required) — The primary address line.
- `city` (string, required) — The city or locality of the address.
- `post_code` (string, required) — The postal or ZIP code.
- `country` (string, required) — The ISO 3166-1 alpha-2 country code (e.g. 'US').
- `line_2` (string, optional, nullable) — An optional secondary address line.
- `state_or_province` (string, optional, nullable) — The ISO 3166-2 state or province code (e.g. 'CA') or name. Required for countries that use subdivisions.

## Examples

**Request**

```json
{
  "card_product_id": "string",
  "capital_account_id": "string"
}
```

**Response**

```json
{
  "card_id": "card_019375de-a2a0-7f31-884a-a2a0f3184abd",
  "version": 1,
  "version_time": "2024-01-15T10:30:00Z",
  "issued_time": "2024-01-15T10:30:00Z",
  "expiration_date": "2030-06-30",
  "bin_id": "bin_01937000-0592-7190-87e7-05921907e7c5",
  "bin_range_id": "bin_range_01937b28-f048-77de-8ef4-f0487deef42d",
  "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",
  "cardholder_id": "cardholder_01937e19-4ebb-75bd-8250-4ebb5bd25085",
  "status": "pending",
  "active": true,
  "terminated": false,
  "currency": "USD",
  "country": "US",
  "usage_type": "single_use",
  "scheme_details": {
    "network": "visa",
    "funding_type": "debit",
    "product_type": "consumer"
  },
  "terminated_time": "2024-01-15T10:30:00Z",
  "bin": "424242",
  "last_four": "4242",
  "control_account_id": "account_019372e3-b8dc-7de2-80b6-b8dcde20b6c9",
  "usage_limits": {
    "authorizations_maximum": 1,
    "authorizations_used": 0,
    "amount_limit": "250.00",
    "amount_remaining": "180.00"
  },
  "alias": "Marketing Team Card",
  "description": "Card issued for the marketing team's advertising spend.",
  "spend_control_id": "spend_control_019379d9-a170-796b-867a-a17096b67a21",
  "client_reference": {
    "id": "order-482910",
    "data": {}
  },
  "form_factor": "virtual"
}
```

**SDK Code**

```python
import requests

url = "https://issuing.sandbox.api.thepennyinc.com/cards/virtual"

payload = {
    "card_product_id": "string",
    "capital_account_id": "string"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://issuing.sandbox.api.thepennyinc.com/cards/virtual';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"card_product_id":"string","capital_account_id":"string"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://issuing.sandbox.api.thepennyinc.com/cards/virtual"

	payload := strings.NewReader("{\n  \"card_product_id\": \"string\",\n  \"capital_account_id\": \"string\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://issuing.sandbox.api.thepennyinc.com/cards/virtual")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"card_product_id\": \"string\",\n  \"capital_account_id\": \"string\"\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://issuing.sandbox.api.thepennyinc.com/cards/virtual")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"card_product_id\": \"string\",\n  \"capital_account_id\": \"string\"\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://issuing.sandbox.api.thepennyinc.com/cards/virtual', [
  'body' => '{
  "card_product_id": "string",
  "capital_account_id": "string"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://issuing.sandbox.api.thepennyinc.com/cards/virtual");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"card_product_id\": \"string\",\n  \"capital_account_id\": \"string\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "card_product_id": "string",
  "capital_account_id": "string"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://issuing.sandbox.api.thepennyinc.com/cards/virtual")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```