---
title: "Issue a second or physical card"
description: "Give a cardholder up to 10 cards, sharing their balance or with a balance of their own. Physical cards are Not yet available."
---
Use this recipe to give a cardholder up to 10 cards. Each extra card shares the cardholder's balance or has a balance of its own. Physical cards are Not yet available.

**Who it is for.** This recipe is for a consumer app that gives Ada a separate card for subscriptions.

**Status.** Additional virtual cards are Available. Physical cards are Not yet available.

## Money example

Ada's main card holds 131.25 USD.

1. You issue her a "subscriptions" virtual card with a balance of its own and a 50 USD daily limit.
2. You move 30 USD to the new card. The main card still holds 131.25 USD, and the subscriptions card holds 30 USD.
3. A 9.99 USD subscription charges the subscriptions card, which leaves 20.01 USD on it.

## Before you start

- Ada's application is approved and her first card exists. Check with `GET /v1/cards?customer_id=…`.
- She holds fewer than 10 cards that are not blocked.

## Find out what is required

Count Ada's cards:

<CodeGroup>
```bash title="cURL"
curl --request GET \
     --url 'https://api.gravv.xyz/v1/cards?customer_id=5b0f6c1e-2a8f-4c39-9d0e-0c7e3b9a1f42&status=active,freeze,inactive' \
     --header 'Api-Key: <API_KEY>'
```
```javascript title="Node"
const response = await fetch("https://api.gravv.xyz/v1/cards?customer_id=5b0f6c1e-2a8f-4c39-9d0e-0c7e3b9a1f42&status=active,freeze,inactive", {
  method: "GET",
  headers: {
    "Api-Key": process.env.GRAVV_API_KEY,
  },
});
console.log(response.status, await response.json());
```
```python title="Python"
import os

import requests

response = requests.get(
    "https://api.gravv.xyz/v1/cards?customer_id=5b0f6c1e-2a8f-4c39-9d0e-0c7e3b9a1f42&status=active,freeze,inactive",
    headers={
        "Api-Key": os.environ["GRAVV_API_KEY"],
    },
)
print(response.status_code, response.json())
```
</CodeGroup>

## Steps

### 1. Issue a second virtual card with its own balance

Send a new `Idempotency-Key` for each extra card.

<CodeGroup>
```bash title="cURL"
curl --request POST \
     --url https://api.gravv.xyz/v1/cards \
     --header 'Api-Key: <API_KEY>' \
     --header 'Idempotency-Key: 3211a0fd-795d-4218-bc6e-4966abe161ab' \
     --header 'Content-Type: application/json' \
     --data '
{
  "customer_id": "5b0f6c1e-2a8f-4c39-9d0e-0c7e3b9a1f42",
  "card_type": "virtual",
  "card_limit": 50,
  "name_on_card": "Ada Obi",
  "funding": {
    "mode": "own"
  }
}
'
```
```javascript title="Node"
const response = await fetch("https://api.gravv.xyz/v1/cards", {
  method: "POST",
  headers: {
    "Api-Key": process.env.GRAVV_API_KEY,
    "Idempotency-Key": "3211a0fd-795d-4218-bc6e-4966abe161ab",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "customer_id": "5b0f6c1e-2a8f-4c39-9d0e-0c7e3b9a1f42",
    "card_type": "virtual",
    "card_limit": 50,
    "name_on_card": "Ada Obi",
    "funding": {
      "mode": "own"
    }
  }),
});
console.log(response.status, await response.json());
```
```python title="Python"
import os

import requests

response = requests.post(
    "https://api.gravv.xyz/v1/cards",
    headers={
        "Api-Key": os.environ["GRAVV_API_KEY"],
        "Idempotency-Key": "3211a0fd-795d-4218-bc6e-4966abe161ab",
        "Content-Type": "application/json",
    },
    json={
        "customer_id": "5b0f6c1e-2a8f-4c39-9d0e-0c7e3b9a1f42",
        "card_type": "virtual",
        "card_limit": 50,
        "name_on_card": "Ada Obi",
        "funding": {
            "mode": "own",
        },
    },
)
print(response.status_code, response.json())
```
</CodeGroup>

```json title="Response"
{
  "data": {
    "message": "Card creation request is processing",
    "status": true,
    "id": "0c9b8a7f-6e5d-4c4b-9a3f-2e1d0c9b8a76",
    "fee_charged": false
  },
  "error": null
}
```

Send `{"mode": "shared"}`, or leave `funding` out, to spend from the same balance as the main card.

### 2. Check it

`GET /v1/cards/0c9b8a7f-6e5d-4c4b-9a3f-2e1d0c9b8a76` shows `card_type` `virtual`, `status` `active` and the 50 USD limit. Next, [top it up](/recipes/cards/top-up-a-card).

### Physical cards

Not yet available. A physical card cannot make a payment today. In sandbox, the request returns `card creation failed!` and leaves an empty card row. In live, the card starts `inactive`, and no API call activates it. For the shipping address rules, see [Physical card shipping](/platform/cards/physical-card-shipping).

## What can go wrong

| Response (HTTP 400 unless noted) | Why | Fix |
| :-- | :-- | :-- |
| `customer already holds the maximum of 10 cards` | The cardholder has reached the cap of 10 cards | Block an unused card |
| `missing idempotency key in request headers` | The request has no `Idempotency-Key` | Add one |
| 422 `idempotency_key_reused` | You sent the same key with another body | Use a new key for each card |
| `funding.mode must be "shared" or "own"` | The mode is invalid | Send `shared` or `own` |
| `this card's balance is a new provider account whose application is <status>; retry with the same Idempotency-Key once it is approved` | In live, an `own` balance waits for approval | See [Issue expense cards to employees](/recipes/cards/issue-expense-cards-to-employees#what-can-go-wrong) |
| `card creation failed!` | The card program refused the card. Every physical card request in sandbox returns this today | Issue a virtual card, and ignore the empty row |

## Webhooks you will receive

Gravv sends no webhook when you issue a card. You receive `cards.transaction.*` events once the cardholder uses the card.

## Testing in sandbox

Additional virtual cards work in sandbox. A card with `funding.mode` `own` gets its own `card_group_id`. Physical cards fail to issue.

## Reference

- [Create a card](/platform/cards/create-a-card)
- [Check card balance](/platform/cards/check-card-balance)
