Skip to main content
CBPay cards spend Just-In-Time from the account’s central balance: no prefunding, no moving balance around. Each card picks which balance it spends from (spending_asset: USD, USDT, USDC, BTC, GOLD, SILVER or PLATINUM, USD by default). USD, USDT and USDC are 1:1 with the dollar; BTC and GOLD convert at the price of the moment of each event. Every purchase is authorized in real time against that asset’s available balance and the card’s own limits, and the debit shows up immediately in the movement history.

How many cards you can hold

Each card spends from the account’s central balance in its configured asset (spending_asset, USD by default). Fine-grained control is per-card spending limits (per transaction, daily, monthly), always measured in USD, which you can change at any time.

Choosing the spending balance (USD, USDT, USDC, BTC, GOLD, SILVER or PLATINUM)

Set spending_asset when creating the card or change it later with PATCH. It only affects future purchases: in-flight authorizations keep the asset they were debited in (and their reversal returns that same asset).
USDT and USDC are both worth 1 USD, so the conversion is exact 1:1 with no exchange fee: a 25.00 USD purchase debits 25.000000 of the chosen asset. BTC and GOLD convert at the effective price of the moment of each event (the same settlement price you see in GET /v1/rates, settlement block):
  • Authorization: the purchase’s equivalent in your asset is reserved plus a small cushion (not a charge: it covers price drift until clearing and is returned at capture). If the execution price is not available at that moment, the purchase is declined (pricing_unavailable) — your balance is never converted with an untrustworthy price.
  • Settlement (capture): the final amount is re-converted at the price of the capture moment; the cushion’s excess returns to your balance (or the difference is debited if the price moved beyond the cushion).
  • Reversal of an authorization: the EXACT reserved amount is returned, with no conversion.
  • Refunds and adjustments after capture: re-converted at the price of the moment of the event. The price may move between the purchase and the refund — you receive the equivalent in your asset at that moment’s price, not the original quantity.
  • BTC/GOLD/SILVER/PLATINUM purchases share your account’s volatile-asset limits (per operation and 24h volume, visible in GET /v1/settlement).
If the chosen asset’s balance is short, the purchase is declined with insufficient_funds — there is no automatic fallback to another balance.
With BTC/GOLD/SILVER/PLATINUM your balance is exposed to price moves between a purchase’s events (authorization, capture, refund). Every conversion uses the effective price of its moment — CBPay never re-quotes amounts backwards nor deducts “just in case”: the authorization cushion is always returned at settlement.

Costs (configured by your operator, can be 0)

Exact amounts come from GET /v1/rates (fees field). Every issuance charge is automatically refunded if issuance fails.

Per-purchase fee (lifecycle)

The per-transaction fee follows the same lifecycle as the purchase:
  • Authorization: the estimated fee is reserved inside the hold together with the purchase amount, in the card’s spending_asset (the percent applies over the purchase’s USD amount; in BTC/GOLD/SILVER/PLATINUM it converts with the same event price).
  • Settlement: the fee is recalculated with the configuration in force at that moment and the definitive one is charged (card_fee in your movements); the difference against the estimate is released or charged together with the cushion adjustment.
  • Reversals and downward adjustments: the fee is prorated back to the refunded fraction of the purchase (card_fee_refund).
If your operator changes the percent between authorization and settlement, the settlement fee is charged — the same criterion as the BTC/GOLD/SILVER/PLATINUM price per event. Declined purchases charge no fee.

Create a card

The flow depends on whether your account is a person or a company — pick your tab. The common rule: the cardholder is verified ONCE per account, on the first issuance; subsequent cards reuse it with no data. The idempotency_key is always required (a retry with the same key returns the original card and never double-charges).
New physical issuance is temporarily unavailable. A request with physical: true returns 400 physical_temporarily_unavailable; this cutoff is checked after idempotency replay, so a replay of an existing physical request still returns its original card. Physical cards that were already issued continue operating.
A person account issues cards for itself (at most 1 live card total; new physical issuance is temporarily unavailable).Your first card creates and verifies your holder at the issuer. Since your account already approved its identity verification, your data and documents auto-fill from your verification — you only add the issuer-specific fields (occupation, salary_usd); any field you send explicitly wins over the autofill:
occupation is a catalog code (see below) and salary_usd is whole US dollars. If your verification was done through the wizard without some data or document the issuer requires, add it explicitly to the cardholder (first_name, email, address, id_front_url…, same format as always).A second issuance request is not available for a person account once it already has one live card or one open application. It returns 409 card_limit_reached: (the physical one, for example) asks for no data — your holder is already verified:
A physical request returns 400 physical_temporarily_unavailable even when the account has no card. Use a digital card request instead.

