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
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
| Parameter | Description | Type | Required |
|---|---|---|---|
target | DOM element where the payment button should be mounted | HTMLElement | Yes |
options | Configuration object for the payment request | PaymentRequestOptions | Yes |
PaymentRequestOptions interface
| Parameter | Description | Type | Required |
|---|---|---|---|
amount | Payment amount in lowest currency denomination (e.g., cents) | number | Yes |
currency | ISO 4217 currency code (uppercase). See: Supported currencies | string | Yes |
createOrder | Async function that calls your backend to create an order and returns the order token | () => Promise<{publicId: string}> | Yes |
onSuccess | Callback triggered when payment completes successfully | () => void | No |
onError | Callback triggered when payment fails. Receives RevolutCheckoutError | (error: RevolutCheckoutError) => void | No |
onCancel | Callback triggered when user cancels payment | () => void | No |
validate | Async validation function executed before payment processing. Should throw error if validation fails | (payload: PaymentValidationPayload) => void | Promise<void> | No |
preferredPaymentMethod | Preferred payment method or array of methods in order of preference | 'applePay' | 'googlePay' | Array<'applePay' | 'googlePay'> | No |
buttonStyle | Button appearance customisation | ButtonStyle | No |
requestShipping | Enable shipping address and delivery method collection | boolean (default: false) | No |
shippingOptions | Available shipping options for the customer | ShippingOption[] | No |
onShippingOptionChange | Callback triggered when customer selects a different shipping option | (option: ShippingOption) => Promise<ShippingChangeResult> | No |
onShippingAddressChange | Callback 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.
| Property | Description | Type | Default |
|---|---|---|---|
action | Button action text (e.g., "Buy with Apple Pay") | 'subscribe' | 'donate' | 'pay' | 'buy' | null |
size | Button width: 'large' fills container, 'small' fits content | 'small' | 'large' | 'large' |
radius | Border radius size | 'none' | 'small' | 'large' | 'round' | 'small' |
variant | Colour theme | 'light' | 'dark' | 'light-outlined' | 'dark' |
height | Custom 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.
| 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 |
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:
| Method | Description | Type |
|---|---|---|
render | Render the payment button after confirming availability | () => Promise<void> |
canMakePayment | Check if Apple Pay or Google Pay is available on this device/browser | () => Promise<'applePay' | 'googlePay' | null> |
destroy | Remove 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.
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}`)
}
})