Set Up Deposit/Withdraw Wallet

Overview

The deposit/withdraw wallet is a self-custody hot wallet used for day-to-day customer operations. This wallet holds the smallest amount of funds and has no restrictive policies, allowing spenders to freely process customer deposits and withdrawals.

In the custody starter architecture, this wallet:

  • Holds the smallest amount of assets (only what you need for daily operations).
  • Has no policies or minimal policies for maximum operational flexibility.
  • Allows spenders to withdraw freely without approval requirements.
  • Receives customer deposits.
  • Processes customer withdrawals.

Prerequisites

Create Deposit/Withdraw Wallet

Generate a self-custody hot wallet using BitGo Express or the SDK. You configure this wallet without restrictive policies to enable rapid customer transactions.

Endpoint: Generate Wallet

export BITGO_EXPRESS_HOST="<YOUR_LOCAL_HOST>"
export COIN="<ASSET_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export ENTERPRISE="<YOUR_ENTERPRISE_ID>"
export PASSPHRASE="<YOUR_WALLET_PASSPHRASE>"
export LABEL="<YOUR_DESIRED_WALLET_NAME>"

curl -X POST \
  http://$BITGO_EXPRESS_HOST/api/v2/$COIN/wallet/generate \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "enterprise": "'"$ENTERPRISE"'",
    "passphrase": "'"$PASSPHRASE"'",
    "label": "'"$LABEL"'",
    "multisigType": "onchain",
    "type": "hot"
}'
const { BitGo } = require('bitgo');

const accessToken = '<YOUR_ACCESS_TOKEN>';

const bitgo = new BitGo({
  accessToken: accessToken,
  env: 'prod',
});

async function createDepositWithdrawWallet() {
  const newWallet = await bitgo.coin('<ASSET_ID>').wallets().generateWallet({
    label: 'Deposit-Withdraw Wallet - Hot',
    passphrase: '<YOUR_WALLET_PASSPHRASE>',
    enterprise: '<YOUR_ENTERPRISE_ID>',
    multisigType: 'onchain',
    type: 'hot'
  });

  console.log('Deposit/Withdraw Wallet Created:');
  console.log('Wallet ID:', newWallet.wallet.id());
  console.log('Receive Address:', newWallet.wallet.receiveAddress());

  // IMPORTANT: Save the backup keychain securely
  console.log('Backup Keychain (SAVE SECURELY):', newWallet.backupKeychain);
}

createDepositWithdrawWallet();

Step Result

📘

Note

This response contains critical key material. Save the backup keychain in a secure place.

{
  "wallet": {
    "id": "7849948ac0623f81f74f63dbd8351d5g",
    "users": [
      {
        "user": "62ab90e06dfda30007974f0a52a12995",
        "permissions": ["admin", "spend", "view"]
      }
    ],
    "coin": "btc",
    "label": "Deposit-Withdraw Wallet - Hot",
    "m": 2,
    "n": 3,
    "keys": [
      "78499487e6c77351bd3bbf04281fa8cc",
      "78499487cd07fc57de18f6481baa1904",
      "7849948902be620840a384c148d19980"
    ],
    "enterprise": "62c5ae8174ac860007aff138a2d74df7",
    "approvalsRequired": 1,
    "isCold": false,
    "type": "hot",
    "multisigType": "onchain",
    "receiveAddress": {
      "address": "bc1p..."
    }
  },
  "userKeychain": {
    "id": "78499487e6c77351bd3bbf04281fa8cc",
    "pub": "xpub661MyMwAqRbcEst4tb4F36AfvoFtAy7U9viB7zapRqNnXhPknsPwNqhxpD1CqMGSGhq3hDMKQR1Br8gGxYygoR6SGic3XdJoTEzM5v9wyFy",
    "source": "user",
    "encryptedPrv": "{...}"
  },
  "backupKeychain": {
    "id": "78499487cd07fc57de18f6481baa1904",
    "pub": "xpub661MyMwAqRbcEfnfBkVRk9BB1SrYaFR884ndYpmNXnci6U2wrAQCsFiD21c49Aq7EvtK6QFzDzMwmFKVqi1bTL7kmuCEJ78bFn9Rq6NyLDV",
    "source": "backup",
    "encryptedPrv": "{...}"
  },
  "bitgoKeychain": {
    "id": "7849948902be620840a384c148d19980",
    "pub": "xpub661MyMwAqRbcGCXsEAmctkLstGa92f5ugiD3hvCL3Wyt8BqHYGCVsL2x6PgNgJeq8Aabtz92sMzq4Ezac459QkDmxowKqoL35gNJXEJDdeo",
    "source": "bitgo",
    "isBitGo": true
  }
}
📘

Note

