Skip to main content

Overview

Internal wallets are platform-managed custodial wallets that hold user cryptocurrency across various blockchain networks. Each user can have multiple internal wallets for different networks and currencies, with the platform securely managing all private keys.

Creating Internal Wallets

Create one or more internal wallets for a user with a single API call:
curl -X POST "https://api.example.com/v1/wallet/internal" \
  -H "x-client-key: YOUR_PUBLIC_KEY" \
  -H "Authorization: Bearer USER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "wallets": [
      {
        "network": "linea",
        "currency": "usdc"
      }
    ]
  }'
Wallet creation is idempotent. If a wallet already exists for the specified network and currency combination, the API returns success without creating a duplicate.

Network and Currency Combinations

NetworkSupported CurrenciesMemo Required
lineausdc, usdtNo
ethereumusdc, usdtNo
solanausdc, usdt, solNo
xrpxrpYes (destination tag)
bitcoinbtcNo
Always specify both network and currency as a matching pair. For example, specify xrp for both network and currency when creating an XRP wallet.

Retrieving Internal Wallets

Get all internal wallets for the authenticated user:
curl -X GET "https://api.example.com/v1/wallet/internal" \
  -H "x-client-key: YOUR_PUBLIC_KEY" \
  -H "Authorization: Bearer USER_ACCESS_TOKEN"

Response Fields

FieldTypeDescription
idstringWallet identifier for transaction history queries
balancestringCurrent wallet balance in the specified currency
currencystringCurrency held in this wallet
addressstringBlockchain address for deposits
addressMemostring|nullDestination tag/memo (required for XRP and similar networks)
addressIdstringIdentifier for linking wallet to card
typestringAlways “INTERNAL” for custodial wallets
The addressId field is required when linking wallets to cards. Keep this identifier for card linking operations.

Understanding Wallet Addresses

Standard Addresses (Most Networks)

For most networks (Ethereum, Linea, Solana, Bitcoin), only the address field is needed:
{
  "address": "0x0a4b21fa733e9aeaddbf070302a85c559de13c4d",
  "addressMemo": null
}
Users can deposit funds by sending cryptocurrency to this address.

Memo-Required Networks (XRP, Stellar)

Some networks require a memo/destination tag to identify the recipient:
{
  "address": "rNxp4h8apvRis6mJf9Sh8C6iRxfrDWN7AA",
  "addressMemo": "78"
}
For memo-required networks, users MUST include both the address AND the memo when depositing. Missing the memo may result in lost funds or delayed processing.
Display to Users:
Address: rNxp4h8apvRis6mJf9Sh8C6iRxfrDWN7AA
Destination Tag: 78

Checking Wallet Balances

Balances are returned when retrieving wallet list:
async function getWalletBalance(currency) {
  const response = await fetch('https://api.example.com/v1/wallet/internal', {
    headers: {
      'x-client-key': 'YOUR_PUBLIC_KEY',
      'Authorization': `Bearer ${userToken}`
    }
  });

  const wallets = await response.json();
  const wallet = wallets.find(w => w.currency === currency);

  return wallet ? parseFloat(wallet.balance) : 0;
}

const usdcBalance = await getWalletBalance('usdc');
console.log(`USDC Balance: ${usdcBalance}`);

Receiving Deposits

Once a wallet is created, users can deposit funds by sending cryptocurrency to the wallet address.

Deposit Flow

1

Display Deposit Address

Show the wallet address (and memo if applicable) to the user in your application.
2

User Initiates Transfer

User sends cryptocurrency from their external wallet or exchange to the displayed address.
3

Blockchain Confirmation

Transaction is confirmed on the blockchain (timing varies by network).
4

Balance Update

Platform detects the deposit and updates the wallet balance automatically.
5

Notify User

Poll wallet balance or implement webhooks to notify user of confirmed deposits.

Network Confirmation Times

NetworkTypical Confirmation Time
Linea1-2 minutes
Ethereum5-15 minutes
Solana5-30 seconds
XRP3-5 seconds
Bitcoin10-60 minutes
Confirmation times vary based on network congestion and gas prices. Display expected timing to users to set proper expectations.

Deposit Example UI

