Accept payments via Pay by Bank - Web
Revolut's Pay by Bank widget allows you to effortlessly accept payments directly from your customers' bank accounts, offering a seamless and secure checkout experience.
In this tutorial, we'll guide you through integrating the Pay by Bank widget, powered by the Revolut Checkout Widget. Customers can securely authorize payments directly from their bank accounts within your website, simplifying the payment process and enhancing user experience.

Before implementing Pay by Bank, be aware of the following:
- No sandbox environment: Pay by Bank is not available in the sandbox environment. Real transactions must be made to test your implementation in the production environment.
- No refund support: Pay by Bank does not support refunds through the Merchant API. If you need to refund a payment, you must process it through alternate channels outside of Revolut's payment system.
- Pricing restrictions: Pay by Bank is not available for merchants on unblended pricing plans.
Available banks
The list of available banks may vary at the time of payment and depends on network status.
| Country | Banks | Currency | Supported schemes |
|---|---|---|---|
| Austria (AT) |
| EUR | SEPA Credit Transfers |
| Belgium (BE) |
| EUR | SEPA Credit Transfers SEPA Instant |
| Croatia (HR) |
| EUR | SEPA Credit Transfers |
| Finland (FI) |
| EUR | SEPA Credit Transfers SEPA Instant |
| France (FR) |
| EUR | SEPA Credit Transfers SEPA Instant |
| Germany (DE) |
| EUR | SEPA Credit Transfers SEPA Instant |
| Greece (GR) |
| EUR | SEPA Credit Transfers |
| Ireland (IE) |
| EUR | SEPA Credit Transfers |
| Italy (IT) |
| EUR | SEPA Credit Transfers |
| Lithuania (LT) |
| EUR | SEPA Credit Transfers SEPA Instant |
| Netherlands (NL) |
| EUR | SEPA Credit Transfers SEPA Instant |
| Portugal (PT) |
| EUR | SEPA Credit Transfers SEPA Instant |
| Spain (ES) |
| EUR | SEPA Credit Transfers SEPA Instant |
| United Kingdom (GB) |
| GBP | Faster Payments |
How it works
Implementing the Pay by Bank widget involves these core components:
- Server-side: expose an endpoint on your backend that creates an order using the Merchant API: Create an order endpoint.
- Client-side: the Revolut Checkout Widget facilitates bank selection, uses your endpoint to create the order, and handles other actions like redirection or customer authentication.
- Webhook endpoint (recommended): Set up webhooks to monitor payment lifecycle events. For more details, refer to Use webhooks to track of the payment lifecycle.
The order and payment flow is similar to all payment solutions:
- The customer goes to the checkout page.
- The customer initiates the payment by clicking a button.
- Your client creates an instance of the
payByBankwidget. - The widget shows a pop-up window to select the customer's bank, and handles additional actions, like redirection to the bank's page to complete the payment.
- In the background, the widget uses your endpoint to create an order, initiates the payment processing, and handles payment results via event callbacks.
- Your client responds to the callbacks to present the payment result to the customer.
- Your server receives webhook notifications about each event you're subscribed to.
For more information about the order and payment lifecycle, see: Order and payment lifecycle.
Implementation overview
Here is an overview of the key integration steps:
- Install Revolut Checkout Widget
- Set up an endpoint for creating orders
- Initialise widget
- Add DOM element
- Listen to DOM events
- Configure and show the widget
- Listen to webhooks
Before you begin
Make sure you've completed the following:
Implement the Pay by Bank widget
1. Install Revolut Checkout Widget
Before you begin, ensure the Revolut Checkout Widget is installed in your project. This widget is a necessary component to create and configure the Pay by Bank widget. You can install the widget via your project's package manager.
npm install @revolut/checkout
Alternatively, you can add the widget to your code base by adding the embed script to your page directly. To learn more, see: Adding the embed script.
2. Set up an endpoint for creating orders
When a customer proceeds to make payment on your website, the widget will call the createOrder callback. You'll need to create an order based on your customer's checkout and return its token using the Merchant API: Create an order endpoint.
This token represents the order and is used to initialise the Pay by Bank widget. The process of creating an order and receiving a token will vary based on your backend setup.
See an example response of an order created with minimal required parameters:
{
"id": "6516e61c-d279-a454-a837-bc52ce55ed49",
"token": "0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
"type": "payment",
"state": "pending",
"created_at": "2023-09-29T14:58:36.079398Z",
"updated_at": "2023-09-29T14:58:36.079398Z",
"amount": 5,
"currency": "GBP",
"outstanding_amount": 5,
"capture_mode": "automatic",
"checkout_url": "https://checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
"enforce_challenge": "automatic"
}
3. Initialise widget
Use the RevolutCheckout.payments() module's payByBank instance with your Merchant API Public key to initialise the widget.
const { payByBank } = await RevolutCheckout.payments({
locale: 'en', // Optional, defaults to 'auto'
publicToken: '<yourPublicApiKey>', // Merchant public API key
})
// Configuration code will go here
For more information about the RevolutCheckout.payments() function, see: Merchant Web SDKs: The payments object
4. Add DOM element
Prepare your checkout page by adding a button or similar interactive element that users will click to initiate the payment:
<...>
<button id='pay-by-bank'>Pay by bank</button>
<...>
This button will trigger your JavaScript integration of the widget, so make sure you listen to events.
5. Listen to DOM events
Attach a click handler to your button that will trigger the widget.
const { payByBank } = await RevolutCheckout.payments({
locale: 'en', // Optional, defaults to 'auto'
publicToken: '<yourPublicApiKey>', // Merchant public API key
})
const payByBankButton = document.getElementById('pay-by-bank')
payByBankButton.addEventListener('click', async () => {
// Configuration code will go here
})
6. Configure and show the widget
Invoke the payByBank({ ... }) instance and pass your configuration parameters. Then, call the .show() method on the returned instance to open the Pay by Bank modal.
const { payByBank } = await RevolutCheckout.payments({
locale: 'en', // Optional, defaults to 'auto'
publicToken: '<yourPublicApiKey>', // Merchant public API key
})
const payByBankButton = document.getElementById('pay-by-bank')
payByBankButton.addEventListener('click', async () => {
const payByBankInstance = payByBank({
createOrder: async () => {
// Call your backend here to create an order and return order.token
// For more information, see: https://developer.revolut.com/docs/merchant/create-order
const order = await yourServerSideCall()
return { publicId: order.token }
},
onSuccess() {
// Do something to handle successful payments
window.alert('Successful payment!')
},
onError(error) {
// Do something to handle payment errors
window.alert(`Something went wrong. ${error}`)
}
})
payByBankInstance.show()
})
-
RevolutCheckout.payments(...)initialises the Revolut Checkout module and returns an object containing thepayByBankfactory. You must pass yourlocaleandpublicToken(your merchant public API key) here. -
payByBankis a function that creates a Pay by Bank instance when you call it with your options. It returns aPaymentsModulePayByBankInstancethat exposes two methods:.show()— opens the bank-selection modal.destroy()— removes any rendered UI and cleans up
-
createOrderis a function you define (e.g. yourServerSideCall()) that takes the order details from your frontend (amount,currency,billing_address, etc.) and passes them to your backend.- Your backend calls the Merchant API: Create an order endpoint with that payload.
- The Merchant API responds with a
token. - You return
{ publicId: order.token }to the widget, so it can start the checkout session.
-
onSuccessis an event handler that triggers when the payment is successful. In this example it shows a "Successful payment!" alert. It's designed to execute custom actions. Any return value is ignored.For example, you can:
- Redirect the customer to a confirmation page
- Update your UI with a "Thank you" message
- Trigger any post-purchase logic (e.g. emailing a receipt)
-
onErroris an event handler that triggers in case of an error. In this example it displays an alert with the error message. Similar to theonSuccess, it's intended for implementing custom error handling logic based on the merchant's requirements. Any return value is ignored.For example, you can:
- Display a custom error screen
- Log the error for diagnostics
- Retry the order-creation or prompt the user to choose another bank
-
Finally, once you have your instance, call
.show()to open the Revolut Pay by Bank modal. If you need to abort before rendering, call.destroy()instead.
For more details about the available parameters, see: Merchant Web SDK: Payments.payByBank.
By following these steps, you have successfully integrated the Revolut Checkout Widget's Pay by Bank module into your website. This setup allows customers to pay with their bank accounts securely.
Additional settings
The payByBank module of the Revolut Checkout Widget offers several options that allow for a customised checkout experience. Here are some additional settings you can leverage:
-
Event handlers:
onSuccess,onErrorare event handlers that you can define to manage the different states of the payment process - from successful transactions to errors.onCancelcan be used to handle scenarios where the payment process is interrupted or cancelled by the user.
-
Instant payment filter:
- By setting
instantOnly: true, you can restrict the list of available banks to those supporting real-time transfers. We recommend using this filter if your business fulfills orders instantly, as non-instant payments via SEPA can take up to 2 business days to arrive in your account.
- By setting
7. Listen to webhooks
While client-side callbacks like onSuccess indicate the customer has completed the flow, it's crucial to confirm the final payment status on your server before fulfilling the order. Webhooks provide a reliable way to track the order and payment lifecycle asynchronously.
Important considerations for Pay by Bank:
- Settlement time: Payments processed via non-instant methods like SEPA Credit Transfers can take up to 2 business days to settle in your account. Relying solely on client-side redirects or polling for status updates is not recommended due to these potential delays.
- Fulfillment trigger: You should wait for the
ORDER_COMPLETEDwebhook event before fulfilling Pay by Bank orders. This event confirms that the funds are successfully settled.
We strongly recommend implementing a webhook endpoint to listen for events. This approach is more robust than relying on client-side actions or polling, given potential settlement delays. Setting up webhooks allows you to reliably track order status and manage fulfillment accordingly.
Follow our detailed guide to set up webhooks for your integration: Use webhooks to track the payment lifecycle.
Examples
- Check out our live Pay by Bank demo for a practical demonstration of this integration.
- Explore our integration examples repository to discover all available examples and see how different payment solutions are implemented.
Insert the following DOM element into your webpage where you want to display the Pay by Bank widget, and attach to your click handler:
<button id='pay-by-bank'>Pay by bank</button>
Example with minimal required parameters
const { payByBank } = await RevolutCheckout.payments({
locale: 'en', // Optional, defaults to 'auto'
publicToken: '<yourPublicApiKey>', // Merchant public API key
})
const payByBankButton = document.getElementById('pay-by-bank')
payByBankButton.addEventListener('click', async () => {
const payByBankInstance = payByBank({
createOrder: async () => {
// Call your backend here to create an order and return order.token
// For more information, see: https://developer.revolut.com/docs/merchant/create-order
const order = await yourServerSideCall()
return { publicId: order.token }
},
onSuccess() {
// Do something to handle successful payments
window.alert('Successful payment!')
},
onError(error) {
// Do something to handle payment errors
window.alert(`Something went wrong. ${error}`)
}
})
payByBankInstance.show()
})
Example with additional parameters
const { payByBank } = await RevolutCheckout.payments({
locale: 'en', // Optional, defaults to 'auto'
publicToken: '<yourPublicApiKey>', // Merchant public API key
})
const payByBankButton = document.getElementById('pay-by-bank')
payByBankButton.addEventListener('click', async () => {
const payByBankInstance = payByBank({
createOrder: async () => {
// Call your backend here to create an order and return order.token
// For more information, see: https://developer.revolut.com/docs/merchant/create-order
const order = await yourServerSideCall()
return { publicId: order.token }
},
instantOnly: true,
onSuccess() {
// Do something to handle successful payments
window.alert('Successful payment!')
},
onError(error) {
// Do something to handle payment errors
window.alert(`Something went wrong. ${error}`)
},
onCancel() {
// Do something to handle cancelled payments
window.alert('The payment was cancelled.')
}
})
payByBankInstance.show()
})
Implementation checklist
Pay by Bank is not available in the sandbox environment. You must test your implementation using real transactions in the production environment. We recommend using small amounts for testing purposes.
Before deploying your Pay by Bank implementation to your live website, complete the checklist below to ensure everything works as expected in the production environment.
General checks
- Pay by Bank modal opens correctly when the customer clicks the payment button.
- Your backend creates the order successfully when the widget is triggered.
- Widget successfully calls
createOrderfunction to fetch and use the ordertoken. - Bank selection screen displays correctly with available banks.
- Successful payment flow:
- Customer can select a bank and complete authentication.
- Payment completes successfully with a real bank account.
- Success callback (
onSuccess) is triggered as expected. - Customer sees appropriate success messaging.
- Error handling works as expected:
- Failed payments trigger the error callback (
onError). - Customer sees appropriate error messaging.
- Cancel callback (
onCancel) is triggered when payment is abandoned.
Webhook verification
- Webhook endpoint is set up to receive order and payment updates.
- Webhook notifications are received correctly for all payment events.
ORDER_COMPLETEDwebhook event is received when payment settles successfully.- Your backend only fulfills orders after receiving the
ORDER_COMPLETEDwebhook event. - Webhook signature verification is implemented for security.
Payment method specific checks
If you implemented the instantOnly: true filter:
- Only banks supporting instant payments are displayed in the bank selection.
- Payments are processed and settled in real-time.
If you allow non-instant payments (SEPA Credit Transfers):
- Non-instant banks are displayed in the bank selection.
- Your system handles the delayed settlement (up to 2 business days).
- Order fulfillment waits for the
ORDER_COMPLETEDwebhook before proceeding.
Integration pattern checks
- Event callbacks (
onSuccess,onError,onCancel) handle UI updates correctly. - Backend logic relies on webhooks, not client-side callbacks, for critical operations.
- Payment status is verified server-side before fulfilling orders.
Once your implementation passes all the checks in the production environment, you can confidently deploy it to your live website.
These checks only cover the implementation path described in this tutorial. If your application handles more features of the Merchant API, see the Merchant API: Implementation checklists.
Congratulations! You've successfully implemented Pay by Bank and are ready to accept payments from your customers.
What's next
- Check our integration example - Learn more about how to use the Revolut Checkout SDK with the Pay by Bank widget
- Learn more about the Pay by Bank SDK
- Learn more about the order and payment lifecycle
- Learn more about webhooks - Check our guide about how you can track payment lifecycle with the Merchant API's webhook service
- Learn more about order management - Explore the full capabilities of our Orders API
- Learn more about customer management - Explore the full capabilities of our Customers API