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

# Crypto Wallets

> Accept stablecoin payments from your customers with one API call: a dedicated address per customer, every deposit tracked, your funds available at any time

**Accept USDC and USDT from your customers in minutes, not months.** One API call gives a customer their own deposit address. Every payment is attributed automatically, every deposit is reported to you, and the money collected is yours to withdraw whenever you decide.

<CardGroup cols={3}>
  <Card title="Live in one call" icon="bolt">
    `POST /wallets` returns a ready-to-use address. No node, no key, no blockchain code on your side.
  </Card>

  <Card title="Secured by design" icon="shield-halved">
    Funds are moved to cold storage, keys never leave KemyCard, and no API key can move your money.
  </Card>

  <Card title="Your funds, your call" icon="money-bill-transfer">
    Withdraw what you collected to your own address at any time, from your dashboard.
  </Card>
</CardGroup>

## The problem wallets solve

Collecting crypto with a single shared address means asking every payer for a transaction hash, matching payments by hand and fixing the mistakes. It breaks as soon as you grow.

With wallets, **the address is the reference**. A deposit on the address of customer A can only come from customer A: no memo, no hash, no manual matching, no support ticket.

## Why partners choose it

* **No friction for your team** — a single endpoint, a clear JSON response, and a call that is safe to repeat. Most integrations are done in an afternoon.
* **No friction for your customers** — they see an address, they send, it is done. The address never changes, so they can save it and pay again.
* **No infrastructure to run** — you do not generate keys, run nodes, watch blocks or move funds between addresses. We do it.
* **No volatility** — USDC and USDT only: what your customer sends is what you receive, in dollars.
* **Four networks** — Solana, Base, Ethereum and Tron: each customer pays on the network that is cheapest for them.
* **Open from KYC Level 1** — a customer can receive a wallet as soon as it is created. See [KYC levels](/guides/kyc-levels).
* **Predictable cost** — you pay for a wallet when you create one, not for every customer on every network.

## Security you can show your own customers

<AccordionGroup>
  <Accordion title="Funds are moved to cold storage" icon="vault" defaultOpen>
    Deposits do not sit on the collection addresses. They are swept to secured cold storage, and withdrawals are served from separate operating wallets. A collection address is a way in, not a place where funds are kept.
  </Accordion>

  <Accordion title="You never handle a private key" icon="key">
    Keys are generated and kept by KemyCard, encrypted at rest. They are never returned by the API, never shown in the dashboard and never sent to your servers: there is nothing for you to store, and nothing to leak on your side.
  </Accordion>

  <Accordion title="An API key cannot move your money" icon="lock">
    The API creates and lists wallets. Withdrawals are decided by the administrator of your partner account, from the dashboard. A leaked API key cannot send your funds anywhere.
  </Accordion>

  <Accordion title="Your data is isolated" icon="user-shield">
    You only ever see the wallets and the deposits of your own customers. A wallet code that belongs to another account answers `404`, exactly as if it did not exist.
  </Accordion>

  <Accordion title="Notifications you can trust" icon="signature">
    Every webhook is signed with HMAC-SHA256 using your endpoint secret, and retried if your server does not answer. You credit a customer only on a message you have verified. See [Webhooks](/guides/webhooks).
  </Accordion>

  <Accordion title="Nothing is lost if something fails" icon="rotate-left">
    If a wallet cannot be created, the creation fee is refunded automatically. If you call twice, you get the same wallet and you are charged once.
  </Accordion>
</AccordionGroup>

## What you can build

<CardGroup cols={2}>
  <Card title="Collect funds from your customers" icon="hand-holding-dollar">
    Top-ups of an account in your app, payment of an order or an invoice, deposits on a trading or savings product: give each customer their address and credit them when their deposit arrives.
  </Card>

  <Card title="On-ramp and off-ramp" icon="building-columns">
    Wallets are the crypto side of [virtual bank accounts](/api-reference/virtual-accounts/create): together they let your customers move between bank transfers and stablecoins.
  </Card>
</CardGroup>

## The only limit is your imagination

A wallet is a building block, not a finished product. There is no cap on the number of wallets you create or on the number of customers you serve: one address per customer, as many customers as your business reaches. What you build on top is up to you.

