Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developer.uphold.com/llms.txt

Use this file to discover all available pages before exploring further.

The Payment Widget handles FPS bank account selection. Your backend creates the session, then continues with the REST API to create a quote and transaction once the user selects their destination bank account.
The Payment Widget does not create any transaction. Your backend must create the quote and transaction via the REST API after the user selects their bank account.

Prerequisites

Walkthrough


Select source account

FPS withdrawals can be sourced from any account. If the selected account is not in GBP, the balance will be converted at the time of the transaction using Uphold’s prevailing rate. Make sure the origin asset has the necessary features enabled. Call List accounts to retrieve the user’s accounts and let them pick the one to withdraw from.
GET /core/accounts
{
  "accounts": [
    {
      "id": "a00507fe-628c-4f27-ae81-e1c40b2a8fb8",
      "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a",
      "label": "My GBP account",
      "asset": "GBP",
      "balance": {
        "total": "500.00",
        "available": "500.00"
      }
    }
  ]
}

Select a bank account

The widget lets the user select an existing FPS-linked bank account.

Create a payment session

Call the Create payment session endpoint to create a session for the select-for-withdrawal flow.
POST /widgets/payment/sessions
{
  "flow": "select-for-withdrawal"
}
A successful response returns a session object with a token and url to initialize the widget.
{
  "session": {
    "flow": "select-for-withdrawal",
    "url": "https://payment.enterprise.uphold.com/",
    "token": "GEbRxBN...edjnXbL"
  }
}

Set up the widget

Initialize the widget for the select-for-withdrawal flow using the session data returned from the API.
import { PaymentWidget } from '@uphold/enterprise-payment-widget-web-sdk';

const initializeWithdrawalWidget = async (session) => {
  // Initialize the widget
  const widget = new PaymentWidget<'select-for-withdrawal'>(session, { debug: true });

  // Set up event handlers
  widget.on('ready', () => {
    console.log('Ready');
  });

  widget.on('complete', (event) => {
    console.log('Complete', JSON.stringify(event.detail.value));
  });

  widget.on('cancel', () => {
    console.log('Cancelled');
    widget.unmount();
  });

  widget.on('error', (event) => {
    console.error('Error', event.detail.error);
    widget.unmount();
  });

  // Mount the widget
  widget.mountIframe(document.getElementById('payment-container'));
};
The example above is for web applications. For native apps using a WebView, you’ll need a bridge for events as outlined in Installation & setup.

Handle the complete event

The complete event fires when the user selects a bank account and completes the flow.
widget.on('complete', (event) => {
  const { via, selection } = event.detail.value;

  if (via === 'external-account' && selection.type === 'bank') {
    // selection is the external account the user selected
    handleBankWithdrawal(selection);
  }

  widget.unmount();
});
The event payload contains two primary properties:
  • via — set to external-account when the user selects a saved bank account.
  • selection — an external account object with the selected bank details.
{
  "via": "external-account",
  "selection": {
    "id": "aa6e6efa-8d73-497c-8278-0347f459bd68",
    "type": "bank",
    "network": "fps",
    "label": "My GBP Account"
  }
}

Handle cancellations

The cancel event fires when the user closes the widget without selecting a bank account.
widget.on('cancel', () => {
  widget.unmount();
  // Redirect back or show a cancellation message
});

Handle errors

The error event fires when an error occurs during the bank account selection process.
widget.on('error', (event) => {
  console.error('Widget error:', event.detail.error);
  widget.unmount();
  // Show a user-friendly error message
});
The Payment Widget handles most errors internally. For unrecoverable errors, the widget fires an error event. It is the host application’s responsibility to handle these events, present an error message to the user, and unmount the widget.

Create a quote

To initiate the withdrawal, call Create quote with the origin as the user’s account and the destination as the selected FPS external account. Specify the amount and asset for the withdrawal.
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"
  }
}
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"
    },
    "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 requote if needed.

Confirm and create transaction

After the user confirms the withdrawal, call Create transaction with the quote ID to execute the transfer.
POST /core/transactions
{
  "quoteId": "623000c8-9bdf-4a2b-aa3d-6a6b44a7f6a0"
}
In a successful FPS withdrawal, the origin is the user’s account and the destination is the external-account representing the user’s bank. The transaction status is initially processing and updates to completed once the transfer settles.
{
  "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",
        "network": "fps"
      }
    },
    "status": "processing",
    "quotedAt": "2025-01-10T14:22:15Z",
    "createdAt": "2025-01-10T14:22:45Z",
    "updatedAt": "2025-01-10T14:22:45Z",
    "denomination": {
      "asset": "GBP",
      "amount": "250.00",
      "target": "origin"
    }
  }
}

Monitor for settlement

The widget does not monitor for settlement. Your application must do this via webhooks or polling.

Notify the user

Display an in-app confirmation when the transaction is completed, and send an email if applicable.
You now support FPS bank transfer withdrawals via the Payment Widget.