> ## 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.

# FPS bank deposit via the Payment Widget

> Accept GBP Faster Payments (FPS) deposits with the Uphold Payment Widget. Create a session, display bank instructions, and monitor for incoming funds.

The Payment Widget handles FPS deposit method selection and displays the necessary transfer instructions to the user. Your backend only needs to create the session and monitor for the incoming transfer.

<Warning>
  The Payment Widget does not create any transaction. Monitoring and processing the incoming transfer must be handled by your backend via webhooks or polling.
</Warning>

## Prerequisites

* The user has [completed onboarding](/developer-guides/user-onboarding/overview) and has the required capabilities enabled.
* The Payment Widget SDK is installed in your frontend. See [Installation and setup](/widgets/payment/installation-and-setup).

## Walkthrough

```mermaid theme={null}
sequenceDiagram
  autonumber
  participant Usr as User
  participant U as Your App
  participant B as Your Backend
  participant P as Payment Widget
  participant A as Uphold
  participant F as Bank

  Usr->>U: Request deposit instructions
  U->>B: Create widget session
  B->>A: Create widget session (select-for-deposit)
  A-->>B: { session }
  B-->>U: { session }
  U->>P: Initialize widget
  Usr->>P: Select deposit method
  P-->>Usr: Display bank transfer instructions
  Usr->>F: Initiate bank transfer
  F-->>A: Incoming transfer received
  A->>A: Link origin as external account
  A-->>B: webhook: transaction.created (processing)
  F-->>A: Settlement confirmed
  A-->>B: webhook: transaction.status-changed (completed/failed)
  B-->>Usr: Notify the user
```

***

## Select deposit method

The widget lets the user select an FPS deposit method and view the transfer instructions.

### Create a widget session

Call the [Create widget session](/rest-apis/widgets-api/payment/create-session) endpoint to create a session for the `select-for-deposit` flow.

```http theme={null}
POST /widgets/payment/sessions
{
  "flow": "select-for-deposit"
}
```

A successful response contains a `session` object. Pass `response.session` to your frontend to initialize the widget.

```json theme={null}
{
  "session": {
    "flow": "select-for-deposit",
    "url": "https://payment.enterprise.uphold.com/",
    "token": "GEbRxBN...edjnXbL"
  }
}
```

### Set up the widget

Initialize the widget for the `select-for-deposit` flow using the session data returned from the API.

```javascript theme={null}
import { PaymentWidget } from '@uphold/enterprise-payment-widget-web-sdk';

const initializeDepositWidget = async (session) => {
  // Initialize the widget
  const widget = new PaymentWidget<'select-for-deposit'>(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'));
};
```

<Info>
  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](/widgets/payment/installation-and-setup#native-application-integration).
</Info>

### Handle the complete event

The `complete` event fires when the user selects a deposit method and completes the flow.

```javascript theme={null}
widget.on('complete', (event) => {
  const { via, selection } = event.detail.value;

  if (via === 'deposit-method') {
    const { depositMethod, account } = selection;
    handleBankDeposit(depositMethod, account);
  }

  widget.unmount();
});
```

The event payload contains two primary properties:

* `via` — is set to `deposit-method` when the user selects a deposit method and completes the flow.
* `selection` — contains the `account` that will receive the funds and the `depositMethod` configuration with transfer instructions.

The widget presents these details directly to the user, so you don't need to display them separately. The FPS `depositMethod.details` contains:

```json theme={null}
{
  "type": "bank",
  "status": "ok",
  "details": {
    "network": "fps",
    "asset": "GBP",
    "sortCode": "123456",
    "accountNumber": "12345678",
    "reference": "UH12345678",
    "beneficiary": "John Doe",
    "bankName": "Example Bank",
    "bankAddress": {
      "line1": "123 Bank Street",
      "line2": "London, United Kingdom"
    }
  }
}
```

### Handle cancellations

The `cancel` event fires when the user closes the widget without selecting a deposit method.

```javascript theme={null}
widget.on('cancel', () => {
  widget.unmount();
  // Redirect back or show a cancellation message
});
```

### Handle errors

The `error` event fires when an error occurs during the deposit method selection process.

```javascript theme={null}
widget.on('error', (event) => {
  console.error('Widget error:', event.detail.error);
  widget.unmount();
  // Show a user-friendly error message
});
```

<Warning>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.</Warning>

## Monitor for the incoming transfer

The widget presents the deposit instructions to the user but does not monitor for the incoming transfer. Your application must do this via webhooks or polling.

* Webhook events (recommended):
  * [core.transaction.created](/rest-apis/core-api/transactions/webhooks/transaction-created)
    * `status: processing` → bank transfer received, pending posting
  * [core.transaction.status-changed](/rest-apis/core-api/transactions/webhooks/transaction-status-changed)
    * `status: completed` → funds settled
    * `status: failed` → irrecoverable error
* Polling (fallback): [Get transaction](/rest-apis/core-api/transactions/get-transaction)

## Sample transaction

In a successful FPS deposit, the origin is represented as an `external-account` node. This is because the origin bank details are automatically registered as an external account. The destination is the account selected when the deposit instructions were generated, or the user's default GBP account if the transfer was sent without a reference, or the selected account doesn't exist anymore.

```json [expandable] theme={null}
{
  "transaction": {
    "id": "b1bbbc0f-dae2-4e94-9e6d-4b9d5a1f3c1f",
    "origin": {
      "asset": "GBP",
      "amount": "250.00",
      "node": {
        "type": "external-account",
        "id": "aa6e6efa-8d73-497c-8278-0347f459bd68",
        "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a"
      }
    },
    "destination": {
      "asset": "GBP",
      "amount": "250.00",
      "node": {
        "type": "account",
        "id": "a00507fe-628c-4f27-ae81-e1c40b2a8fb8",
        "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a"
      }
    },
    "status": "completed",
    "quotedAt": "2025-01-10T11:02:39Z",
    "createdAt": "2025-01-10T11:12:39Z",
    "updatedAt": "2025-01-10T11:13:08Z",
    "denomination": {
      "asset": "GBP",
      "amount": "250.00",
      "target": "origin"
    }
  }
}
```

The new external account can be then retrieved with [Get external account](/rest-apis/core-api/external-accounts/get-external-account) to show the sender's bank details alongside the transaction, or to withdraw funds to the same account in the future.

```json [expandable] theme={null}
{
  "externalAccount": {
    "id": "aa6e6efa-8d73-497c-8278-0347f459bd68",
    "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a",
    "type": "bank",
    "status": "ok",
    "label": "GBP Bank Account",
    "asset": "GBP",
    "network": "fps",
    "features": [
      "withdraw"
    ],
    "details": {
      "accountNumber": "12345678",
      "sortCode": "123456"
    },
    "createdAt": "2025-01-10T11:12:39Z",
    "updatedAt": "2025-01-10T11:13:08Z"
  }
}
```

## Notify the user

Display an in-app confirmation when the transaction is `completed`, and send an email if applicable.

<Check>You now support FPS bank transfer deposits via the Payment Widget.</Check>