<CardGroup cols={3}>
  <Card title="Marketplaces" icon="store">
    One address per buyer, or one per order with a reference: you always know which sale a payment belongs to.
  </Card>

  <Card title="Top-ups and credits" icon="coins">
    Let users fund their balance in your app, game or platform with stablecoins, from anywhere in the world.
  </Card>

  <Card title="Invoices and subscriptions" icon="file-invoice-dollar">
    Give each client a permanent address: every payment they send is matched to their account.
  </Card>

  <Card title="Remittance and payouts" icon="paper-plane">
    Collect in stablecoins in one country and pay out where your customers need the money.
  </Card>

  <Card title="Savings and investment apps" icon="piggy-bank">
    Accept deposits from each saver on a dedicated address, without ever handling a private key.
  </Card>

  <Card title="One-time payment addresses" icon="rotate">
    A fresh address for every order, invoice or session, replaced after each payment. Each one is still tied to your customer.
  </Card>

  <Card title="Your idea" icon="lightbulb">
    If money has to come in from many people and be attributed to each of them, wallets do it.
  </Card>
</CardGroup>

## How it works

```
Step 1: Create the customer              → KYC Level 1 (basic)
Step 2: Create a wallet                  → You get a deposit address
Step 3: Show the address to the customer
Step 4: The customer sends USDC / USDT   → The deposit is attributed to this customer
Step 5: The deposit is reported          → In your dashboard and by webhook: credit the customer in your own system
Step 6: You withdraw the collected funds → At any time, to your own external address
```

Your customers never need to do anything other than send funds to their address.

## Every deposit is reported, every dollar is yours

**You always know who paid.** Each deposit received on the wallet of one of your customers appears in the **Wallets** section of your partner dashboard, with the customer, the blockchain, the amount and the date. The same deposit is sent to your server by [webhook](/guides/webhooks), so you can credit the customer in your own system without anyone opening the dashboard.

**You have one collection account per blockchain.** It is opened for you automatically, at no cost, with your first wallet on a blockchain, and it has its own address. Each deposit of a customer is credited to it, net of the deposit fee: a customer who sends 100 USDC on Solana adds to your Solana collected balance. You see the address and the balance of each account in the **Wallets** section of your dashboard.

**You withdraw when you want.** The deposits of all your customers are consolidated into these balances, per network. The administrator of your partner account can repatriate these funds **at any time** to your own external address, from the dashboard. You choose the moment and the destination.

### How to withdraw

1. Open the **Wallets** section of your dashboard and click **Withdraw** on the blockchain you want to withdraw from.
2. Enter the amount and the destination address. The commission, the network fee and the amount you will receive are shown before you confirm.
3. Confirm with your account password. The amount is debited from your collected balance and the transfer is processed automatically.
4. Follow it under **Your Withdrawals**, and receive the [`wallet.withdrawal_completed`](/guides/webhooks) webhook when it has been sent.

<Warning>
  **Check the destination address and the blockchain before you confirm.** A blockchain transfer cannot be cancelled or reversed. If the address is wrong, or if it is not an address on the blockchain you withdraw from, the funds are permanently lost and KemyCard cannot recover them.
</Warning>

<Info>
  Withdrawals are decided by you, from your dashboard. A customer cannot withdraw from their wallet: it is a collection address, and the funds it receives belong to your balance.
</Info>

## Supported networks

| `blockchain` | `currency` | Good to know |
| - | - | - |
| `solana` | `USDC` | Very low network fees, confirmed in seconds |
| `base` | `USDC` | Low network fees |
| `ethereum` | `USDC` | Highest network fees, widest compatibility |
| `tron` | `USDT` | The most used network for USDT |

## Create a wallet

```bash theme={null}
curl -X POST https://api.kemycard.com/v1/wallets \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_code": "bf75d143-e2ff-4872-8c93-cc6157f834aa",
    "blockchain": "solana"
  }'
```

```json theme={null}
{
  "success": true,
  "data": {
    "code": "01a11628-4600-7e59-bd4a-01604c588373",
    "customer_code": "bf75d143-e2ff-4872-8c93-cc6157f834aa",
    "blockchain": "solana",
    "currency": "USDC",
    "address": "CUSTOMER_DEPOSIT_ADDRESS",
    "status": "active",
    "created_at": "2026-10-07T11:38:19+00:00"
  }
}
```

Display `address` to your customer, together with the blockchain and the currency.

The wallet is created during the call: the address in the response is ready to receive funds. KemyCard sends no email when a wallet is created, neither to you nor to your customer: you stay in control of how the address is presented.

## Rules to know

