Skip to main content
Cards are topped up from stablecoins deposited for the cardholder (applicant). Apocor exposes one receive address and a one-click fund call. You choose the product mode per program.

How money moves

Each applicant has three balances, and funds flow through them in order:
  1. Deposit wallet — where on-chain stablecoin deposits land (GET …/funding/deposit-address).
  2. Spend account — the applicant’s USD balance. Deposits are swapped in automatically when a funding call needs them.
  3. Card funds — the budget (debit programs) or per-card balance (prepaid programs) that transactions draw from. Top up with POST /v1/cards/{id}/fund-from-wallet, or move USD explicitly with POST /v1/accounts/{id}/transfers.
You never have to move money between pots 1 and 2 yourself: both fund-from-wallet and transfers (direction "in") auto-convert deposited stablecoins to USD when the spend balance is short, and report what they converted in a swapped array.
Card issuance charges an opening fee from the card funds pot. Make sure the applicant’s funding is in place before the first POST /v1/cards, or issuance fails with an issuer Balance insufficient error. The whole first-card flow is three steps: deposit stablecoins → one POST /v1/accounts/{id}/transfers with direction: "in" (auto-converts the deposit and fills the budget) → issue the card.
Both modes use the same deposit address and the same POST /v1/cards/{id}/fund-from-wallet call. BYO only adds the configured send-from wallet on the program and on deposit-address responses.
Upstream issuer / crypto-rail names never appear in responses. You only see Apocor fields.

Testing deposits with TEST keys

The TEST environment runs on issuer testnets. Deposits are only detected for: Request the deposit address with ?chain=ETH&currency=USDC, then send testnet USDC (Ethereum Sepolia) from the Circle faucet. Credits appear in funding/balances within a couple of minutes.
Other chains (Base, Arbitrum, Optimism, Polygon, Solana) generate valid addresses in TEST but deposits on them never credit — the issuer sandbox supports withdrawals only on those chains. Testnet funds sent there are unrecoverable. In LIVE, all configured chains support deposits normally.

1. Set the program funding mode

Wallet service (default)

Bring-your-own (BYO) wallet

byo.address is required — the user’s external wallet they will send from.
Read back with GET /v1/programs/{id}/funding-config.

2. Get the deposit address

After the applicant has completed identity verification (status: APPROVED):
With TEST keys use chain=ETH — the issuer sandbox only credits deposits on Ethereum Sepolia (see Testing deposits).
Example BYO response:
  • address — always the receive address (send to this).
  • byo_wallet.address — only in byo_wallet mode; the configured send-from wallet.

3. Check balances

Use available_to_fund_usd to know when you can fund: it is the sum of the USD spend balance plus stablecoin deposits that can still be converted. It does not include amounts already moved into budgets — check those with GET /v1/accounts/{id}/budgets.

4. Fund the card

This swaps deposited stables → USD and credits the card’s spend pot. Minimums are enforced by the rail (typically ≥ $0.50). Idempotency-Key is required on fund, fund-from-wallet, and defund — retries with the same key replay the original response for 72 hours.

Budgets (debit programs)

Debit programs spend from budgets — named pots of USD that cards draw from. Every applicant gets a default budget automatically the first time funds move or a card is issued; you can create more to ring-fence spend (e.g. “Marketing” vs “Travel”).

Top up a budget

direction: "in" funds the budget (auto-converting deposits if needed); direction: "out" withdraws back to the spend account. Pass budget_id to target a specific budget — omitted, the default budget is used. If deposits plus spend balance still don’t cover the amount, you get 402 INSUFFICIENT_FUNDS. Idempotency-Key is optional here but honored — send one to make retries safe.

Named budgets

Bind a card to a budget at issuance by passing budget_id to POST /v1/cards (defaults to the default budget). The card’s spending and its fund-from-wallet top-ups then use that budget.

Flow

Errors to expect

  • Programs & accounts — create the program first
  • Cards — issue the prepaid card before funding
  • API reference: PUT /v1/programs/{id}/funding-config, GET …/funding/deposit-address, POST /v1/cards/{id}/fund-from-wallet