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

> ## Agent Instructions
> Bitnob API requests authenticate with an `X-Auth-Client` API key header against https://api.bitnob.com.
> Always use the sandbox environment for testing. Never put live API keys in sample code.
> Money amounts are integers in the smallest unit of the currency (satoshis for BTC, cents for fiat). Never use floats.
> Every state-changing request takes a client-supplied `reference` and must be treated as idempotent on retry.
> Quotes expire. Re-quote rather than reusing a stale quote id.

# Module 5: Funding virtual cards

> How prepaid funding works, which assets can fund a card, and the FX and fee edge cases to expect.

## Learning objectives

* Understand how prepaid virtual card funding works
* Know what assets can be used to fund cards
* Learn how to combine card registration, issuance, and funding into one clean flow
* Handle common edge cases (errors, fees, FX behavior)

## What does “funding a virtual card” mean?

Funding is the act of preloading money onto a virtual card. Since virtual cards are prepaid by design, they must be funded before use.

Think of it like putting money into a secure digital envelope that only works on the internet.

The money typically comes from:

* A fiat wallet (NGN, GHS, ZAR, etc.)
* A stablecoin balance (e.g. USDT)
* A treasury float controlled by your platform

## How funding works (conceptually)

Here’s the typical flow:

```text theme={null}
Your Wallet/Float
⬇ (deduct amount)
Virtual Card Processor
⬇ (credit card balance)
Card is ready to spend online
```

## Supported funding assets

| Source | What happens |
| - | - |
| Company balance | Each top-up debits your company’s stablecoin balance. The error’s `extensions.currency` names the balance that was checked. |
| Crypto deposit | A USDT or USDC deposit to a card’s deposit address can fund that card automatically. |

Bitnob doesn’t convert other assets during a top-up. To fund cards from BTC or NGN, convert to the stablecoin first with a trade.

## Top-up rules and limits

| Rule | Value (example) |
| - | - |
| Minimum top-up | \$2 |
| Maximum per top-up | \$2,500 |
| Maximum card balance | \$50,000 |
| Top-up fee | \$1 flat below \$100, 1% at \$100 and above |
| FX markup (if applicable) | Varies per platform |

These limits help control risk and fraud. They’re also adjustable based on business model.

## Full flow: Create customer → issue → fund

Let’s now walk through the combined MVP flow:

### Step 1: Create the customer

```bash theme={null}
POST /api/customers
```

```json theme={null}
{
  "customer_type": "individual",
  "first_name": "Tunde",
  "last_name": "Okoro",
  "email": "tunde@example.com",
  "dial_code": "+234",
  "phone_number": "8000000001"
}
```

➡ Store the returned customer `id`. Complete card KYC for the customer before you issue a card.

### Step 2: Create a card for the customer

```bash theme={null}
POST /api/cards
```

```json theme={null}
{
  "customer_id": "019a3b61-8eb7-76d9-a1a2-4d5e6f7a8b9a",
  "card_type": "virtual",
  "card_program": "prepaid",
  "card_brand": "visa",
  "currency": "USD",
  "amount": 10000000,
  "reference": "user_001_card"
}
```

A prepaid card needs initial funding of at least \$2. The amount is in micro-units, so `10000000` is \$10.

➡ You'll receive the card record with status `pending`. Store its `id` securely, and wait for the `virtualcard.created.completed` webhook before you fund it again.

### Step 3: Fund the card

```bash theme={null}
POST /api/cards/{cardId}/balance
```

```json theme={null}
{
  "type": "fund",
  "amount": 100000000,
  "reference": "user_001_topup_01"
}
```

`100000000` is \$100.

➡ The response confirms the funding request.

## What to show the user

| Step | Ux Element |
| - | - |
| Create customer | No UI shown: background action |
| Create | Show the card once `virtualcard.created.completed` arrives |
| Fund | Show the new balance once `virtualcard.topup.completed` arrives |
| Failed Top-Up | Display failure reason (e.g. insufficient wallet balance) and retry CTA |

## Common funding errors

| Error | Reason |
| - | - |
| `400` with `extensions.error_code` `COMPANY_INSUFFICIENT_BALANCE` | Your company balance doesn’t cover the top-up and fee |
| `400` "Card is not active" | You tried funding a frozen or terminated card |
| `400` "amount below minimum funding of \$2" | The top-up is under \$2 |
| `400` "rate limit exceeded: please wait 120 seconds before making another topup" | The card was funded in the last 120 seconds |
| `404` | The `cardId` doesn’t exist or doesn’t belong to your account |

## Funding use cases

| Use Case | Pattern |
| - | - |
| User-triggered top-up | Let users tap “Add Funds” manually in UI |
| Auto-fund after payout | When user receives crypto or fiat payment, auto-top-up a card |
| Budgeted card issuance | Top-up the card with \$200 monthly allowance |
| Pay-as-you-spend | Top-up in real time based on transaction attempt (advanced) |

## Best practices

| Practice | Why |
| - | - |
| Show current card balance in UI | Helps users understand availability before spending |
| Validate card status before funding | Prevent wasteful operations and stuck funds |
| Show fee breakdown and FX conversion | Builds transparency and trust |
| Always log top-up reference IDs | Helps with reconciliation and dispute handling |
| Use webhooks to confirm top-up success | Never assume success from just a `200` response |

## Recap exercise

You're building an app that gives each new user a \$50 shopping card after KYC.

Sketch out your backend flow in pseudocode or sequence:

1. Create the customer
2. Issue card
3. Fund with \$50 from marketing wallet
4. Display card
5. Listen to `virtualcard.topup.completed` webhook

This is your **basic card distribution engine.**

## Key takeaways

* Virtual cards must be funded before use, they’re not credit-based
* Most systems support funding from crypto, fiat, or wallet balances
* You can combine registration, issuance, and top-up into a smooth experience
* Design your UI and backend to show status clearly, handle errors, and listen to webhooks


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