Printed name

The card’s printed name is optional in the request. Send cardholder.first_name and cardholder.last_name when the legal name from the approved profile is longer than the issuer’s 22-byte printing limit or when you need a shorter display name. If you omit either field, the approved KYC/KYB profile supplies it during autofill. An explicit field always wins over the profile value. After trimming surrounding whitespace, the API counts the UTF-8 bytes of both fields together. A total above 22 is rejected with 422 cardholder_name_too_long before the issuance hold or fee. This is a byte limit, not a Unicode-character limit.
The response exposes the effective value as cardholder_name:

Issuer fields and AML-derived PEP

The first issuance creates the issuer-side cardholder. The platform validates the issuer fields before charging the issuance fee or creating a hold. When an existing account holder is reused, these fields are not requested again. For an account holder, the supported PEP source is the account’s AML verification screening. The screening gate is mandatory: an explicit pep: true does not bypass 422 screening_required; once screening exists, the value sent to the issuer is the conservative OR of the request boolean and the screening result, so a request false never overrides a screening true. The checklist displays the result as Politically exposed person (screening). Company contact and legal-representative fields are completed from KYB UBO data when the request does not provide them. Company document URLs are completed from the KYB file using these fallbacks: business_license_url has no fallback. If the assembled holder is still missing required issuer data, the API returns HTTP 422 with the missing keys and no issuer call is made:

Catalogs

Use the live catalogs rather than typing labels or inventing codes:
Each response has the shape {"items":[{"code":"...","label":"..."}],"meta":{"retrieved":"..."}}. Send items[].code in occupation or kind_of_business; a label such as "Engineer" is not accepted as a code. The same code validation is used by the firewall checklist, so a value can be present and still be marked ok: false when it is not in the catalog.
The issuer-side PEP value cannot be derived. Complete an approved AML verification and retry the same card request; do not guess a PEP value.
Because a designated person is not the account holder, the request must carry an explicit boolean cardholder.pep. It has no default.

Availability and issuance errors

Availability and issuance errors

Availability and issuance errors

Availability and issuance errors

Availability and issuance errors

Availability and issuance errors

Availability and issuance errors

Availability and issuance errors

Availability and issuance errors

Availability and issuance errors

Availability and issuance errors

Availability and issuance errors

Availability and issuance errors

Availability and issuance errors

Availability and issuance errors

Availability and issuance errors

Availability and issuance errors

Availability and issuance errors

Response (same shape in every case):
Application review. If your organization enabled card application review, POST /v1/cards can answer 202 Accepted with {"status":"in_review","kind":"card_application","review_id":"…"} instead of 201 — the card is issued only when compliance approves the review. The creation fee is charged when the application is held and refunded automatically if it is rejected. Track the result with the webhook txn_review_status_changed or in Transaction reviews.
You can pin the spending balance from the start by adding "spending_asset": "USDC" to the creation body (USD if omitted).
Documents are actually validated by the issuer: URLs must point to legitimate, reachable documents. If they are missing or insufficient, issuance fails (422 core_rejected or 409 cardholder_kyc_pending), the fee is refunded automatically and you can retry with corrected data.
Person or company? The differences between both account types across ALL products are summarized in persons and companies.

Occupation and business activity (catalog codes)

When designating a person, occupation must be a code from the official catalog (not free text); for a company, so must kind_of_business. Look them up (searchable with ?q=):
Each item is { "code": "...", "label": "..." }. Use the code in occupation / kind_of_business. An out-of-catalog value returns 400 invalid_occupation or 400 invalid_kind_of_business before reaching the issuer. salary_usd is in dollars (integer).

Physical cards: activation

A physical card is born pending_activation and travels inactive for security. Once the holder has it in hand:

Reveal PAN and CVV (sensitive data)

Only the owning account can reveal them (never the org admin). The response is one-shot: display it to the holder and discard it.
Never store or log the PAN/CVV. CBPay does not persist it either: the response comes straight from the issuer (PCI standard).