Save the wallet ID and backup keychain from the response. You need the wallet ID to configure whitelist policies with the standby wallet.

Policy Configuration

The deposit/withdraw wallet is intentionally configured with no restrictive policies to enable rapid customer transactions. Spenders can freely initiate and complete withdrawals without approval requirements.

If your use case requires some level of control, consider these optional lightweight policies:

  • Velocity limit alerts: Configure notifications when withdrawal volume exceeds thresholds (without blocking transactions).
  • Monitoring webhooks: Set up webhooks to track all transactions for audit purposes.
📘

Note

Adding approval requirements to this wallet defeats the purpose of having a free-spending operational wallet. Only add policies if your compliance requirements mandate them.

Withdrawal Flow

Since this wallet has no approval policies, withdrawals can use either the simple or manual flow. Choose the appropriate tab based on your wallet type (Multisig or MPC) and preferred level of control.

The simple withdrawal flow for self-custody multisignature hot wallets enables you to build, sign, and send transactions, all in one call, using BitGo Express. The simple flow suffices for most multisignature use cases. If you require more granular control, see the Multisig Hot Manual tab.

The simple flow also supports sending to many recipients in 1 transaction, lowering the aggregate amount of blockchain fees when compared to creating multiple transactions.

1. Build, Sign, and Send Transaction

Build and sign the transaction and send it to BitGo, all in one call.

Endpoint: Send Transaction

export BITGO_EXPRESS_HOST="<YOUR_LOCAL_HOST>"
export COIN="<ASSET_ID>"
export WALLET_ID="<YOUR_WALLET_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export WALLET_PASSPHRASE="<YOUR_WALLET_PASSPHRASE>"
export ADDRESS="<DESTINATION_ADDRESS>"
export AMOUNT="<AMOUNT_IN_BASE_UNITS>"

curl -X POST \
  http://$BITGO_EXPRESS_HOST/api/v2/$COIN/wallet/$WALLET_ID/sendcoins \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "address": "'"$ADDRESS"'",
    "amount": "'"$AMOUNT"'",
    "walletPassphrase": "'"$WALLET_PASSPHRASE"'",
    "type": "transfer",
    "txFormat": "psbt"
}'
const tx = await wallet.send({
  address: '<DESTINATION_ADDRESS>',
  amount: '<AMOUNT>',
  walletPassphrase: '<YOUR_WALLET_PASSPHRASE>',
  txFormat: 'psbt',
  type: 'transfer'
});

console.log('Transaction sent:', tx.txid);
📘

Note: If you are building transactions for a UTXO asset in quick succession, BitGo recommends reserving unspents by passing the reservation and expireTime parameters. Reserving unspents avoids errors by ensuring the UTXO are not included in subsequent builds.

Step Result

BitGo uses the data you pass to build a half-signed transaction. Since this wallet has no approval policies, BitGo applies the final signature using the BitGo key and broadcasts the transaction to the blockchain immediately.

{
  "transfer": {
    "entries": [
      {
        "address": "2N1poiHTi5ur8hz5QBhNoy88bYzqrWYvBbV",
        "wallet": "6553e933288be490293ae748efafeaaf",
        "value": -100000,
        "valueString": "-100000"
      },
      {
        "address": "2Myx8nY8ReERqUwu9H96Lb2K4yYjs3xY8GH",
        "value": 10000,
        "valueString": "10000",
        "isChange": false,
        "isPayGo": false
      },
      {
        "address": "tb1q5xtred89revxp789r6dmvyf74vgecczp2ch2hvhlj8anjkcepqtspu7j7d",
        "wallet": "6553e933288be490293ae748efafeaaf",
        "value": 331419,
        "valueString": "331419",
        "isChange": true,
        "isPayGo": false
      }
    ],
    "id": "6553ee12d5a49ecc9baccdcbe0563448",
    "coin": "tbtc4",
    "wallet": "6553e933288be490293ae748efafeaaf",
    "walletType": "hot",
    "txid": "e7648c85edac7f9870e511b4ef95b62b1878556791bd52ac715cb2cd4b466e6f",
    "state": "signed",
    "type": "send"
  },
  "txid": "e7648c85edac7f9870e511b4ef95b62b1878556791bd52ac715cb2cd4b466e6f",
  "status": "signed"
}

Customer Deposits

Share the wallet receive address with customers to receive deposits. For enhanced privacy, create unique addresses for each customer or transaction.

const wallet = await bitgo.coin('<ASSET_ID>').wallets().get({ id: '<DEPOSIT_WITHDRAW_WALLET_ID>' });

// Create a new receive address
const address = await wallet.createAddress({ label: 'Customer ABC Deposit' });
console.log('New deposit address:', address.address);

For more details, see Create Receive Addresses.

Next

Create Whitelists (Standby-Deposit tab)

See Also