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

# ACH, Fednow/RTP & Wire bank deposit via the Payment Widget

> Accept ACH, Fednow/RTP & Wire bank deposits with the Uphold Payment Widget: create a session, display transfer instructions to the user, and monitor for incoming funds.

The Payment Widget handles deposit method selection across all supported US networks — ACH, Wire, FedNow, and RTP — and displays the necessary transfer instructions to the user. Your backend only needs to create the session and monitor for the incoming transfer. No per-network handling is required.

<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-->>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 a deposit method and view transfer instructions that work across all supported US networks — ACH, Wire, FedNow, and RTP.

### 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. Across supported US rails, the transfer instruction fields such as routing and account details are shared, while `depositMethod.details.network` indicates the rail selected for this deposit method. No per-network handling is required.

<Info>
  In the API, `"fednow"` represents both the FedNow and RTP networks.
</Info>

<Info>
  The optional `secondaryNetworks` field lists additional supported rails for the same account and transfer instructions, and it's only present when more than one network is supported.
</Info>

```json theme={null}
{
  "type": "bank",
  "status": "ok",
  "details": {
    "network": "ach",
    "asset": "USD",
    "routingNumber": "021000021",
    "accountNumber": "123456789",
    "beneficiary": "John Doe",
    "bankName": "Example Bank",
    "bankAddress": {
      "line1": "456 Bank Avenue",
      "line2": "Fort Lee, NJ 07024"
    },
    "secondaryNetworks": [
      "fednow",
      "wire"
    ]
  }
}
```

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

The sample below shows an ACH deposit. Transactions for other supported networks have the same structure — only `origin.node.network` differs: `"ach"`, `"fednow"` (FedNow and RTP), or `"wire"`.

In a successful ACH bank deposit, the origin is represented as a `bank-address` node. The destination is the user's default USD account.

```json [expandable] theme={null}
{
  "transaction": {
    "id": "a2b3c4d5-e6f7-8a9b-c0d1-e2f3a4b5c6d7",
    "origin": {
      "asset": "USD",
      "amount": "500.00",
      "node": {
        "type": "bank-address",
        "network": "ach"
      }
    },
    "destination": {
      "asset": "USD",
      "amount": "500.00",
      "node": {
        "type": "account",
        "id": "a00507fe-628c-4f27-ae81-e1c40b2a8fb8",
        "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a"
      }
    },
    "status": "completed",
    "quotedAt": "2025-06-15T14:00:00Z",
    "createdAt": "2025-06-15T14:10:00Z",
    "updatedAt": "2025-06-15T14:30:00Z",
    "denomination": {
      "asset": "USD",
      "amount": "500.00",
      "target": "origin"
    }
  }
}
```

## Notify the user

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

<Check>You now support ACH, Wire, RTP, and FedNow push bank deposits via the Payment Widget.</Check>
