Mounts the Revolut Checkout widget to a DOM element, providing access to all enabled payment methods through a single, unified interface. The widget aggregates Revolut Pay, Card, Apple Pay, Google Pay, Pay by Bank, and other payment methods configured in your Business Dashboard.
Key features:
- Unified widget for all payment methods
- Dashboard-configured (no code changes to add/reorder methods)
- Automatic payment method optimisation
- Built-in customisation options
For a complete implementation guide with examples, see: Accept payments via Revolut Checkout - Web
Prerequisites
This payment method requires direct initialisation.
Type signature
RevolutCheckout.embeddedCheckout: (
options: EmbeddedCheckoutOptions
) => Promise<EmbeddedCheckoutInstance>
interface EmbeddedCheckoutOptions {
publicToken: string
mode: 'prod' | 'sandbox'
locale?: Locale | 'auto'
target: HTMLElement
createOrder: () => Promise<{ publicId: string }>
revolutPayOptions?: EmbeddedCheckoutRevolutPayOptions
onSuccess?: (payload: { orderId: string }) => void
onError?: (payload: { error: RevolutCheckoutError; orderId: string }) => void
onCancel?: (payload: { orderId: string | undefined }) => void
email?: string
billingAddress?: Address
shippingOptions?: ShippingOption[]
onShippingAddressChange?: (address: Address) => Promise<ShippingAddressChangeResult>
onShippingOptionChange?: (option: ShippingOption) => Promise<ShippingChangeResult>
}
interface EmbeddedCheckoutRevolutPayOptions {
mobileRedirectUrls?: {
success: string
failure: string
cancel: string
}
}
interface EmbeddedCheckoutInstance {
destroy: () => void
}Parameters
| Parameter | Description | Type | Required |
|---|---|---|---|
options | Configuration object for the embedded checkout widget | EmbeddedCheckoutOptions | Yes |
EmbeddedCheckoutOptions interface
| Parameter | Description | Type | Required |
|---|---|---|---|
publicToken | Your Merchant API Public key | string | Yes |
mode | API environment | 'prod' | 'sandbox' | Yes |
locale | Widget language | Locale | 'auto' (default: 'auto') | No |
target | DOM element where the widget should be mounted | HTMLElement | Yes |
createOrder | Async function that calls your backend to create an order and returns the order token | () => Promise<{publicId: string}> | Yes |
revolutPayOptions | Configuration options specific to Revolut Pay within the embedded checkout widget. Required for Revolut Pay to be visible on mobile — see Revolut Pay options for details. | EmbeddedCheckoutRevolutPayOptions | No |
onSuccess | Callback triggered when payment completes successfully | (payload: {orderId: string}) => void | No |
onError | Callback triggered when payment fails. Receives RevolutCheckoutError | (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 |
email | Provide customer's email address. If provided, the email field is hidden from the checkout form | string | No |
billingAddress | Provide or skip the billing address form. If the provided address is valid, the billing form is hidden completely. If the address is invalid or incomplete, the form is shown with the pre-filled values. For the form to be hidden, countryCode, postcode, streetLine1, and city must be present and valid | Address | No |
shippingOptions | Available shipping options for the customer | ShippingOption[] | No |
onShippingAddressChange | Callback triggered when customer changes shipping address | (address: Address) => Promise<ShippingAddressChangeResult> | No |
onShippingOptionChange | Callback triggered when customer selects a different shipping option | (option: ShippingOption) => Promise<ShippingChangeResult> | No |
ShippingOption
interface ShippingOption {
id: string
label: string
amount: number
description?: string
}Defines a shipping option available to the customer.
| Property | Description | Type | Required |
|---|---|---|---|
id | Unique identifier for the shipping option | string | Yes |
label | Display name (e.g., "Standard Shipping") | string | Yes |
amount | Shipping cost in lowest currency denomination | number | Yes |
description | Additional details (e.g., "Delivery in 5-7 days") | string | No |
ShippingChangeResult
type ShippingChangeResult = {
status: 'success' | 'fail'
total: {
amount: number
label?: string
}
}Response from onShippingOptionChange callback with updated total.
ShippingAddressChangeResult
type ShippingAddressChangeResult = {
status: 'success' | 'fail'
shippingOptions?: ShippingOption[]
total: {
amount: number
label?: string
}
}Response from onShippingAddressChange callback with updated shipping options and total.
EmbeddedCheckoutRevolutPayOptions
Configuration options specific to Revolut Pay within the embedded checkout widget.
interface EmbeddedCheckoutRevolutPayOptions {
mobileRedirectUrls?: {
success: string
failure: string
cancel: string
}
}| Parameter | Description | Type | Required |
|---|---|---|---|
mobileRedirectUrls | An object with URLs for redirecting the user after a Revolut Pay payment on mobile devices. See mobile redirect behaviour below. | Object | No |
Mobile redirect behaviour
On mobile devices, Revolut Pay needs to redirect the user out of the checkout flow and back once payment completes. mobileRedirectUrls configures the destination URLs for this redirect — one for each payment outcome:
success— URL the customer is redirected to after a successful paymentfailure— URL the customer is redirected to after a failed paymentcancel— URL the customer is redirected to after cancelling the payment
Revolut Pay will not be displayed in the widget on mobile devices unless redirect targets are configured. You can provide them in one of two ways:
- SDK-level: Set
revolutPayOptions.mobileRedirectUrlsin theembeddedCheckout()configuration (recommended for the embedded checkout widget) - API-level: Set
redirect_urlwhen creating the order via the Merchant API
If neither is configured, Revolut Pay will not appear as a payment method in the widget on mobile devices.
If the order was created with a redirect_url parameter (Merchant API), that value takes precedence over revolutPayOptions.mobileRedirectUrls and is used for all three outcomes (success, failure, cancel).
When a user is redirected, Revolut Pay appends the order's public ID (token) as a query parameter named _rp_oid to the URL. For example, for a success URL of https://example.com/success, the final URL will be:
https://example.com/success?_rp_oid=fe34dbd3-3fa9-4d4c-8987-3f7735ba3cdf
You can retrieve this ID on your redirect page using the SDK's helper function:
import { getRevolutPayOrderIdURLParam } from '@revolut/checkout'
const revolutPublicOrderId = getRevolutPayOrderIdURLParam()The _rp_oid query parameter and the redirect URL are untrusted client-side values. A user can forge or replay them. Do not treat arrival at the success URL as proof of payment.
To verify a payment:
- Send
_rp_oidto your backend. - Retrieve the order through the Merchant API: Retrieve an order endpoint.
- Only fulfil the order when the returned state is
completed.
For critical backend actions such as order fulfilment, also use verified webhooks as the authoritative source of payment status.
For more details on redirect verification, see the Revolut Pay SDK reference.
Example:
const { destroy } = await RevolutCheckout.embeddedCheckout({
publicToken: '<yourPublicApiKey>',
mode: 'prod',
target: document.getElementById('checkout-container'),
createOrder: async () => {
const order = await yourServerSideCall()
return { publicId: order.token }
},
revolutPayOptions: {
mobileRedirectUrls: {
success: 'https://www.example.com/success',
failure: 'https://www.example.com/failure',
cancel: 'https://www.example.com/cancel',
},
},
onSuccess: ({ orderId }) => {
console.log('Payment successful!', orderId)
window.location.href = `/confirmation?orderId=${orderId}`
},
onError: ({ error, orderId }) => {
console.error('Payment failed:', error.message, orderId)
},
onCancel: ({ orderId }) => {
console.log('Payment cancelled', orderId)
},
})Return value
Promise<EmbeddedCheckoutInstance>
interface EmbeddedCheckoutInstance {
destroy: () => void
}The promise resolves with an EmbeddedCheckoutInstance object containing:
| Property | Description | Type |
|---|---|---|
destroy | Function to remove the widget from the page and clean up resources | () => void |
Callback events
The embedded checkout widget provides the following callback functions for handling payment lifecycle events in your frontend.
Widget callbacks are not guaranteed to fire due to network issues, browser closures, or ad-blockers. Always use webhooks for critical backend operations like order fulfilment.
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
(payload: { orderId: string }) => voidTriggered when the payment completes successfully.
Use cases:
- Display success message to the customer
- Redirect to order confirmation page
- Update UI to reflect successful payment
- Show success animations
Example:
onSuccess: ({ orderId }) => {
console.log('Payment successful!', orderId)
window.location.href = `/confirmation?orderId=${orderId}`
}onError
(payload: { error: RevolutCheckoutError; orderId: string }) => voidTriggered when the payment fails. The error parameter is a RevolutCheckoutError object containing error details.
Use cases:
- Display error message to the customer
- Log error for debugging
- Re-enable checkout form
- Show retry option
Example:
onError: ({ error, orderId }) => {
console.error('Payment failed:', error.message, orderId)
alert(`Payment failed: ${error.message}`)
}onCancel
(payload: { orderId: string | undefined }) => voidTriggered when the user cancels the payment. The orderId may be undefined if the order was not created yet.
Use cases:
- Display cancellation message
- Re-enable checkout form
- Track abandonment analytics
Example:
onCancel: ({ orderId }) => {
console.log('Payment cancelled', orderId)
alert('Payment was cancelled. You can try again.')
}onShippingAddressChange
(address: Address) => Promise<ShippingAddressChangeResult>Triggered when the customer changes their shipping address. Validate the address and return updated shipping options and order total.
Use cases:
- Validate delivery availability for the provided address
- Update shipping options based on the customer's region
- Recalculate order total with applicable shipping cost
Example:
const shippingOptions: ShippingOption[] = [
{ id: 'standard', label: 'Standard Shipping', amount: 500, description: 'Delivery in 5-7 days' },
{ id: 'express', label: 'Express Shipping', amount: 1000, description: 'Delivery in 1-2 days' }
]
const { destroy } = await RevolutCheckout.embeddedCheckout({
// ... other configuration
shippingOptions,
onShippingAddressChange: async (address) => {
const isValidRegion = await validateDeliveryRegion(address)
if (!isValidRegion) {
return {
status: 'fail',
total: { amount: 5000 }
}
}
return {
status: 'success',
shippingOptions,
total: { amount: 5000 + shippingOptions[0].amount }
}
}
})onShippingOptionChange
(option: ShippingOption) => Promise<ShippingChangeResult>Triggered when the customer selects a different shipping option. Return the updated order total.
Use cases:
- Recalculate order total with the selected shipping cost
- Update pricing display
Example:
onShippingOptionChange: async (selectedOption) => {
return {
status: 'success',
total: {
amount: 5000 + selectedOption.amount,
label: 'Total'
}
}
}Error handling
Throws: RevolutCheckoutError
The embedded checkout can throw errors in the following scenarios:
- Invalid
publicToken - Failed order creation in the
createOrdercallback - Network connectivity issues
- Invalid configuration options
- Widget loading failures
Example error handling:
try {
const { destroy } = await RevolutCheckout.embeddedCheckout({
// ... configuration
})
} catch (error) {
if (error.name === 'RevolutCheckout') {
console.error('Checkout initialisation failed:', error.message)
// Handle initialisation error
}
}For error handling within callbacks, see the onError callback section.
Usage example
import RevolutCheckout from '@revolut/checkout'
// Initialise and mount the embedded checkout
const { destroy } = await RevolutCheckout.embeddedCheckout({
publicToken: process.env.REVOLUT_PUBLIC_KEY,
mode: 'prod',
locale: 'auto',
target: document.getElementById('checkout-container'),
createOrder: async () => {
// Call your backend to create an order
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.')
},
})
// Later, if you need to remove the widget:
// destroy()Provide customer information
You can improve the checkout experience by providing customer information upfront:
const { destroy } = await RevolutCheckout.embeddedCheckout({
// ... other configuration
email: 'customer@example.com',
billingAddress: {
countryCode: 'GB',
region: 'Greater London',
city: 'London',
postcode: 'EC1A 1BB',
streetLine1: '1 Example Street',
streetLine2: 'Flat 2B',
},
})When you provide billingAddress, the widget applies the following behaviour:
- Valid address - the billing address form is hidden completely. The customer does not need to enter or review any address fields.
- Invalid or incomplete address - the billing address form is shown with the pre-filled values. The customer can review and correct any fields that failed validation.
For the form to be hidden, the widget pre-validates the address. The fields countryCode, postcode, streetLine1, and city must be present and valid. streetLine2 and region are not validated by the embedded checkout.
If email is provided — either in the widget configuration or on the order via the API — the email field is hidden from the checkout form.