Skip to main content
This flow covers initiating a crypto withdrawal and monitoring until settlement.

Prerequisites

  • The user is onboarded and verified (KYC).
  • The crypto-withdrawals capability is enabled for the user.
  • A funded account to support the withdrawal.
  • The details of the destination wallet: blockchain address and destination tag/memo if applicable (e.g., XRP/XLM).
If the destination network requires an additional reference (e.g., destination tag, memo), strongly encourage your users to provide it. Missing references often lead to loss of funds or lengthy recovery.

The flow

Choose the source account

List the user’s accounts using the List accounts endpoint and allow them to choose one with sufficient balance for the withdrawal.
GET /core/accounts?perPage=10&currency=XRP

Collect withdrawal details

Collect the details where to make the withdrawal to. This can be implemented either by calling the necessary API endpoints directly to build a custom UI for collecting the required details, or by integrating the Payment Widget, which handles the entire process automatically. Both implementations are described below.

Using the REST API

Follow these steps to perform a crypto withdrawal using the REST API.

List networks

To retrieve the list of available networks, use the List networks and List rails endpoints. Filter for networks of type crypto that have at least one rail of type crypto-transaction with the withdrawal feature enabled. When constructing the UI to collect the withdrawal details, use the Network’s reference field to determine whether to display a destination tag/memo input.

Using the Payment Widget

To use the Payment Widget for crypto withdrawals, you must use the Select for Withdrawal flow.

Select for withdrawal flow

Please refer to the Select for withdrawal guide for a step-by-step tutorial.
Regardless of how the withdrawal details were collected (REST API or Payment Widget), the rest of the process is handled via REST API.

Create a quote

Create a quote for the withdrawal using the Create quote endpoint.
POST /core/transactions/quote
{
  "origin": {
    "type": "account",
    "id": "a00507fe-628c-4f27-ae81-e1c40b2a8fb8"
  },
  "destination": {
    "type": "crypto-address",
    "asset": "BTC",
    "network": "bitcoin",
    "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
  },
  "denomination": {
    "asset": "GBP",
    "amount": "100.00",
    "target": "origin"
  }
}

Quote object

A successful response returns a quote object with details about the withdrawal, including fees and expiration.
{
  "quote": {
    "id": "623000c8-9bdf-4a2b-aa3d-6a6b44a7f6a0",
    "origin": {
      "amount": "0.00121023",
      "asset": "BTC",
      "rate": "0.00002629253259492961",
      "node": {
        "type": "account",
        "id": "a00507fe-628c-4f27-ae81-e1c40b2a8fb8",
        "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a"
      }
    },
    "destination": {
      "amount": "0.00121023",
      "asset": "BTC",
      "rate": "1",
      "node": {
        "type": "crypto-address",
        "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
        "network": "bitcoin",
        "execution": {
          "mode": "onchain"
        }
      }
    },
    "denomination": {
      "amount": "100.00",
      "asset": "GBP",
      "target": "origin",
      "rate": "0.00001210225938333485"
    },
    "fees": [],
    "expiresAt": "2024-07-24T15:22:39Z"
  }
}
Quotes typically expire quickly. Prompt for user confirmation within the expiry window and regenerate if needed.

Handle quote requirements

Some quotes may include requirements in the requirements array that must be resolved before creating the transaction. If present, follow the Quote requirements flow before proceeding.

Create a transaction

Once the user confirms the quote, create the transaction using the Create transaction endpoint.
POST /core/transactions
{
  "quoteId": "623000c8-9bdf-4a2b-aa3d-6a6b44a7f6a0"
}

Transaction object

A successful response returns a transaction object with details about the initiated withdrawal.
{
  "transaction": {
    "id": "223c24c5-76c6-4553-91bc-5af519441f03",
    "origin": {
      "amount": "0.00121023",
      "asset": "BTC",
      "rate": "0.00002629253259492961",
      "node": {
        "type": "account",
        "id": "a00507fe-628c-4f27-ae81-e1c40b2a8fb8",
        "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a"
      }
    },
    "destination": {
      "amount": "0.00121023",
      "asset": "BTC",
      "rate": "1",
      "node": {
        "type": "crypto-address",
        "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
        "network": "bitcoin",
        "execution": {
          "mode": "onchain"
        }
      }
    },
    "fees": [],
    "status": "processing",
    "quotedAt": "2024-07-24T15:02:39Z",
    "createdAt": "2024-07-24T15:22:39Z",
    "updatedAt": "2024-07-24T15:22:39Z",
    "denomination": {
      "amount": "100.00",
      "asset": "GBP",
      "target": "origin",
      "rate": "0.00001210225938333485"
    }
  }
}
The transaction will have these values:
  • origin.node.type: account
  • origin.node.id: The id of the source account
  • origin.node.ownerId: The id of the user that owns the source account
  • destination.node.type: crypto-address
  • destination.node.network: The destination crypto network (e.g. bitcoin)
  • destination.node.address: The destination crypto address (e.g. 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa)
  • destination.node.reference: The destination address reference, such as a destination tag (if applicable)

Execution modes

Crypto withdrawals support different execution modes depending on the destination and environment:
  • On-chain execution: The transaction is processed directly on the blockchain network. The destination.node.execution.mode will be onchain and include blockchain-specific details such as transaction hashes upon completion.
  • Off-chain execution: When both the sender and recipient are Uphold users, the transaction is processed internally within Uphold’s infrastructure. This eliminates network fees and is faster than onchain processing. The destination.node.execution.mode will be offchain. For offchain transactions, the execution object includes additional properties: accountOwnerId (the recipient user ID) and accountId (the recipient account ID).
  • Simulated execution: Used in development environments for testing purposes. The transaction appears processed but does not affect actual blockchain state (user balances will be affected though). The destination.node.execution.mode will be simulated.

Monitor for settlement

Prefer webhooks for real-time updates, or fall back to polling if webhooks are not feasible.
  • Webhook events (recommended):
    • core.transaction.created
      • status: processing → initiated but not yet broadcast
    • core.transaction.status-changed
      • status: completed → broadcast and confirmed
      • status: on-hold → transaction checks paused (e.g., pending RFIs)
      • status: failed → transaction failed, check statusDetails for more info
  • Polling (fallback):

Notify the user

Display an in-app confirmation when the transaction is completed, and send an email if applicable.
You now support crypto transfer withdrawals with the Enterprise API Suite!