Skip to main content
This guide covers all funding methods, status tracking, and edge cases for moving money in and out of investment wallets.

Deposit methods

ACH via Plaid

Pull funds from a linked bank account. Requires a linked bank account.
curl -X POST "$BASE_URL/accounts/$ACCOUNT_ID/deposits" \
  -H "Authorization: Basic $AUTH" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: dep-$(uuidgen)" \
  -d '{
    "amount": "5000.00",
    "currency": "USD",
    "method": "ach",
    "description": "Initial funding",
    "plaid_options": {
      "item_id": "item_abc123",
      "account_id": "acc_1234567890"
    }
  }'

Manual bank transfer

The user sends a bank transfer using instructions provided in the response:
curl -X POST "$BASE_URL/accounts/$ACCOUNT_ID/deposits" \
  -H "Authorization: Basic $AUTH" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: dep-$(uuidgen)" \
  -d '{
    "amount": "5000.00",
    "currency": "USD",
    "method": "manual_bank_transfer",
    "description": "Wire transfer funding"
  }'
The response includes bank details and a reference code:
{
  "method_details": {
    "referenceCode": "BLUUM-ABC123XY",
    "bankDetails": {
      "bankName": "Choice Financial Group",
      "accountName": "Bluum Finance, Inc.",
      "routingNumber": "091311229",
      "accountNumber": "202534766488",
      "instructions": "Include reference code \"BLUUM-ABC123XY\" in your transfer memo."
    }
  },
  "expires_at": "2025-06-22T10:45:00.000Z"
}
Display the bank details and reference code to your user. The deposit expires at expires_at if funds are not received.

Tracking deposit status

curl -X GET "$BASE_URL/accounts/$ACCOUNT_ID/deposits/$DEPOSIT_ID" \
  -H "Authorization: Basic $AUTH"
StatusMeaningNext
pendingCreated, not yet initiatedWait or cancel
processingACH initiated with bankWait
receivedFunds received, settlingWait
completedFunds in wallet, ready to tradeTrade
failedTransfer failedCheck failure_reason, retry
Use webhooks (transfer.deposit.*) for real-time status updates instead of polling.

Withdrawals

Withdraw funds to a linked bank account:
curl -X POST "$BASE_URL/accounts/$ACCOUNT_ID/withdrawals" \
  -H "Authorization: Basic $AUTH" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: wdr-$(uuidgen)" \
  -d '{
    "amount": "1000.00",
    "currency": "USD",
    "method": "ach",
    "description": "Withdrawal to checking",
    "plaid_options": {
      "item_id": "item_abc123",
      "account_id": "acc_1234567890"
    }
  }'

Withdrawal statuses

StatusMeaning
pendingCreated, can be canceled
processingACH initiated
submittedSubmitted to bank
completedFunds delivered
failedTransfer failed

Canceling a withdrawal

Only pending withdrawals can be canceled:
curl -X POST "$BASE_URL/accounts/$ACCOUNT_ID/withdrawals/$WITHDRAWAL_ID/cancel" \
  -H "Authorization: Basic $AUTH"

Idempotency

Always include Idempotency-Key headers on deposit and withdrawal requests. This prevents duplicate transfers if a request is retried due to network issues or timeouts.
-H "Idempotency-Key: dep-unique-operation-id"
See Idempotency for best practices.

Error handling

ErrorCauseResolution
BLUM-400-*Invalid amount or missing fieldsCheck request body
BLUM-422-*Insufficient funds (withdrawal)Check wallet balance
BLUM-409-*Duplicate idempotency key with different bodyUse a new key for different operations