paymentRequest()

Creates a Payment Request button that enables customers to pay with Apple Pay or Google Pay using the W3C Payment Request API. The SDK automatically detects available payment methods based on the user's device and browser.

Key features:

  • Automatic detection of Apple Pay/Google Pay availability
  • Native payment sheet experience
  • Built-in shipping address and options collection
  • Customisable button styles
  • Real-time shipping cost calculation
Info

For a complete implementation guide with examples, see: Accept payments via Apple Pay and Google Pay

Prerequisites

This payment method requires payments module initialisation. See: Payments module initialisation

Type signature

PaymentsInstance.paymentRequest(
target: HTMLElement,
options: PaymentRequestOptions
): PaymentRequestInstance

interface PaymentRequestOptions {
amount: number
currency: string
createOrder: () => Promise<{ publicId: string }>
onSuccess?: () => void
onError?: (error: RevolutCheckoutError) => void
onCancel?: () => void
validate?: (payload: PaymentValidationPayload) => void | Promise<void>
preferredPaymentMethod?: PaymentRequestPaymentMethod | PaymentRequestPaymentMethod[]
buttonStyle?: ButtonStyle
requestShipping?: boolean
shippingOptions?: ShippingOption[]
onShippingOptionChange?: (option: ShippingOption) => Promise<ShippingChangeResult>
onShippingAddressChange?: (address: Address) => Promise<ShippingAddressChangeResult>
}

interface PaymentRequestInstance {
render: () => Promise<void>
canMakePayment: () => Promise<PaymentRequestPaymentMethod | null>
destroy: () => void
}

type PaymentRequestPaymentMethod = 'applePay' | 'googlePay'

Parameters

ParameterDescriptionTypeRequired
targetDOM element where the payment button should be mountedHTMLElementYes
optionsConfiguration object for the payment requestPaymentRequestOptionsYes

PaymentRequestOptions interface

ParameterDescriptionTypeRequired
amountPayment amount in lowest currency denomination (e.g., cents)numberYes
currencyISO 4217 currency code (uppercase). See: Supported currenciesstringYes
createOrderAsync function that calls your backend to create an order and returns the order token() => Promise<{publicId: string}>Yes
onSuccessCallback triggered when payment completes successfully() => voidNo
onErrorCallback triggered when payment fails. Receives RevolutCheckoutError(error: RevolutCheckoutError) => voidNo
onCancelCallback triggered when user cancels payment() => voidNo
validateAsync validation function executed before payment processing. Should throw error if validation fails(payload: PaymentValidationPayload) => void | Promise<void>No
preferredPaymentMethodPreferred payment method or array of methods in order of preference'applePay' | 'googlePay' | Array<'applePay' | 'googlePay'>No
buttonStyleButton appearance customisationButtonStyleNo
requestShippingEnable shipping address and delivery method collectionboolean (default: false)No
shippingOptionsAvailable shipping options for the customerShippingOption[]No
onShippingOptionChangeCallback triggered when customer selects a different shipping option(option: ShippingOption) => Promise<ShippingChangeResult>No
onShippingAddressChangeCallback triggered when customer changes shipping address(address: Address) => Promise<ShippingAddressChangeResult>No

ButtonStyle

type ButtonStyle = {
action?: 'subscribe' | 'donate' | 'pay' | 'buy'
size?: 'small' | 'large'
radius?: 'none' | 'small' | 'large' | 'round'
variant?: 'light' | 'dark' | 'light-outlined'
height?: string
}

Customises the payment button appearance.

PropertyDescriptionTypeDefault
actionButton action text (e.g., "Buy with Apple Pay")'subscribe' | 'donate' | 'pay' | 'buy'null
sizeButton width: 'large' fills container, 'small' fits content'small' | 'large''large'
radiusBorder radius size'none' | 'small' | 'large' | 'round''small'
variantColour theme'light' | 'dark' | 'light-outlined''dark'
heightCustom height (CSS value, e.g., '48px')string-

ShippingOption

interface ShippingOption {
id: string
label: string
amount: number
description?: string
}

Defines a shipping option available to the customer.

PropertyDescriptionTypeRequired
idUnique identifier for the shipping optionstringYes
labelDisplay name (e.g., "Standard Shipping")stringYes
amountShipping cost in lowest currency denominationnumberYes
descriptionAdditional details (e.g., "Delivery in 5-7 days")stringNo

