Virtual Cards

Bitnob’s Virtual Cards API allows you to programmatically issue and manage USD-denominated virtual debit cards for users. These cards can be used for online purchases, subscriptions, and other payments just like physical debit cards.

Card API Endpoints

Migrating from v1

If you integrated against the legacy card endpoints, a few paths have been consolidated in v2. The intent is one endpoint per resource transition, with the specific action carried in the body — simpler to build SDKs against and easier to observe in logs.

v2 consolidations (breaking changes from v1)

Fund + Withdraw → single POST /api/cards/:cardId/balance discriminated by type: "fund" | "withdraw" in the body.

Freeze + Unfreeze → single POST /api/cards/:cardId/status discriminated by status: "frozen" | "active" in the body.

Termination → DELETE /api/cards/:cardId with a reason in the body (was POST /api/cards/:cardId/terminate in v1).

Secure details → GET /api/cards/:cardId/secure (was /details in v1).

Spend limits → PUT /api/cards/:cardId/spend-limits (plural renamed from spending-limits) — covers transaction, daily, weekly, monthly, yearly, all_time limits.

Amount Units

All amount fields on card endpoints are in the base units of the card currency. On a USD card the base unit is cents — so 5000000 means $50,000.00 (5,000,000 ÷ 100), not five million dollars. Apply the same divisor on every amount field (funding, withdrawals, spend limits, balances).


Create Card

Issue a new virtual or physical card for a customer. The card is created in an active state and can be used immediately after funding.

Create Card

Create Card Body Parameters
1
amountnumberRequired

Initial funding amount for the card, in the currency's smallest unit (e.g. 5000000 = $50.00 when currency is USD).

2
card_typestringRequired

The type of card to issue. Accepted values: 'virtual' or 'physical'.

3
currencystringRequired

Currency the card will transact in (e.g. 'USD'). All purchases settle in this currency.

4
namestringRequired