function DepositAddress({ wallet }) {
  const copyToClipboard = (text) => {
    navigator.clipboard.writeText(text);
  };

  return (
    <div className="deposit-container">
      <h3>Deposit {wallet.currency.toUpperCase()}</h3>

      <div className="address-field">
        <label>Address</label>
        <div className="address-display">
          <code>{wallet.address}</code>
          <button onClick={() => copyToClipboard(wallet.address)}>
            Copy
          </button>
        </div>
      </div>

      {wallet.addressMemo && (
        <div className="memo-field">
          <label>Destination Tag (Required)</label>
          <div className="address-display">
            <code>{wallet.addressMemo}</code>
            <button onClick={() => copyToClipboard(wallet.addressMemo)}>
              Copy
            </button>
          </div>
          <p className="warning">
            ⚠️ You must include this destination tag or your funds may be lost
          </p>
        </div>
      )}

      <div className="network-info">
        <p>Network: {wallet.network}</p>
        <p>Expected confirmation: 1-2 minutes</p>
      </div>
    </div>
  );
}

Wallet Transaction History

View transaction history for a specific internal wallet:
curl -X GET "https://api.example.com/v1/wallet/history?walletId=098aeb90-e7f7-4f81-bc2e-4963330122c5&walletType=INTERNAL&walletCurrency=usdc&page=0" \
  -H "x-client-key: YOUR_PUBLIC_KEY" \
  -H "Authorization: Bearer USER_ACCESS_TOKEN"

Query Parameters

ParameterRequiredDescription
walletIdYesThe wallet id from GET /v1/wallet/internal
walletTypeYesMust be “INTERNAL” for internal wallets
walletCurrencyYesCurrency of the wallet (e.g., “usdc”, “xrp”)
pageNoPage number (zero-indexed). Defaults to 0
Transaction history is paginated with 10 transactions per page, ordered by date descending (newest first).

Linking to Cards

Internal wallets can be linked to cards for payments. See the dedicated guide for details: Card Linking Guide → Quick Example:
curl -X POST "https://api.example.com/v1/wallet/internal/card_linked" \
  -H "x-client-key: YOUR_PUBLIC_KEY" \
  -H "Authorization: Bearer USER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "addressId": "7c1839ee-918e-4787-b74f-deeb48ead58b"
  }'

Use Cases

Create wallets for different currencies to allow users to hold and spend various cryptocurrencies. For example, create USDC on Linea for low fees and USDT on Ethereum for broader compatibility.
Provide users with deposit addresses to fund their accounts from exchanges like Coinbase or Binance. Users send crypto from their exchange to their internal wallet address.
Support users on different blockchain networks. Create Solana wallets for users in the Solana ecosystem and Ethereum wallets for users in the EVM ecosystem.
For users new to cryptocurrency, internal wallets provide a familiar account-based experience without requiring wallet software or seed phrase management.
Link internal wallets to cards so users can spend their cryptocurrency holdings for everyday purchases without manual transfers.

Error Handling

Wallet Already Exists

{
  "error": "Wallet already exists",
  "code": "WALLET_ALREADY_EXISTS",
  "message": "A wallet for this network and currency combination already exists"
}
Solution: This is expected behavior. The existing wallet is returned in GET requests. No action needed.

Unsupported Network

{
  "error": "Unsupported network",
  "code": "WALLET_UNSUPPORTED_NETWORK",
  "message": "The specified network is not supported in this environment"
}
Solution: Verify the network name and ensure it’s supported in your environment configuration. Contact support for network availability.

Invalid Currency for Network

{
  "error": "Invalid currency",
  "code": "WALLET_INVALID_CURRENCY",
  "message": "The specified currency is not supported on this network"
}
Solution: Ensure the currency is valid for the specified network. For example, you cannot create a BTC wallet on the Ethereum network.

Best Practices

Create Wallets Proactively

Create wallets during user onboarding rather than when needed for a transaction. This reduces friction and provides immediate deposit addresses.

Display Clear Instructions

For memo-required networks, prominently display both the address and memo with clear warnings about including both values.

Monitor Deposits

Poll wallet balances or implement webhook notifications to detect deposits quickly and update your UI in real-time.

Show Transaction History

Display transaction history to help users track their activity and verify deposits/withdrawals.

Handle Network Delays

Inform users about expected confirmation times and display pending transactions separately from confirmed balances.

Provide Copy Functionality

Always include a “copy to clipboard” button for addresses and memos to prevent user input errors.

US Environment

For US-based users, route requests to the US environment:
curl -X GET "https://api.example.com/v1/wallet/internal" \
  -H "x-client-key: YOUR_PUBLIC_KEY" \
  -H "Authorization: Bearer USER_ACCESS_TOKEN" \
  -H "x-us-env: true"

Next Steps