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

# Get started with cards

> Issue a card, fund it, read its balance and spending — and what to expect at each step.

<Warning>
  Issuance cannot currently succeed for a business client: the customer holder must be at tier 2 and no customer can reach it. Expect `404 card_holder_not_found` at step 1. The rest of this page describes what happens once that gate opens. See [the introduction](/services/cards/introduction#the-gates).
</Warning>

```bash theme={null}
export SAKAWAVE_API_KEY='sk_test_replace_with_your_key'
export SAKAWAVE_BASE_URL='https://sandbox-api.sakawave.example'
```

## 1. Issue the card

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url "$SAKAWAVE_BASE_URL/v1/cards" \
    --header "Authorization: Bearer $SAKAWAVE_API_KEY" \
    --header "Content-Type: application/json" \
    --data "{
      \"customerId\": \"$CUSTOMER_ID\",
      \"type\": \"virtual\",
      \"brand\": \"mastercard\",
      \"currency\": \"USD\",
      \"externalReference\": \"card_issue_20260814_001\",
      \"label\": \"Ada travel card\",
      \"debitAccountId\": \"$NGN_ACCOUNT_ID\",
      \"amount\": \"5000\",
      \"spendingControls\": {
        \"transactionAmountLimit\": \"2000\",
        \"dailyAmountLimit\": \"5000\",
        \"dailyTransactionCount\": 10
      }
    }"
  ```

  ```ts Node.js theme={null}
  const response = await fetch(`${process.env.SAKAWAVE_BASE_URL}/v1/cards`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.SAKAWAVE_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      customerId,
      type: 'virtual',
      brand: 'mastercard',
      currency: 'USD',
      externalReference: 'card_issue_20260814_001',
      label: 'Ada travel card',
      debitAccountId: ngnAccountId,
      amount: '5000',
      spendingControls: { transactionAmountLimit: '2000', dailyAmountLimit: '5000', dailyTransactionCount: 10 },
    }),
  });

  const { card, operation } = await response.json();
  if (!response.ok) throw new Error(`${response.status}: ${card?.code ?? operation?.code}`);

  console.log(card.status, operation.type, operation.status);
  ```
</CodeGroup>

`"5000"` is **\$50.00**: `amount` is in the card's currency, so USD minor units. A card is always issued **funded** — there is no unfunded card, and `debitAccountId` and `amount` are both required.

The account you debit does not have to be USD. When it is not, Sakawave quotes the rate at issuance and debits the equivalent — an NGN account funding a $50.00 card is debited whatever $50.00 costs in naira at that moment. You do not pass a quote. [`POST /v1/card-fx-quotes`](/api-reference/cards/create-a-card-fx-quote) is still there to show a customer an indicative rate beforehand, but issuance does not accept one.

The response carries both the card and the operation that is issuing it:

```json theme={null}
{
  "card": { "id": "01K2…", "status": "creating", "maskedPan": "•••• •••• •••• ••••", "balance": "0" },
  "operation": { "id": "01K2…", "type": "issuance", "status": "pending" }
}
```

`creating` is normal. The card becomes `active` once the provider has issued and funded it — poll `GET /v1/cards/{cardId}` or wait for `card.updated`.

<Note>
  Spending controls are rejected on a `disposable` card. Send them only with `type: "virtual"`.
</Note>

## 2. Add more money later

```bash theme={null}
curl --request POST \
  --url "$SAKAWAVE_BASE_URL/v1/cards/$CARD_ID/fund" \
  --header "Authorization: Bearer $SAKAWAVE_API_KEY" \
  --header "Content-Type: application/json" \
  --data "{
    \"externalReference\": \"card_fund_20260814_001\",
    \"accountId\": \"$USD_ACCOUNT_ID\",
    \"amountUsd\": \"2500\"
  }"
```

Funding works while the card is `active` **or** `frozen`. The response is an operation, often `pending` — it settles asynchronously.

## 3. Read the card

```bash theme={null}
curl --silent --url "$SAKAWAVE_BASE_URL/v1/cards/$CARD_ID" \
  --header "Authorization: Bearer $SAKAWAVE_API_KEY" \
| jq '{status, balance, balanceFormatted, operations: [.operations[] | {type, status}]}'
```

`GET` on one card includes every operation against it, which is how you check whether that funding landed.

## 4. See what was spent

```bash theme={null}
curl --silent --url "$SAKAWAVE_BASE_URL/v1/cards/$CARD_ID/transactions" \
  --header "Authorization: Bearer $SAKAWAVE_API_KEY" \
| jq '.[] | {status, direction, amountFormatted, merchantName, createdAt}'
```

This is the card's spending, refreshed from the provider on each call — not the ledger. A refund appears as a `credit`.

## Four things to know before you build

1. **Amounts are USD minor units, everywhere.** `"5000"` is \$50.00, even when you pay from an NGN account — the conversion is ours to make, not yours.
2. **Freezing does not stop funding.** It stops merchants. If you need the money back, withdraw it.
3. **A failed issuance retries under the same reference.** That is the opposite of transfers — see [setup and configuration](/services/cards/setup-and-configuration#idempotency).
4. **Termination is irreversible** and sweeps the balance to an account you name.

## If it failed

| Status | `code` | What to do |
| - | - | - |
| `403` | `reason: feature_not_available` | Your business is below tier 2. Card issuance needs tier 2. |
| `403` | `card_client_account_required` | You used a customer wallet. Cards fund from your own accounts. |
| `404` | `card_holder_not_found` | The customer is not eligible — today, this is every customer. |
| `400` | `card_holder_required` | A business client must send a `customerId`. |
| `409` | `card_fx_quote_not_required` | You asked to fund or withdraw with a quote on a USD account; drop it. |
| `409` | `card_fx_quote_invalid` | Expired, spent, or bound to a different account, card, or operation. |
| `409` | `card_not_usable` | The card is not `active` or `frozen`. |
| `503` | `card_provider_unavailable` | The provider was unreachable. Retry with the same reference. |

## Next

* [Card programs and PAN handling](/services/cards/card-programs-and-pan-handling)
* [Use cases](/services/cards/use-cases) — controls, freezing, reconciliation


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.