PaymentValidationPayload

type PaymentValidationPayload = {
email?: string
shippingAddress?: W3CPaymentAddress
billingAddress?: W3CPaymentAddress
}

Customer data passed to the validate callback for pre-payment validation.

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.

Return value

PaymentRequestInstance

interface PaymentRequestInstance {
render: () => Promise<void>
canMakePayment: () => Promise<PaymentRequestPaymentMethod | null>
destroy: () => void
}

The method returns a PaymentRequestInstance object containing:

MethodDescriptionType
renderRender the payment button after confirming availability() => Promise<void>
canMakePaymentCheck if Apple Pay or Google Pay is available on this device/browser() => Promise<'applePay' | 'googlePay' | null>
destroyRemove the button and clean up resources() => void

Check payment method availability

Always call canMakePayment() before rendering the button:

const instance = paymentRequest(target, options)
const method = await instance.canMakePayment()

if (method) {
// Apple Pay or Google Pay is available
instance.render()
} else {
// No supported payment method - clean up
instance.destroy()
}

Callback events

The payment request provides callback functions for handling payment lifecycle events.

Caution

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.

onSuccess

() => 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:

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

onError

(error: RevolutCheckoutError) => void

Triggered 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

Example:

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

onCancel

() => void

Triggered when the user cancels the payment (e.g., closes the payment sheet).

Use cases:

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

Example:

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

Usage examples

import RevolutCheckout from '@revolut/checkout'

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

// Create payment request button
const target = document.getElementById('payment-request')
const instance = paymentRequest(target, {
amount: 1000,
currency: 'USD',

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

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

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

onCancel: () => {
console.log('Payment cancelled')
}
})

// Check availability and render
const method = await instance.canMakePayment()
if (method) {
console.log(`${method} is available`)
instance.render()
} else {
console.log('Apple Pay / Google Pay not available')
instance.destroy()
}

Custom button styling

Customise the payment button appearance to match your design:

const instance = paymentRequest(target, {
amount: 1000,
currency: 'USD',
createOrder: async () => { /* ... */ },

buttonStyle: {
action: 'buy',
size: 'large',
radius: 'small',
variant: 'dark',
height: '48px'
},

onSuccess: () => {
window.location.href = '/confirmation'
},

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

With shipping options

Collect shipping address and offer delivery options:

const shippingOptions = [
{
id: 'standard',
label: 'Standard Shipping',
amount: 500,
description: 'Delivery in 5-7 business days'
},
{
id: 'express',
label: 'Express Shipping',
amount: 1000,
description: 'Delivery in 1-2 business days'
}
]

const instance = paymentRequest(target, {
amount: 5000,
currency: 'USD',
createOrder: async () => { /* ... */ },

requestShipping: true,
shippingOptions,

onShippingOptionChange: async (selectedOption) => {
// Recalculate total with new shipping cost
return {
status: 'success',
total: {
amount: 5000 + selectedOption.amount,
label: 'Total'
}
}
},

onShippingAddressChange: async (address) => {
// Validate address and potentially update shipping options
const isValidRegion = address.country === 'US'

if (!isValidRegion) {
return {
status: 'fail',
total: { amount: 5000 }
}
}

// Offer express shipping for nearby regions
const updatedOptions = address.region === 'CA'
? [
...shippingOptions,
{
id: 'same-day',
label: 'Same-Day Delivery',
amount: 2000,
description: 'Delivery today'
}
]
: shippingOptions

return {
status: 'success',
shippingOptions: updatedOptions,
total: {
amount: 5000 + shippingOptions[0].amount
}
}
},

onSuccess: () => {
window.location.href = '/confirmation'
},

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

Pre-payment validation

Validate customer data before processing payment:

const instance = paymentRequest(target, {
amount: 1000,
currency: 'USD',
createOrder: async () => { /* ... */ },

validate: async (payload) => {
// Validate email format
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
if (payload.email && !emailRegex.test(payload.email)) {
throw new Error('Invalid email address')
}

// Validate shipping address with backend
if (payload.shippingAddress) {
const response = await fetch('/api/validate-address', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload.shippingAddress)
})

if (!response.ok) {
throw new Error('Invalid shipping address')
}
}
},

onSuccess: () => {
window.location.href = '/confirmation'
},

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

See also

Was this page helpful?