Accept payments via Revolut Pay - iOS
Welcome to the implementation guide for Revolut Pay on iOS! This page provides a comprehensive walkthrough for integrating Revolut Pay into your iOS application, allowing your customers to pay with their card or Revolut account for a streamlined checkout experience.

How it works
From an implementation perspective, the Revolut Pay iOS SDK works with the following components:
- Server-side: A server-side endpoint is required to securely communicate with the Merchant API to create orders.
- Client-side: The SDK is configured in your app with your public API key. When the customer taps the Revolut Pay button, the SDK uses the
tokenobtained from your server to initate and process the payment. The SDK handles the entire payment flow, including presenting native sheets, handling biometric authentication, and redirecting to the Revolut app if necessary. - Endpoint for webhooks: Your server should listen for webhook events to reliably track the payment lifecycle and handle critical backend processes like updating order status, managing inventory, or initiating shipping. For more information, see: Use webhooks to keep track of the payment lifecycle.
The payment flow differs slightly based on the SDK version you integrate and whether the customer has the Revolut app installed.
With the modern native SDK, the entire payment experience, including login and payment authorisation, occurs within a native interface inside your app. This provides the most seamless experience for the user, regardless of whether they have the Revolut app installed.
- The customer taps the Revolut Pay button in your app.
- Your app obtains an order
tokenfrom your server and passes to the SDK for initialisation. - The SDK presents a native payment sheet where the customer reviews and authorises the payment, potentially using biometrics or passkeys.
- The SDK processes the payment and returns the result to your app via a completion handler. You should use this result to update your UI (e.g., show a success or failure message).
- Your server receives webhook notifications to confirm the payment's final state and securely fulfill the order.
Available versions
The Revolut Pay iOS SDK is available in two versions:
-
Revolut Pay native SDK (recommended): This version is available via the
RevolutPayments/RevolutPaymodule. It provides a fully native payment flow, offering a superior user experience directly within your app.noteIntegrating this version will add approximately 45MB to your app's total size.
-
Lightweight WebView-based SDK (replaces 2.x.x): This lightweight version is available via the
RevolutPayments/RevolutPayLitemodule. It uses a flow that prioritises redirecting to the Revolut app, with a WebView-based experience as a fallback if the app is not installed. All2.x.xversions are now considered deprecated in favour ofRevolutPayLite.
Implementation overview
Check the following high-level overview on how to implement Revolut Pay in your app:
- Set up an endpoint for creating orders
- Configure your Xcode project
- Initialise the SDK
- Add the Revolut Pay button
- Handle payment result
Before you begin
Before you start this tutorial, ensure that you have completed the following steps:
Implement Revolut Pay on iOS
This section walks you through the server- and client-side implementation step by step.
1. Set up an endpoint for creating orders
Before the Revolut Pay button can be displayed in your app, your client-side code needs to fetch a unique, single-use token that represents an order. This token can only be created on your server by making a secure call to the Revolut Merchant API.
This server-side endpoint is a mandatory security requirement. Your secret API key must never be exposed in your iOS application.
When a customer taps the Revolut Pay button in your app, your app will call this endpoint. Your endpoint is then responsible for:
- Receive the checkout details (e.g.,
amount,currency) from your client-side request. - Securely call the Merchant API: Create an order endpoint with the checkout details.
- Receive the order object, including the public
token, in the API response. - Return the
tokenfrom the response to your app.
Later, in the client-side configuration, the createOrder callback function will call this endpoint to fetch the token, which is required to initialise the SDK and display the Revolut Pay button.
Below is an example of the JSON response your endpoint will receive from the Merchant API after successfully creating an order. The crucial field to extract and return to your app is the token.
{
"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": 1000,
"currency": "GBP",
"outstanding_amount": 1000,
"capture_mode": "automatic",
"checkout_url": "https://checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
"enforce_challenge": "automatic"
}
2. Configure your Xcode project
This section covers the one-time setup tasks required to prepare your Xcode project for the SDK.
2.1 Install the SDK
The minimum supported iOS version is 13.0.
CocoaPods
We recommend using CocoaPods to integrate the SDK into your Xcode project.
Check the available versions section to determine which SDK variant is right for your needs.
-
Ensure you have the latest version of CocoaPods installed.
-
If your project doesn't have a
Podfileyet, create one by running:pod init -
Add the following line to your
Podfile:pod 'RevolutPayments/RevolutPay' -
At the end of your
Podfile, add this configuration:post_install do |installer|
installer.generated_projects.each do |project|
project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
end
end
end
end -
Install the dependencies:
pod install -
From now on, open your project using the
.xcworkspacefile rather than the.xcodeprojfile. -
To ensure the SDK uses the latest version, run:
pod update RevolutPayments/RevolutPaynoteRun this command to update the SDK to a newer version in the future.
2.2 Configure project capabilities
To allow your app to open the Revolut retail app, you must declare the revolut URL scheme in your Info.plist file.
<key>LSApplicationQueriesSchemes</key>
<array>
<string>revolut</string>
</array>
2.3 Enable biometrics and passkeys support
This step is only required when implementing the Native SDK.
To offer users a seamless and secure login experience with Face ID, Touch ID, and passkeys, you must associate your app with our web service.
-
Configure your App ID for Passkeys: To configure passkeys, you need your App ID, which is a combination of your App ID Prefix and your Bundle ID.
It's crucial to get the correct App ID Prefix. This may be different from the Team ID shown in your main Apple Developer account page or in Xcode, especially for older developer accounts or apps that have been transferred between accounts.
To find the correct App ID Prefix and Bundle ID:
- Log in to your developer account at developer.apple.com >
Certificates, IDs & Profiles>Identifiers. - Select your app from the list.
- Here you will find the App ID Prefix (e.g.,
ABCDE12345) and your app's Bundle ID (e.g.,com.yourcompany.yourapp).
Your final App ID will be in the format:
<App ID Prefix>.<Bundle ID>, based on our example:ABCDE12345.com.yourcompany.yourapp. - Log in to your developer account at developer.apple.com >
-
Register your App ID with Revolut: Email your verified App ID to merchant-integration@revolut.com.
-
Add the Associated Domain to your project: Once Revolut confirms your App ID registration, you must link your app to the Revolut domain.
- In your Xcode project, go to Signing & Capabilities.
- Click + Capability and add the Associated Domains capability.
- In the domains field, add the following entry:
webcredentials:revolut.com.
cautionImportant Update for SDK 3.9+
Starting with SDK version 3.9, you must use
webcredentials:revolut.com.The previous domain,
webcredentials:sso.revolut.com, is now deprecated. Please ensure your Associated Domains configuration is updated.Migrating from 3.9>
If you are updating from a version of the SDK prior to 3.9.0, you will need to update your Associated Domains configuration.
- In your Xcode project, navigate to Signing & Capabilities.
- Find the Associated Domains section.
- Replace the old entry
webcredentials:sso.revolut.comwith the new entrywebcredentials:revolut.com.
2.4 Add the URL handler
When the user is redirected from the Revolut app back to yours, you must pass the incoming URL to the SDK.
Your implementation depends on your app's lifecycle management. Use the UISceneDelegate method for modern, scene-based apps (the default since iOS 13), which support features like multiple windows on iPad. Use the AppDelegate method for older apps or if you have explicitly opted out of the scene-based lifecycle.
If you are using UISceneDelegate, add this to your SceneDelegate:
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
if let url = URLContexts.first?.url {
RevolutPayKit.handle(url: url)
}
}
3. Initialise the SDK
First, import the RevolutPayments module. Then, on app launch, typically in your AppDelegate, configure the SDK with your public API key and the environment.
import RevolutPayments
// In your AppDelegate's didFinishLaunchingWithOptions method
RevolutPaymentsSDK.configure(with: .init(
merchantPublicKey: "<yourPublicApiKey>",
environment: .production // or .sandbox for testing
))
4. Add the Revolut Pay button
On your checkout screen, create and display the Revolut Pay button.
4.1 Create the button
Instantiate RevolutPayKit and call the button method. This is where you connect your server-side endpoint and define what happens after the payment attempt.
let revolutPayKit = RevolutPayKit()
let button = revolutPayKit.button(
style: .init(size: .large),
returnURL: "myapp://revolut-pay", // Your app's custom URL scheme
createOrder: { createOrderHandler in
// 1. Call your server to create the order
createOrderOnBackEnd { orderToken in
// 2. Pass the token to the SDK
createOrderHandler.set(orderToken: orderToken)
}
},
completion: { result in
switch result {
case .success:
// Handle successful payment
case .failure(let error):
// Handle payment error
case .userAbandonedPayment:
// Handle abandoned payment
}
}
)
For more information about the parameters and button styling, see: Parameters: iOS and Revolut Pay button guidelines.
4.2 Display the button
Add the created button to your view hierarchy.
view.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
button.bottomAnchor.constraint(equalTo: view.bottomAnchor),
button.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor),
button.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor),
button.centerXAnchor.constraint(equalTo: view.centerXAnchor)
])
4.3 Advanced features
You can enable additional features like saving payment methods or Fast Checkout within the button initaliser.
- Merchant Initiated Transactions (MIT): To save a customer's payment method for future use (e.g., subscriptions), pass
savePaymentMethodForMerchant: true. See our guide on charging a saved payment method for details. - Fast checkout: To collect shipping details via Revolut Pay, pass
shouldRequestShipping: ture. This requires your backend to support the Fast checkout flow. See the Fast Checkout guide for details.
Fast checkout and MIT are mutually exclusive. You can enable one or the other, but not both in the same transaction.
Add a promotional banner
You can use the promotional banner widget to offer rewards to customers who create a new Revolut account after checkout.
We recommend implementing the promotional banner. Analysis has shown that having the upsell widget can increase conversion to payment by ~5%.
First, configure the banner by calling revolutPayKit.promotionalBanner method:
let promotionalBanner = revolutPayKit.promotionalBanner(
transactionId: "transaction-id", // Unique ID of the payment corresponding to the promotional offer
amount: 10_00,
currency: .EUR,
customer: .init()
)
Then, add the banner to your view hierarchy, for example on your order confirmation screen:
view.addSubview(promotionalBanner)
promotionalBanner.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
promotionalBanner.topAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.topAnchor,
constant: 16
),
promotionalBanner.trailingAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.trailingAnchor,
constant: -16
),
promotionalBanner.leadingAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.leadingAnchor,
constant: 16
)
])
For more information about the possible parameters of the banner, see: Revolut Pay iOS SDK: RevolutPayKit.promotionalBanner.
5. Handle payment result
The client-side completion handler is for UI updates only. Its delivery is not guaranteed due to network conditions or other issues. You must rely on server-to-server webhooks to get the final, authoritative status of a payment before fulfilling the order.
The completion block passed to the button method provides a Result type that tells you if the payment succeeded, failed, or was cancelled. Use this to show an appropriate message to the user.
If all the steps have been followed correctly, you have successfully implemented Revolut Pay! 🎉
Example
For a complete, working implementation, please refer to the example app included in our public SDK repository.
To run the example app:
- Clone the repository.
- Navigate to the
ExampleAppdirectory within the latest release. - Run
make projectto install dependencies. - Open
RevolutPayApp.xcworkspacein Xcode and run the project.
Preparing for App Store submission
To comply with Apple's App Store requirements, you must include our privacy manifest in your app. This file, named PrivacyInfo.xcprivacy, details the data collection practices of the Revolut Pay SDK.
Because the Revolut Pay SDK is distributed as a static library, you must manually merge our PrivacyInfo.xcprivacy file with your app's primary privacy manifest.
These steps are required to prepare your iOS application for Apple's review policies and ensure that your Revolut Pay integration adheres to their privacy standards.
For merchants using the Native SDK, privacy manifests are available from version 3.2.1:
- The privacy manifest file is located within the
RevolutPayments.ziparchive underFrameworks/RevolutPay/RevolutPayNativeSDK.bundle/PrivacyInfo.xcprivacy. - Download the archive from the latest Release and extract the privacy manifest.
- Add the privacy manifest to your app's resources:
- If your app does not currently use a privacy manifest, simply add the SDK's file to your app's resources.
- If you already have an existing privacy manifest, merge the SDK's manifest with your app's existing privacy document to ensure compliance with Apple's new requirements. Address any conflicts by integrating data handling practices from both the SDK and your app into a unified document.
Implementation checklist
The Sandbox environment is designed to replicate the production environment's behaviour, with the key difference being the absence of app redirection due to the lack of a sandbox version of the Revolut retail app.
For more information about Revolut Pay payment flows in Sandbox, see: Test flows.
Before going live, use this checklist to test your integration in both the .sandbox and .production environments.
Project setup
-
SDK is installed via CocoaPods.
-
Info.plistcontains therevolutURL scheme. -
Associated Domain
webcredentials:revolut.comis configured for passkeys.cautionDouble-check your Associated Domain, if you used an SDK version before 3.9.
-
The SDK is initialised with the correct public API key and environment.
-
The Privacy Manifest is correctly merged into the app's resources.
Payment flow
- The Revolut Pay button appears correctly on the checkout screen.
- Tapping the button successfully calls your server to create an order and receives a
token. - Test case 1 (Revolut app not installed): The payment flow completes successfully within the in-app native/WebView flow.
- Test case 2 (Revolut app installed): The payment flow correctly redirects to the Revolut app and back.
- Test case 3 (Biometrics): Passkey/Face ID/Touch ID login works as expected (requires a real device).
- A successful payment shows a success message in the UI.
- A failed payment shows an appropriate error message in the UI.
- The user cancelling the payment flow is handled gracefully.
Backend verification
- Your server correctly receives and processes webhook events for different payment states (e.g.,
ORDER_COMPLETED,ORDER_AUTHORISEDfor success;ORDER_PAYMENT_FAILED,ORDER_CANCELLEDfor failure or cancellation). - Order fulfillment logic is only triggered after receiving a successful webhook, not from the client-side callback.