Name to emboss / associate with the card (typically the cardholder's full name).

5
contactless_paymentbooleanOptional

Whether contactless (NFC) payments are enabled on the card.

6
created_byUUIDOptional

Identifier of the user or operator issuing the card — stored on the audit trail.

7
webhook_urlstringOptional

HTTPS URL that will receive lifecycle and transaction webhooks for this card.

8
card_limitsobjectOptional

Spend controls applied to the card. Each limit is a string-formatted decimal in the card currency.

9
card_limits.single_transactionstringOptional

Maximum amount per single transaction (e.g. '1000.00').

10
card_limits.dailystringOptional

Maximum cumulative spend per day (e.g. '5000.00').

11
card_limits.weeklystringOptional

Maximum cumulative spend per 7-day rolling window (e.g. '20000.00').

12
card_limits.monthlystringOptional

Maximum cumulative spend per calendar month (e.g. '50000.00').

13
customerobjectRequired

Cardholder identity and address. Required fields vary by ID type and country.

14
customer.customer_typestringRequired

'individual' or 'business'.

15
customer.first_namestringRequired

Cardholder's given name.

16
customer.last_namestringRequired

Cardholder's family name.

17
customer.emailstringRequired

Cardholder's email address.

18
customer.phone_numberstringRequired

Local phone number without the country code (e.g. '8034567890').

19
customer.dial_codestringRequired

International dial code for the phone number (e.g. '+234').

20
customer.date_of_birthstringRequired

Cardholder's date of birth in YYYY-MM-DD format.

21
customer.id_typestringRequired

Government ID type used for KYC (e.g. 'national_id', 'passport', 'drivers_license').

22
customer.id_numberstringRequired

Value of the ID document referenced by id_type.

23
customer.line1stringRequired

Street address line.

24
customer.citystringRequired

City of the cardholder's address.

25
customer.statestringRequired

State or province of the cardholder's address.

26
customer.postal_codestringRequired

Postal / ZIP code.

27
customer.countrystringRequired

Three-letter ISO 3166-1 alpha-3 country code (e.g. 'NGA', 'USA', 'GBR').

Customer Is Created From This Payload

The customer object on this request is used to create a new customer record as part of card issuance you do not need to call the Customers API first. The customer returned on the response can be reused for subsequent cards or other endpoints.

Body Parameters

Response
1
successBoolean

Top-level flag indicating whether the request was processed successfully.

2
messageString

Human-readable status message describing the outcome.

3
data.cardObject

The created card record.

4
data.card.idUUID

Unique identifier for the newly created card. Use it on subsequent lifecycle endpoints (fund, freeze, etc.).

5
data.card.company_idUUID

Identifier of the company that owns this card.

6
data.card.customer_idUUID

Identifier of the customer the card was issued to (created implicitly from the request's customer object).

7
data.card.card_typeString

The type of card issued — 'virtual' or 'physical'.

8
data.card.statusString

Overall card status. A freshly created card is 'pending' until the issuer completes provisioning, then transitions to 'active'.

9
data.card.created_statusString

Fine-grained provisioning status. 'processing' while the issuer is minting the card; becomes 'completed' once the PAN is generated and masked_pan is populated.

10
data.card.nameString

Name associated with the card (as provided in the request).

11
data.card.preferred_nameString

Display name for the card. Defaults to name if no preferred name is supplied.

12
data.card.masked_panString

Masked card number (e.g. '**** **** **** 4532'). Empty string while created_status is 'processing'; populated once provisioning completes.

13
data.card.balance_amountString

Current balance as a string in the card's smallest unit. Starts at '0' and updates on fund / withdraw operations.

14
data.card.balance_currencyString

Currency of the balance (e.g. 'USD').

15
data.card.display_amountNumber

Balance rendered as a decimal number for display (e.g. 0, 50.25).

16
data.card.contactless_paymentBoolean

Whether contactless (NFC) payments are enabled on the card.

17
data.card.spending_limitsObject

Applied spending limits (single_transaction, daily, weekly, monthly). Empty object when no limits are in effect.

18
data.card.referenceString

Server-generated reference for tracking the card creation (e.g. 'CARD_CREATE_49C9464924DC').

19
data.card.webhook_urlString

Webhook URL that will receive lifecycle and transaction events for this card.

20
data.card.user_metadataString

Stringified JSON of metadata you attached (e.g. '{}' when empty).

21
data.card.billing_addressObject

Billing address printed on the card statement (line1, line2, city, state, postal_code, country). Returned as the issuer's billing address, which may differ from the cardholder's address.

22
data.card.created_byUUID

Identifier of the user or operator that issued the card, echoed from the request.

23
data.card.created_atDate

RFC 3339 / ISO 8601 timestamp of when the card was created (UTC).

24
data.card.updated_atDate

RFC 3339 / ISO 8601 timestamp of the last update to the card record (UTC).

25
metadata.request_idString

Unique identifier for this API request, useful for log correlation and support.

26
timestampDate

Top-level RFC 3339 / ISO 8601 server timestamp of when the response was generated (UTC).

Provisioning Is Asynchronous

A freshly created card returns with status: "pending" and created_status: "processing". masked_pan is empty at this point. Listen for the card-ready webhook (or poll GET /api/cards/:cardId) to pick up the final status: "active" and the populated masked_pan.

Response Body

Get Card

Retrieve the details of a specific card by its ID. This returns general card information including balance and status, but not sensitive card data like the full card number or CVV.

Get Card

Path Parameters
1
cardIdstringRequired

The unique identifier of the card to retrieve.

Response Body

Get Card Details (Sensitive)

Retrieve sensitive card data including the full card number, CVV, and expiry date. This endpoint returns PCI-sensitive information and should be used with extreme care.

Security Warning

Only call this endpoint when absolutely necessary. Never log or store the full card number or CVV. Display card details securely in the UI and consider implementing additional verification (e.g., 2FA) before showing details to end users.

Get Card Details

Path Parameters
1
successBoolean

Top-level flag indicating whether the request was processed successfully.

2
messageString

Human-readable status message describing the outcome.

3
data.detailsObject

Envelope wrapping the sensitive card credentials.

4
data.details.card_idUUID

Identifier of the card whose credentials are being returned.

5
data.details.card_numberString

Full 16-digit PAN. PCI-sensitive — do not log, store, or transmit outside a PCI-compliant surface. Render directly to the end-user's device and drop immediately after use.

6
data.details.cvvString

3-digit card verification value. PCI-sensitive — apply the same handling rules as card_number.

7
data.details.expiry_monthString

Two-digit expiry month, zero-padded (e.g. '04').

8
data.details.expiry_yearString

Four-digit expiry year (e.g. '2029').

9
data.details.nameString

Name associated with the card (cardholder name).

10
metadata.request_idString

Unique identifier for this API request, useful for log correlation and support.

11
timestampDate

Top-level RFC 3339 / ISO 8601 server timestamp of when the response was generated (UTC).

PCI-Sensitive Payload

This response carries the unmasked PAN and CVV — treat the entire payload as PCI-regulated. Never log it, never persist it, and never forward it to non-compliant services. Render directly in an iframe or PCI-scoped surface and discard immediately.

Response Body

List Cards

Retrieve a paginated list of cards belonging to your company. Filter by card type, status, or a search string (e.g. the last 4 digits of the PAN or the cardholder name).

List Cards

Query Parameters
1
card_typestringOptional

Filter by card type. Accepted values: 'virtual' or 'physical'.

2
statusstringOptional

Filter by card status (e.g. 'active', 'pending', 'frozen', 'terminated').

3
searchstringOptional

Free-text search across cards — matches the last 4 digits of the PAN or the cardholder name.

4
cursorstringOptional

Opaque base64 pagination cursor. Pass data.page_info.next_cursor from the previous response to fetch the next page. Omit on the first request.

5
limitnumberOptional

Maximum number of records to return per page. Default 20.

Response Body

Card Transactions

Retrieve a paginated list of transactions on a single card — fees, funding, purchases, refunds. Pagination is cursor-based.

Card Transactions

Query Parameters
1
cursorstringOptional

Opaque base64 pagination cursor. Pass data.page_info.next_cursor from the previous response to fetch the next page, or data.page_info.previous_cursor to go back. Omit on the first request.

2
limitnumberOptional

Maximum number of records to return per page. Default 20.

3
typestringOptional

Filter by transaction type (e.g. 'fee', 'funding', 'purchase', 'refund', 'withdrawal').

4
statusstringOptional

Filter by transaction status (e.g. 'pending', 'completed', 'failed').

Response Fields
1
data.transactionsArray<Transaction>

Page of card transaction records.

2
data.transactions[].idUUID

Unique identifier of the transaction.

3
data.transactions[].card_idUUID

Identifier of the card this transaction belongs to.

4
data.transactions[].company_idUUID

Identifier of the company that owns the card.

5
data.transactions[].typeString

Transaction type: 'fee', 'funding', 'purchase', 'refund', 'withdrawal'.

6
data.transactions[].statusString

Lifecycle status: 'pending', 'completed', or 'failed'.

7
data.transactions[].amountString

Transaction amount as an integer string in the card's smallest unit (e.g. '5000000' = $50.00 on a USD card).

8
data.transactions[].currencyString

Currency of the transaction.

9
data.transactions[].display_amountNumber

Transaction amount as a decimal number for display.

10
data.transactions[].balance_beforeString

Card balance immediately before this transaction, in the smallest unit.

11
data.transactions[].balance_afterString

Card balance immediately after this transaction, in the smallest unit.

12
data.transactions[].fee_amountString

Fee charged for this transaction, in the smallest unit. Zero when no fee applies.

13
data.transactions[].fee_typeString

Category of the fee (e.g. 'CARD_CREATION_FEE', 'CARD_TOPUP_FEE'). Empty when fee_amount is zero.

14
data.transactions[].referenceString

Server-generated reference string for this transaction.

15
data.transactions[].descriptionString

Human-readable description of the transaction (e.g. 'Card creation fee', 'Initial card funding').

16
data.transactions[].metadataString

Stringified JSON of metadata attached at transaction time.

17
data.transactions[].cardholder_nameString

Name on the card at the time of the transaction.

18
data.transactions[].last_four_digitString

Last four digits of the card PAN at the time of the transaction. Present on transactions against a provisioned card.

19
data.transactions[].provider_transaction_idString

Identifier returned by the downstream card processor (e.g. Miden). Use it when opening support tickets with the provider. Not present on purely internal transactions like creation fees.

20
data.transactions[].created_byUUID

Identifier of the user or operator that initiated the transaction.

21
data.transactions[].transaction_dateDate

RFC 3339 / ISO 8601 timestamp of when the transaction was recorded.

22
data.transactions[].created_atDate

RFC 3339 / ISO 8601 timestamp of when the transaction record was created.

23
data.transactions[].updated_atDate

RFC 3339 / ISO 8601 timestamp of the most recent update to the record.

24
data.transactions[].failure_codeString

Machine-readable failure code. Only present when status is 'failed' (e.g. 'PROVIDER_REJECTED').

25
data.transactions[].failure_reasonString

Human-readable explanation of the failure, often surfaced from the underlying card processor. Only present when status is 'failed'.

26
data.page_infoObject

Cursor-based pagination metadata.

27
data.page_info.has_next_pageBoolean

True when more records are available via next_cursor.

28
data.page_info.has_previous_pageBoolean

True when prior records are available via previous_cursor.

29
data.page_info.next_cursorString

Opaque base64 cursor for fetching the next page.

30
data.page_info.previous_cursorString

Opaque base64 cursor for stepping back one page.

31
data.page_info.totalInteger

Total number of transactions for this card matching the current filters.

Response Body

Get Card Transaction

Retrieve a single card transaction by its ID, scoped to a specific card. Use this to re-fetch an updated status after a webhook, or to confirm a specific provider_transaction_id / fee_amount before reconciling.

Get Card Transaction

Path Parameters
1
cardIdUUIDRequired

The card the transaction belongs to.

2
transactionIdUUIDRequired

The transaction to retrieve (from data.transactions[].id on the listing endpoint).

Same Shape As Listing

The returned data.transaction object uses the identical schema as entries in the Card Transactions list response — refer to that section for per-field docs, including the provider_transaction_id, failure_code, and failure_reason fields that may or may not be present depending on transaction type and status.

Response Body

Fund or Withdraw

A single endpoint adjusts a card's balance. The type field in the body selects the direction "fund" credits the card, "withdraw" debits it. Both operations are processed asynchronously and resolve via the card transactions webhook.

Fund or Withdraw

Path Parameters
1
cardIdUUIDRequired

The card to adjust. Must belong to your company.

Body Parameters
1
amountnumberRequired

Amount to move in the card currency's smallest unit (e.g. 2000000 = $20.00 on a USD card).

2
typestringRequired

Direction of the balance change: 'fund' to credit the card, 'withdraw' to debit it back to your account.

3
referencestringRequired

Client-generated identifier for this operation. Used for idempotency — retrying with the same reference returns the original transaction instead of creating a duplicate.

Asynchronous Settlement

The response returns immediately with data.transaction.status: "pending" and balance_before === balance_after. The card's balance updates once the provider confirms the operation subscribe to the card transactions webhook or poll GET /api/cards/:cardId/transactions for the final status.

Body Parameters

Response
1
successBoolean

Top-level flag indicating whether the request was accepted.

2
messageString

Human-readable status of the request.

3
data.successBoolean

Provider-level acceptance flag. Returns false while the provider is still processing — watch the webhook for the final terminal state.

4
data.messageString

Provider-level status message (e.g. 'Card funding processing').

5
data.transactionObject

The card transaction record created for this operation. Identical shape to entries in the Card Transactions endpoint — see that section for per-field explanations.

6
data.transaction.typeString

'funding' for a fund request; 'withdrawal' for a withdraw request.

7
data.transaction.statusString

Lifecycle status. Starts as 'pending' on creation and transitions to 'completed' or 'failed' once the provider settles.

8
data.transaction.balance_beforeString

Card balance (smallest unit) before the operation. Equal to balance_after while the transaction is pending.

9
data.transaction.balance_afterString

Card balance (smallest unit) after the operation completes. Updates once the provider confirms.

10
data.transaction.fee_amountString

Fee charged for this operation, in the smallest unit. Funding and withdrawal both incur a 'funding_fee' fee_type.

11
metadata.request_idString

Request identifier for log correlation and support.

12
timestampDate

RFC 3339 / ISO 8601 server timestamp of when the response was generated (UTC).

Response Body

Update Card Status

A single endpoint flips a card between active and frozen, the direction is carried in the body as status: "frozen" | "active".

Freezing blocks all new authorizations while preserving the balance and PAN; unfreezing restores the card to full use. Use this for incident response (lost/stolen), temporary suspensions, or re-enabling after review.

Update Card Status
Body Parameters

Path Parameters
1
cardIdUUIDRequired

The unique identifier of the card to freeze or unfreeze.

Body Parameters
1
statusstringRequired

Target status: 'frozen' to block new authorizations, 'active' to restore. Other values are rejected.

Response Fields
1
successBoolean

Top-level flag indicating the request was accepted.

2
messageString

Human-readable outcome — 'Card frozen successfully' or 'Card activated successfully'.

3
data.successBoolean

Provider-level acceptance flag.

4
data.messageString

Provider-level status message.

5
data.cardObject

Slim card projection after the status change — includes identity, current status, masked PAN, balance, card brand, cardholder name, reference, and display amount. Not the full card record; call Get Card by ID for everything else.

6
data.card.statusString

New card status: 'frozen' or 'active'.

7
metadata.request_idString

Unique identifier for this API request, useful for log correlation.

8
timestampDate

Top-level RFC 3339 / ISO 8601 server timestamp (UTC).

Response Body

Terminate Card

Permanently terminate a card. This action is irreversible — any remaining balance is returned to your company wallet.

24-Hour Cooling Period

You cannot terminate a card within 24 hours of creation. The API will reject the request until the card has been active for at least 24 hours — freeze the card instead (POST /api/cards/:cardId/status with status: "frozen") if you need to block use immediately, then come back to terminate once the cooling period has passed.

Terminate Card

Path Parameters
1
cardIdUUIDRequired

The unique identifier of the card to terminate.

Body Parameters
1
reasonstringOptional

Reason for terminating the card. Stored for audit and compliance (e.g. 'Employee departure', 'Card compromised', 'End of contract').

Body Parameters

Response
1
card_idUUID

Identifier of the card that was terminated.

2
statusstring

Updated card status. 'terminated' after this operation.

3
remaining_balancestring

The balance that was on the card at the time of termination, in the currency's base units.

4
balance_returnedboolean

True if the remaining balance was returned to your company wallet.

5
terminated_atDate

RFC 3339 / ISO 8601 timestamp of when the card was terminated (UTC).

6
reasonstring

The reason provided on the request, echoed back.

What Happens Next

Terminated cards remain visible on GET /api/cards (with status: "terminated") and on GET /api/cards/:cardId so you can reconcile the final ledger. They cannot be funded, unfrozen, or reused — issue a new card if the cardholder needs continued spending.

Response Body
Error - 24-Hour Cooling Period

Update Spending Limits

Update the spending limits and merchant restrictions on a card. All fields are optional — only the fields you include will be updated.

Update Spending Limits

Path Parameters
1
cardIdstringRequired

The unique identifier of the card whose spending limits are being updated.

Body Parameters
1
single_transactionstring

Maximum amount allowed per individual transaction as a decimal string.

2
dailystring

Maximum total spending allowed per day as a decimal string.

3
weeklystring

Maximum total spending allowed per week as a decimal string.

4
monthlystring

Maximum total spending allowed per month as a decimal string.

5
allowed_categoriesarray

List of allowed MCC (Merchant Category Code) categories. Transactions at merchants outside these categories will be declined.

6
blocked_categoriesarray

List of blocked MCC categories. Transactions at merchants in these categories will be declined.

7
allowed_merchantsarray

Whitelist of specific merchant IDs. When set, only transactions at these merchants are allowed.

8
blocked_merchantsarray

Blacklist of specific merchant IDs. Transactions at these merchants will be declined.

Body Parameters

Response
1
card_idstring

Identifier of the card whose spending limits were updated.

2
operationstring

The operation type. Value is update_spending_limits for this endpoint.

3
spending_limitsobject

The full set of updated spending limits, including single_transaction, daily, weekly, monthly, allowed_categories, blocked_categories, allowed_merchants, and blocked_merchants.

4
updated_atstring

ISO 8601 timestamp of when the spending limits were last updated.

Response Body

Get Cards by Customer

Retrieve all cards belonging to a specific customer.

Get Cards by Customer

Path Parameters
1
statusstringRequired

Indicates whether the API request was successful or failed.

2
messagestringRequired

A human-readable message describing the result of the request.

3
cardsarrayRequired

A list of cards associated with the specified customer.

4
idstringRequired

The unique identifier of the card.

5
customer_idstringRequired

The unique identifier of the customer who owns the card.

6
card_typestringRequired

The type of card issued to the customer (e.g., virtual or physical).

7
card_brandstringRequired

The card network brand associated with the card (e.g., Visa or Mastercard).

8
last_fourstringRequired

The last four digits of the card number used for identification.

9
currencystringRequired

The currency the card operates in.

10
statusstringRequired

The current status of the card (e.g., active, inactive, blocked).

11
balancestringRequired

The current available balance on the card.

12
created_atstringRequired

The date and time when the card was created, returned in ISO 8601 format.

13
totalnumberRequired

The total number of cards returned in the response.

Response Body

Did you find this page useful?