Limits and freeze/unfreeze

Update limits
"0" removes a limit. To freeze (declines every purchase instantly):
Freeze

Transactions and their lifecycle

spend_asset / spend_amount show which balance the purchase actually debited and how much in that asset (amount_usd / amount_usdt remain the USD reference value). For BTC/GOLD/SILVER/PLATINUM, an authorized transaction’s spend_amount includes the reserve cushion; after settlement it shows the final amount. fee_asset / fee_amount are the asset and amount of the per-purchase fee (definitive once settled; estimated while authorized). fee_refunded_amount appears once a refund applies from reversals or downward adjustments. When your operator does not configure a per-purchase fee, the fee_* fields are not included in the transaction — the historical behavior is unchanged. If settlement arrives for a different amount than authorized (tips, merchant conversion), the adjustment is applied automatically: positive debits the difference, negative returns it.

Cancel a card

Irreversible. Bills card_cancellation when configured.

Webhooks

Subscribe the same way as every other event (see Webhooks).

FAQ

No. Cards hold no balance of their own: every purchase is authorized in real time against the account’s balance (in the card’s spending asset). If the balance covers it and the purchase respects the limits, it is approved.
They all spend from the account’s central balances. Each authorization debits atomically: you can never spend more than the asset’s available balance, no matter how many cards operate in parallel.
Purchases are processed in USD and debited from the card’s configured balance (spending_asset). USD, USDT and USDC are 1:1 with the dollar, with no conversion fee; BTC and GOLD convert at the effective price of the moment of each event (the same one in the settlement block of GET /v1/rates).
Yes: spending_asset is per card. A company can have, for example, corporate cards spending USDT, employee cards spending USDC and a personal one spending BTC. Changing it with PATCH only applies to future purchases.
Network settlement arrives 1-2 days after the authorization, and the BTC/gold price can move in between. That is why the authorization reserves the purchase’s equivalent plus a small percentage. It is not a charge: at settlement, the purchase is re-converted at that moment’s price and everything reserved in excess automatically returns to your balance.
The purchase is declined (pricing_unavailable) — CBPay never converts your balance with an untrustworthy price. It is a transient condition (degraded price feed): retry in a few minutes or switch the card to USDT/USDC. Events that cannot be declined (the settlement of an already-approved purchase, a refund) are never blocked: they are processed with the last known price plus a prudential margin, audited in the movement.
Refunds convert at the price of the refund moment, not the purchase’s: you receive the equivalent in your asset of the refunded USD amount. If BTC went up since the purchase you receive less BTC (same USD value); if it went down, more. Your BTC/GOLD/SILVER/PLATINUM balance is always exposed to the price — that is the nature of spending from a volatile asset.
The authorization reserves an estimated fee inside the hold. At settlement the fee is recalculated with the configuration in force at that moment: if your operator changed the percent between both events, the settlement fee applies. The difference against the estimate is released or charged together with the purchase adjustment — never as a separate movement.
The card is frozen automatically (card_status_changed event with reason: monthly_fee_unpaid). No debt accrues; once the balance is topped up, unfreeze it with PATCH { "frozen": false }.
Company accounts can issue for any designated person. That person must have an approved KYC verification — you pass their verification_id in the cardholder and their data and documents auto-fill. The card always spends from the balance of the issuing company account.
The general error catalog lives in Errors.

USD as the principal ledger asset

Accounts use USD as the default for settlement_asset and payin_settlement_asset; change it any time with PUT /v1/settlement. In-flight operations are never re-quoted. USD ledger amounts use cents (two decimal places). Direct credits and debits, fees, and supported payout, checkout, POS, and card paths use USD only where their asset field accepts it. Swaps between USD and USDT use 1:1 pricing and do not use an FX oracle. BOB, MXN, and ARS remain separate fiat-ledger assets; v1 money-out pricing for those assets remains unavailable. A payin credited directly to a USD-principal account exposes credit_asset: USD and the credited fiat amount in cents; usdt_credited remains the USD-equivalent reporting field. A controversy hold follows the credited asset: USD credits use hold_asset: USD. disputed and held use hold-asset units; disputed_usdt and held_usdt are normalized equivalents.
Last modified on October 4, 2026