Skip to main content
This flow covers creating a quote, executing the withdrawal, and monitoring until settlement.

Prerequisites

  • The user is onboarded and verified (KYC is complete).
  • A funded account to cover the withdrawal amount and fees.
  • A bank external account to receive the funds.
  • The bank-withdrawals capability is enabled for the user.
  • Your system listens to webhooks for transaction updates.
With bank withdrawals, funds are pushed from Uphold to a user’s bank account. These transactions are quote-based, so the user must accept the quote before the withdrawal is executed.

The flow

Choose the source account

List accounts (e.g., with List Accounts) and let the user select one with sufficient balance.

Choose the external account

Select an external account of type bank which will serve as the destination of the withdrawal transaction. This can be implemented entirely via the REST API, by directly calling the necessary endpoints, or by using the Payment Widget, which will handle the process for you. Both implementations are described below.
For FPS external accounts, they are only created after a successful deposit is made. For more details, see Bank Deposit flow.

Using the REST API

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

List external accounts

To get all available external accounts, use the List External Accounts endpoint. Filter the external accounts that have type bank and that have the withdraw feature enabled. Present the filtered list to the user for selection.

Using the Payment Widget

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

Select for Withdrawal flow

The Select for Withdrawal flow allows the user to select a withdrawal method, including bank transfer, and displays the necessary instructions to complete the withdrawal. Please refer to the Select for Withdrawal guide for a step-by-step tutorial.
Regardless of how the withdrawal account was selected (REST API or Payment Widget), the rest of the process is handled via REST API.

Create a quote

Create a quote for the withdrawal with Create Quote. For cross-asset withdrawals, the FX rate is captured in the quote.
  POST /core/transactions/quote
  {
    "origin": {
      "type": "account",
      "id": "a00507fe-628c-4f27-ae81-e1c40b2a8fb8"
    },
    "destination": {
      "type": "external-account",
      "id": "aa6e6efa-8d73-497c-8278-0347f459bd68"
    },
    "denomination": {
      "asset": "GBP",
      "amount": "250.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": "250.00",
      "asset": "GBP",
      "node": {
        "type": "account",
        "id": "a00507fe-628c-4f27-ae81-e1c40b2a8fb8",
        "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a"
      },
      "rate": "1",
      "node": {
        "type": "account",
        "id": "a00507fe-628c-4f27-ae81-e1c40b2a8fb8",
        "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a"
      }
    },
    "destination": {
      "amount": "250.00",
      "asset": "GBP",
      "node": {
        "type": "external-account",
        "id": "aa6e6efa-8d73-497c-8278-0347f459bd68",
        "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a"
      },
      "rate": "1",
    },
    "denomination": {
      "asset": "GBP",
      "amount": "250.00",
      "target": "origin",
      "rate": "1"
    },
    "fees": [],
    "expiresAt": "2024-07-24T15:22:39Z"
  }
}
Quotes typically expire quickly. Prompt for user confirmation within the expiry window and regenerate if needed.

Create a transaction

Once the user accepts the quote, create the transaction using Create Transaction.
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": "d3e4f5a6-1b2c-4d5e-9f8a-7b6c5d4e3f2a",
    "origin": {
      "asset": "GBP",
      "amount": "250.00",
      "node": {
        "type": "account",
        "id": "a00507fe-628c-4f27-ae81-e1c40b2a8fb8",
        "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a"
      }
    },
    "destination": {
      "asset": "GBP",
      "amount": "250.00",
      "node": {
        "type": "external-account",
        "id": "aa6e6efa-8d73-497c-8278-0347f459bd68",
        "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a"
      }
    },
    "status": "completed",
    "quotedAt": "2025-01-10T14:22:15Z",
    "createdAt": "2025-01-10T14:22:45Z",
    "updatedAt": "2025-01-10T14:23:12Z",
    "denomination": {
      "asset": "GBP",
      "amount": "250.00",
      "target": "origin"
    }
  }
}
The transaction will have these values:
  • origin.node.type: account
  • origin.node.id: The id of the source account
  • destination.node.type: external-account
  • destination.node.id: The id of the destination external account
  • destination.node.type is external-account (the user’s bank)
  • destination.node.network is fps

Monitor for settlement

Prefer webhooks for real-time updates, or fall back to polling if webhooks are not feasible.

Notify the user

Display an in-app confirmation when the transaction is executed, and surface failures so the user can retry or contact support. Send an email if applicable.
You now support bank transfer withdrawals with the Enterprise API Suite.