* **One permanent wallet per customer and per blockchain.** Without a `reference`, a customer has one address on each network, and it never changes.
* **As many additional addresses as you need.** Add a `reference` to open another address for the same customer on the same blockchain. See [One-time addresses](#one-time-addresses).
* **Safe to call again.** Calling `POST /wallets` a second time for the same customer and blockchain returns the existing wallet with a `200` status. Nothing is created and nothing is charged, so you can call it every time you need the address.
* **Creation fee.** A fee is debited from your `others` [ops balance](/guides/ops-balance) each time a new wallet is created (`201`). It is refunded if the wallet cannot be created. Create a wallet when a customer actually needs one rather than for every customer on every network.
* **Deposit fee.** A fee is taken from each deposit before it is credited to your collection account. The [`wallet.deposit_received`](/guides/webhooks) webhook gives the amount sent, the fee and the net amount credited.
* **Withdrawal fees.** A withdrawal of your collected funds carries a commission, plus a fixed network fee that depends on the blockchain. After these fees, a withdrawal must leave you at least \$10. Both are shown in your dashboard and returned by `GET /wallets/balance` (`withdrawal_commission` and `withdrawal_network_fee`).
* **The address does not change.** It stays the same for the whole life of the wallet: your customer can save it and reuse it.

<Warning>
  A wallet only accepts **its own currency on its own blockchain**. Tell your customers clearly which network to use: funds sent on another network or in another token are not credited.
</Warning>

## One-time addresses

A permanent address is ideal when a customer pays you again and again. Sometimes you want the opposite: a **fresh address for each payment**, used once and then replaced. Add a `reference` of your choice and you get a new address for the same customer, on the same blockchain:

```bash theme={null}
curl -X POST https://api.kemycard.com/v1/wallets \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_code": "bf75d143-e2ff-4872-8c93-cc6157f834aa",
    "blockchain": "solana",
    "reference": "order-1001"
  }'
```

* **A new reference, a new address.** `order-1001`, `order-1002`, `order-1003`: three different addresses for the same customer. There is no cap on the number of addresses.
* **Rotate after each payment.** When a deposit arrives, create the next address with a new reference and show that one to your customer.
* **Safe to retry.** The same reference always returns the same address, and nothing is charged again.
* **You know what was paid.** The reference comes back as `wallet_reference` in the deposit list and in the `wallet.deposit_received` webhook: you match the payment to your order without any lookup.
* **Old addresses keep working.** A deposit sent later to a previous address is still credited to you and attributed to the same customer.

The creation fee applies to each new address.

## Retrieve wallets

```bash theme={null}
# All the wallets of your customers
curl "https://api.kemycard.com/v1/wallets?page=1&limit=20" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"

# The wallets of one customer
curl "https://api.kemycard.com/v1/wallets?customer_code=bf75d143-e2ff-4872-8c93-cc6157f834aa" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"

# One wallet
curl https://api.kemycard.com/v1/wallets/01a11628-4600-7e59-bd4a-01604c588373 \
  -H "Authorization: Bearer sk_live_YOUR_KEY"
```

The same list is available in the **Wallets** section of your partner dashboard, with a filter per blockchain.

## Follow deposits and your balance

```bash theme={null}
# Deposits received, most recent first (filters: customer_code, wallet_code)
curl "https://api.kemycard.com/v1/wallets/deposits?customer_code=bf75d143-e2ff-4872-8c93-cc6157f834aa" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"

# Your withdrawals (read-only: a withdrawal is requested from your dashboard)
curl https://api.kemycard.com/v1/wallets/withdrawals \
  -H "Authorization: Bearer sk_live_YOUR_KEY"

# Your collected balance, per blockchain
curl https://api.kemycard.com/v1/wallets/balance \
  -H "Authorization: Bearer sk_live_YOUR_KEY"
```

Use the webhook to react in real time, and `GET /wallets/deposits` to reconcile: every deposit carries its `tx_id`, the amount sent, the fee and the net amount credited to you.

## Test it first

With a `sk_test_` key, `POST /wallets` returns a demo wallet with a fake address: nothing is created and nothing is charged. Never send funds to an address returned in [test mode](/getting-started/test-mode).

## Next steps

<CardGroup cols={2}>
  <Card title="Create a Wallet" icon="plus" href="/api-reference/wallets/create">
    Full reference of the endpoint
  </Card>

  <Card title="Webhooks" icon="bell" href="/guides/webhooks">
    Wallet events sent to your server
  </Card>
</CardGroup>


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