# `payByBank()`

Enables customers to pay directly from their bank account via Open Banking, providing an instant and secure payment experience. The SDK opens a modal widget where customers can select their bank and complete the transfer.

**Key features:**

- Direct bank-to-bank transfers via Open Banking
- Support for instant settlement banks
- Modal widget with bank selection
- No card details required
- Lower processing fees

:::info
For a complete implementation guide with examples, see: [Accept payment via Pay by Bank](/docs/guides/merchant/accept-payments/online-payments/pay-by-bank/web)

Check out our live [Pay by Bank demo](https://github.com/revolut-engineering/revolut-checkout-example/tree/main/pay-by-bank-example) and [integration examples repository](https://github.com/revolut-engineering/revolut-checkout-example).
:::

## Prerequisites

This payment method requires payments module initialisation. See: [Payments module initialisation](/docs/sdks/merchant-web-sdk/initialisation/payments-module)

## Type signature

```typescript
PaymentsInstance.payByBank(
  options: PayByBankOptions
): PayByBankInstance

interface PayByBankOptions {
  createOrder: () => Promise<{ publicId: string }>
  instantOnly?: boolean
  location?: CountryCode
  onSuccess?: (payload: { orderId: string }) => void
  onError?: (payload: { error: RevolutCheckoutError; orderId: string }) => void
  onCancel?: (payload: { orderId: string | undefined }) => void
}

interface PayByBankInstance {
  show: () => void
  destroy: () => void
}
```

## Parameters

| Parameter | Description                          | Type                                                 | Required |
| --------- | ------------------------------------ | ---------------------------------------------------- | -------- |
| `options` | Configuration object for Pay by Bank | [`PayByBankOptions`](#pay-by-bank-options-interface) | Yes      |

### `PayByBankOptions` interface

| Parameter     | Description                                                                                                                        | Type                                                                   | Required |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | -------- |
| `createOrder` | Async function that calls your backend to [create an order](/docs/api/merchant#create-order) and returns the order token           | `() => Promise<{publicId: string}>`                                    | Yes      |
| `instantOnly` | Only show banks with instant settlement support                                                                                    | `boolean` (default: `false`)                                           | No       |
| `location`    | ISO 3166-1 alpha-2 country code to filter banks by country. If specified, only shows banks from the selected country               | [`CountryCode`](/docs/sdks/merchant-web-sdk/types/address#countrycode) | No       |
| `onSuccess`   | Callback triggered when payment completes successfully                                                                             | `(payload: {orderId: string}) => void`                                 | No       |
| `onError`     | Callback triggered when payment fails. Receives [`RevolutCheckoutError`](/docs/sdks/merchant-web-sdk/types/revolut-checkout-error) | `(payload: {error: RevolutCheckoutError, orderId: string}) => void`    | No       |
| `onCancel`    | Callback triggered when user cancels payment. `orderId` may be `undefined` if order creation failed                                | `(payload: {orderId?: string}) => void`                                | No       |

## Return value

```typescript
PayByBankInstance

interface PayByBankInstance {
  show: () => void
  destroy: () => void
}
```

The method returns a `PayByBankInstance` object containing:

| Method    | Description                             | Type         |
| --------- | --------------------------------------- | ------------ |
| `show`    | Open the Pay by Bank modal widget       | `() => void` |
| `destroy` | Close the widget and clean up resources | `() => void` |

## Callback events

The Pay by Bank widget provides callback functions for handling payment lifecycle events.

:::warning
Widget callbacks are not guaranteed to fire due to network issues, browser closures, or ad-blockers. Always use [webhooks](/docs/guides/merchant/monitor-and-observe/webhooks/using-webhooks) for critical backend operations like order fulfilment.
:::

:::info
In all callbacks, `orderId` refers to the order's public token (`order.token` from the API response), not the internal `order.id`. This is the public identifier used in your frontend code.
:::

### `onSuccess`

```typescript
(payload: { orderId: string }) => void
```

Triggered when the payment completes successfully.

**Use cases:**

- Display success message to the customer
- Redirect to order confirmation page
- Update UI to reflect successful payment

**Example:**

```typescript
onSuccess: ({ orderId }) => {
  console.log('Payment successful!', orderId)
  window.location.href = `/confirmation?orderId=${orderId}`
}
```

### `onError`

```typescript
(payload: { error: RevolutCheckoutError; orderId: string }) => void
```

Triggered when the payment fails. The `error` parameter is a [`RevolutCheckoutError`](/docs/sdks/merchant-web-sdk/types/revolut-checkout-error) object containing error details.

**Use cases:**

- Display error message to the customer
- Log error for debugging
- Re-enable checkout form
- Offer alternative payment methods

**Example:**

```typescript
onError: ({ error, orderId }) => {
  console.error('Payment failed:', error.message, orderId)
  alert(`Payment failed: ${error.message}`)
}
```

### `onCancel`

```typescript
(payload: { orderId: string | undefined }) => void
```

Triggered when the user cancels the payment. The `orderId` may be `undefined` if order creation failed or the user closed the widget before completing the flow.

**Use cases:**

- Display cancellation message
- Re-enable checkout form
- Track abandonment analytics

**Example:**

```typescript
onCancel: ({ orderId }) => {
  console.log('Payment cancelled', orderId)
  alert('Payment was cancelled. You can try again.')
}
```

## Usage examples

- ![With async/await]

  ```typescript
  import RevolutCheckout from '@revolut/checkout'

  // Initialise payments module
  const { payByBank } = await RevolutCheckout.payments({
    publicToken: process.env.REVOLUT_PUBLIC_KEY,
    mode: 'prod',
  })

  // Create Pay by Bank instance
  const instance = payByBank({
    createOrder: async () => {
      const response = await fetch('/api/create-order', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ amount: 1000, currency: 'GBP' }),
      })
      const order = await response.json()
      return { publicId: order.token }
    },

    onSuccess: ({ orderId }) => {
      console.log('Payment successful!', orderId)
      window.location.href = `/confirmation?orderId=${orderId}`
    },

    onError: ({ error, orderId }) => {
      console.error('Payment failed:', error.message, orderId)
      alert(`Payment failed: ${error.message}`)
    },

    onCancel: ({ orderId }) => {
      console.log('Payment cancelled', orderId)
      alert('Payment was cancelled.')
    },
  })

  // Show the widget when user clicks a button
  document
    .getElementById('pay-by-bank-button')
    .addEventListener('click', () => {
      instance.show()
    })
  ```

- ![Without async/await]

  ```typescript
  import RevolutCheckout from '@revolut/checkout'

  // Initialise payments module
  RevolutCheckout.payments({
    publicToken: process.env.REVOLUT_PUBLIC_KEY,
    mode: 'prod',
  }).then(({ payByBank }) => {
    // Create Pay by Bank instance
    const instance = payByBank({
      createOrder: () => {
        return fetch('/api/create-order', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ amount: 1000, currency: 'GBP' }),
        })
          .then((response) => response.json())
          .then((order) => ({ publicId: order.token }))
      },

      onSuccess: ({ orderId }) => {
        console.log('Payment successful!', orderId)
        window.location.href = `/confirmation?orderId=${orderId}`
      },

      onError: ({ error, orderId }) => {
        console.error('Payment failed:', error.message, orderId)
        alert(`Payment failed: ${error.message}`)
      },

      onCancel: ({ orderId }) => {
        console.log('Payment cancelled', orderId)
        alert('Payment was cancelled.')
      },
    })

    // Show the widget when user clicks a button
    document
      .getElementById('pay-by-bank-button')
      .addEventListener('click', () => {
        instance.show()
      })
  })
  ```

### Instant settlement only

Restrict bank selection to only those supporting instant settlement:

```typescript
const instance = payByBank({
  createOrder: async () => {
    const response = await fetch('/api/create-order', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ amount: 1000, currency: 'GBP' }),
    })
    const order = await response.json()
    return { publicId: order.token }
  },

  instantOnly: true, // Only show instant settlement banks

  onSuccess: ({ orderId }) => {
    console.log('Instant payment successful!', orderId)
    window.location.href = `/confirmation?orderId=${orderId}`
  },

  onError: ({ error, orderId }) => {
    alert(`Payment failed: ${error.message}`)
  },
})

document.getElementById('instant-pay-button').addEventListener('click', () => {
  instance.show()
})
```

### Filter banks by country

Use the `location` parameter to show only banks from a specific country:

```typescript
const instance = payByBank({
  createOrder: async () => {
    const response = await fetch('/api/create-order', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ amount: 1000, currency: 'GBP' }),
    })
    const order = await response.json()
    return { publicId: order.token }
  },

  location: 'GB', // Only show UK banks

  onSuccess: ({ orderId }) => {
    console.log('Payment successful!', orderId)
    window.location.href = `/confirmation?orderId=${orderId}`
  },

  onError: ({ error, orderId }) => {
    alert(`Payment failed ${error.message}`)
  },
})

document.getElementById('uk-banks-button').addEventListener('click', () => {
  instance.show()
})
```

### Manual widget control

Control widget lifecycle programmatically:

```typescript
let payByBankInstance

// Initialize once
const { payByBank } = await RevolutCheckout.payments({
  publicToken: process.env.REVOLUT_PUBLIC_KEY,
  mode: 'prod',
})

// Create instance
payByBankInstance = payByBank({
  createOrder: async () => {
    const response = await fetch('/api/create-order', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ amount: 1000, currency: 'GBP' }),
    })
    const order = await response.json()
    return { publicId: order.token }
  },

  onSuccess: ({ orderId }) => {
    console.log('Payment successful!', orderId)
    payByBankInstance.destroy()
    window.location.href = `/confirmation?orderId=${orderId}`
  },

  onError: ({ error, orderId }) => {
    console.error('Payment failed:', error.message)
    payByBankInstance.destroy()
    alert(`Payment failed: ${error.message}`)
  },

  onCancel: ({ orderId }) => {
    console.log('User cancelled payment')
    payByBankInstance.destroy()
  },
})

// Show widget
document.getElementById('show-widget').addEventListener('click', () => {
  payByBankInstance.show()
})

// Manually close widget if needed
document.getElementById('close-widget').addEventListener('click', () => {
  payByBankInstance.destroy()
})
```

## See also

- [Accept payment via Pay by Bank](/docs/guides/merchant/accept-payments/online-payments/pay-by-bank/web)
- [Payments module initialisation](/docs/sdks/merchant-web-sdk/initialisation/payments-module)
- [RevolutCheckoutError type reference](/docs/sdks/merchant-web-sdk/types/revolut-checkout-error)
- [Use webhooks to keep track of the payment lifecycle](/docs/guides/merchant/monitor-and-observe/webhooks/using-webhooks)
- [Pay by Bank demo](https://github.com/revolut-engineering/revolut-checkout-example/tree/main/pay-by-bank-example)
- [Integration examples repository](https://github.com/revolut-engineering/revolut-checkout-example)