About SumUp iOS SDK
Section titled “About SumUp iOS SDK”SumUp provides a native iOS SDK that enables you to integrate SumUp's proprietary card terminal(s) and its payment platform to accept credit and debit card payments (incl. VISA, MasterCard, American Express and more) as well as Tap-to-Pay payments on iPhones. SumUp's SDK communicates transparently to the card terminal(s) via Bluetooth. Upon initiating a checkout, the SDK guides your user using appropriate screens through each step of the payment process. As part of the process, SumUp also provides the card terminal setup screen, along with the cardholder signature verification screen. The checkout result is returned with the relevant data for your records.
No sensitive card data is ever passed through to or stored on the merchant’s phone. All data is encrypted by the card terminal, which has been fully certified to the highest industry standards (PCI, EMV I & II, Visa, MasterCard & Amex).
SumUp iOS SDK is provided as an Objective C binary. However, when you use the SDK in Swift projects, Xcode uses automatic bridging to generate Swift-friendly interfaces from the Objective-C headers. For that reason, code samples in this guide are provided both in Swift and Objective C.
The iOS SDK includes a Sample App, which you can run out-of-the-box to immediately test the implementation in practice.
Prerequisites
Section titled “Prerequisites”- Registered for a merchant account via SumUp's country websites (or received a test account).
- Received SumUp card terminal: Solo Lite, Solo, Air, 3G, PIN+.
- Requested an Affiliate (Access) Key via SumUp Dashboard for Developers.
- Deployment Target iOS 14.0 or later.
- Recommended to use on Xcode 14.3.1 and iOS SDK 16 or later.
- iPhone or iPad.
- If your device is managed by an organization, make sure app installation is permitted.
Compatibility
Section titled “Compatibility”- From version 4.4.0 of the SDK, iOS 14 or later is required
- The SDK supports all device orientations on iPad and portrait on iPhone. Feel free to support other orientations on iPhone but please keep in mind that the SDK's UI will be presented in portrait on iPhone. See
UISupportedInterfaceOrientations
in the sample app'sInfo.plist
or the "General" tab in Xcode's Target Editor.
Match Affiliate Key to App Bundle ID
Section titled “Match Affiliate Key to App Bundle ID”iOS SDK uses the Affiliate Key from your merchant account to authenticate your app.
- Log in to SumUp with your merchant account and open the Affiliate Key page.
- Create an Affiliate Key if you don't have one yet.
- Add your app's Bundle ID in the SumUp portal's Application ID field. This way, your app will be able to call SumUp APIs, which require the Affiliate Key.
Add Property List Keys to Project
Section titled “Add Property List Keys to Project”The SumUp iOS SDK requires access to the user's location and Bluetooth peripherals. If your app has not asked for the user's permission, the SumUp iOS SDK will ask at the time of the first login or checkout attempt. Please add the following keys to your info.plist
file and set some values:
NSLocationWhenInUseUsageDescriptionNSBluetoothAlwaysUsageDescriptionNSBluetoothPeripheralUsageDescription (unless your deployment target is at least iOS 13)
Check the Sample App property list for reference.
Fast-track Implementation
Section titled “Fast-track Implementation”If you want to dive straight into implementation, carry out the following steps:
Card Reader Flow
Section titled “Card Reader Flow”- Install the SDK.
- Import the SDK into your project file.
- Initialize the SDK with an Affiliate Key.
- Log the user in.
- Prepare user's device for checkout.
- Allow the user to select a card reader.
- Finally, implement the full checkout.
Tap-to-Pay Flow
Section titled “Tap-to-Pay Flow”Please consider the following when building Tap-to-Pay solutions, as Apple reviews them with high scrutiny:
- Follow the Human Interface Guidelines to save time when Apple reviews your app.
- Also consider Apple’s marketing guidelines and use standard assets where possible.
- Install the SDK.
- Import the SDK into your project file.
- Initialize the SDK with an Affiliate Key.
- Log the user in.
- Follow steps under Implementing Tap-to-Pay.
Integrating iOS SDK
Section titled “Integrating iOS SDK”Adding SDK Framework to Project
Section titled “Adding SDK Framework to Project”The SumUp iOS SDK is provided as an XCFramework SumUpSDK.xcframework
that contains the headers and bundles containing resources such as images and localizations. You can add the SDK binary manually or use a package manager such as Swift Package Manager, Cocoapods, or Carthage. Please follow the relevant instructions below to prepare your project:
The latest Swift Package Manager version added support to distribute binary frameworks as Swift Packages.
If you're using Xcode 12.3 or later, this should work out of the box.
Unfortunately, Xcode 12 releases before that had an issue, (https://bugs.swift.org/browse/SR-13343), that added the framework as a static library, not as an embedded dynamic framework.
Follow this workaround to manage SumUp iOS SDK versions via Swift PM in those cases:
- Add the package dependency to the repository
https://github.com/sumup/sumup-ios-sdk
(File > Swift Packages > Add Package Dependency...) with the versionUp to Next Major: 4.0.0
- Leave the checkbox unchecked for the SumUpSDK at the integration popup (Add Package to ...:)
- From the Project Navigator, drag and drop the
SumUpSDK/Referenced Binaries/SumUpSDK.xcframework
to your Xcode project's "Frameworks, Libraries, and Embedded Content" on the General settings tab. - Make sure the required Info.plist keys are present.
To learn more about adding Swift Package dependencies, please refer to the official documentation.
- Drag and drop the
SumUpSDK.xcframework
to your Xcode project's "Frameworks, Libraries, and Embedded Content" on the project General Settings tab. - Make sure the required Info.plist keys are present.
target '<Your Target Name>' do pod 'SumUpSDK', '~> 6.0'end
Distributing XCFrameworks with the latest Carthage version (0.35.0) is not yet available. There is an open issue (#2799) to solve this. Once that issue is fixed, we expect Carthage to work again.
The SumUp iOS SDK can be integrated with Carthage by following the steps below:
- Add the following line to your
Cartfile
:github "sumup/sumup-ios-sdk" - Run
carthage update sumup-ios-sdk
- Drag and drop the
Carthage/Build/iOS/SumUpSDK.xcframework
to your Xcode project's "Frameworks, Libraries, and Embedded Content" on the General settings tab. - Make sure the required Info.plist keys are present.
To learn more about setting up your project for Carthage, please refer to the official documentation.
Importing SDK
Section titled “Importing SDK”To import the SDK in Objective-C source files, you can use #import <SumUpSDK/SumUpSDK.h>
. If module support is enabled in your project, you can use @import SumUpSDK;
instead.
In Swift, use import SumUpSDK
. You do not have to add any headers to your bridging header.
Authentication - Component Definitions
Section titled “Authentication - Component Definitions”SumUp iOS SDK supports either a modally presented login from a view controller (as you can see in the Sample App) or using an Access Token via the Authorization Code Flow.
/** * Presents the login modally from the given view controller. * * The login is automatically dismissed if login was successful or cancelled by the user. * If error is nil and success is NO, the user cancelled the login. * Errors are handled internally and usually do not need any display to the user. * Does nothing if merchant is already logged in (calls completion block with success=NO, error=nil). * * @param fromViewController The UIViewController instance from which the login should be presented modally. * @param animated Pass YES to animate the transition. * @param block The completion block is called after each login attempt. */+ (void)presentLoginFromViewController:(UIViewController *)fromViewController animated:(BOOL)animated completionBlock:(nullable SMPCompletionBlock)block;
/** * Logs in a merchant with an access token acquired via https://developer.sumup.com/docs/authorization/. * You must implement the "Authorization code flow", the "Client credentials flow" is not supported. * Make sure that no user is logged in already when calling this method. * * @param aToken a user-scoped access token * @param block a completion block that will run after login has succeeded/failed */+ (void)loginWithToken:(NSString *)aToken completion:(nullable SMPCompletionBlock)block;
/** * Performs a logout of the current merchant and resets the remembered password. * * @param block The completion block is called once the logout has finished. */+ (void)logoutWithCompletionBlock:(nullable SMPCompletionBlock)block;
Implementing Authentication
Section titled “Implementing Authentication”Initialization
Section titled “Initialization”Before calling any additional feature of the SumUp iOS SDK, you are required to set up the SDK with your Affiliate Key. Call on the main thread. You may wish to defer calling setupWithAPIKey:
until after app launch, as it requests the user's location permission.

import SumUpSDKimport UIKit
@UIApplicationMainclass AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
/* * This will setup the SumUpSDK. * * You might consider moving this to a later point in your application's lifecycle, * as this will start updating for locations. * * Also remember to provide the necessary usage descriptions in your info.plist * and to properly localize it, see the * Add Property List Keys to Project section. * * Ensure to add the Bundle Identifier of your iOS app to your * Affiliate Key's Application identifiers in the SumUp developer portal. */ SumUpSDK.setup(withAPIKey: "sup_afk_abcqwerty") return true }
}
#import "SUSAppDelegate.h"#import <SumUpSDK/SumUpSDK.h>
@implementation SUSAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { /* * This will setup the SumUpSDK. * * You might consider moving this to a later point in your application's lifecycle, * as this will start updating for locations. * * Also remember to provide the necessary usage descriptions in your info.plist * and to properly localize it, see the * Add Property List Keys to Project section. * * Ensure to add the Bundle Identifier of your iOS app to your * API Key's Application identifiers in the SumUp developer portal. */ [SMPSumUpSDK setupWithAPIKey:@"sup_afk_abcqwerty"]; return YES;}
Logging the user in
Section titled “Logging the user in”Following app authentication, a registered SumUp merchant account needs to be logged in. Present a login screen from your UIViewController:

private func presentLogin() { // present login UI and wait for completion block to update button states SumUpSDK.presentLogin(from: self, animated: true) { [weak self] (success: Bool, error: Error?) in print("Did present login with success: \(success). Error: \(String(describing: error))")
guard error == nil else { // errors are handled within the SDK, there should be no need // for your app to display any error message return }
self?.updateCurrency() self?.updateButtonStates() }}
- (IBAction)buttonLoginTapped:(id)sender { [SMPSumUpSDK presentLoginFromViewController:self animated:YES completionBlock:^(BOOL success, NSError *error) { if (error) { // errors are handled within the SDK, there should be no need // for your app to display any error message }
[self updateButtonState]; }];}
Logging the user out
Section titled “Logging the user out”Similarly, you can log the user out.
fileprivate func requestLogout() { SumUpSDK.logout { [weak self] (success: Bool, error: Error?) in print("Did log out with success: \(success). Error: \(String(describing: error))") self?.updateButtonStates() }}
- (IBAction)buttonLogoutTapped:(id)sender { [SMPSumUpSDK logoutWithCompletionBlock:^(BOOL success, NSError *error) { [self updateButtonState]; }];}
Payment Checkout Definitions
Section titled “Payment Checkout Definitions”- In order to prepare a SumUp card terminal for checkout,
prepareForCheckout
can be called in advance. A registered SumUp merchant account needs to be logged in, and the card terminal must already be setup. You should use this method to let the SDK know that the user is most likely starting a checkout attempt soon; for example when entering an amount or adding products to a shopping cart. This allows the SDK to take appropriate measures, like attempting to wake a connected card terminal. - When logged in you can let merchants check and update their checkout preferences. Merchants can select their preferred card terminal and set up a new one if needed. The preferences available to a merchant depend on their respective account settings.
- Present Checkout View is the main checkout request definition.
Check these methods and included comments before moving on to implementation below.
/** * Can be called in advance when a checkout is imminent and a user is logged in. * You should use this method to let the SDK know that the user is most likely starting a * checkout attempt soon, e.g. when entering an amount or adding products to a shopping cart. * This allows the SDK to take appropriate measures, like attempting to wake a connected card terminal. */+ (void)prepareForCheckout;
/** * Presenting checkout preferences allows the current merchant to configure the checkout options and * change the card terminal. Merchants can also set up the terminal when applicable. * Can only be called when a merchant is logged in and checkout is not in progress. * The completion block will be executed once the preferences have been dismissed. * The success parameter indicates whether the preferences have been presented. * If not successful an error will be provided, see SMPSumUpSDKError. * * @param fromViewController The UIViewController instance from which the checkout should be presented modally. * @param animated Pass YES to animate the transition. * @param block The completion block is called after the view controller has been dismissed. */+ (void)presentCheckoutPreferencesFromViewController:(UIViewController *)fromViewController animated:(BOOL)animated completion:(nullable SMPCompletionBlock)block;
/** * Presents a checkout view with all necessary steps to charge a customer. * * @param request The SMPCheckoutRequest encapsulates all transaction relevant data such as total amount, label, etc. * @param controller The UIViewController instance from which the checkout should be presented modally. * @param block The completion block will be called when the view will be dismissed. */+ (void)checkoutWithRequest:(SMPCheckoutRequest *)request fromViewController:(UIViewController *)controller completion:(nullable SMPCheckoutCompletionBlock)block;
Adding Payment Checkout View
Section titled “Adding Payment Checkout View”In this step, we implement the payment checkout.
Prepare for Checkout
Section titled “Prepare for Checkout”- (BOOL)textFieldShouldReturn:(UITextField *)textField { if (textField == self.textFieldTotal) { // we assume a checkout is imminent // let the SDK know to e.g. wake a connected terminal [SMPSumUpSDK prepareForCheckout];
[self.textFieldTitle becomeFirstResponder]; } else if ([SMPSumUpSDK isLoggedIn]) { [self buttonChargeTapped:nil]; } else { [textField resignFirstResponder]; }
return YES;}
extension ViewController: UITextFieldDelegate { func textFieldShouldReturn(_ textField: UITextField) -> Bool { if textField == textFieldTotal { // we assume a checkout is imminent // let the SDK know to e.g. wake a connected terminal SumUpSDK.prepareForCheckout()
textFieldTitle?.becomeFirstResponder() } else if SumUpSDK.isLoggedIn { requestCheckout() } else { textField.resignFirstResponder() }
return true }}
Present Checkout Preferences
Section titled “Present Checkout Preferences”Provides the user a way to search for nearby Bluetooth card readers and select one to be used. The selected card reader will be saved to UserDefaults
and used for subsequent checkouts. Using this screen is optional. If a checkout is started but no card reader has been saved, the checkout itself will automatically present the screen to search for and select a card reader, and this will be saved for next time.


private func presentCheckoutPreferences() { SumUpSDK.presentCheckoutPreferences(from: self, animated: true) { [weak self] (success: Bool, presentationError: Error?) in print("Did present checkout preferences with success: \(success). Error: \(String(describing: presentationError))")
guard let safeError = presentationError as NSError? else { // no error, nothing else to do return }
print("error presenting checkout preferences: \(safeError)")
let errorMessage: String switch (safeError.domain, safeError.code) { case (SumUpSDKErrorDomain, SumUpSDKError.accountNotLoggedIn.rawValue): errorMessage = "not logged in"
case (SumUpSDKErrorDomain, SumUpSDKError.checkoutInProgress.rawValue): errorMessage = "checkout is in progress"
default: errorMessage = "general error" }
self?.showResult(string: errorMessage) }}
- (IBAction)buttonOpenPreferencesTapped:(id)sender { [SMPSumUpSDK presentCheckoutPreferencesFromViewController:self animated:YES completion:^(BOOL success, NSError *_Nullable error) { if (!success || error) { [self showResultsString:@"not logged in"]; } }];}
Present Checkout View
Section titled “Present Checkout View”Prepare a checkout request that encapsulates the information regarding the transaction.

SumUpSDK.checkout(with: request, from: self) { [weak self] (result: CheckoutResult?, error: Error?) in if let safeError = error as NSError? { print("error during checkout: \(safeError)")
if (safeError.domain == SumUpSDKErrorDomain) && (safeError.code == SumUpSDKError.accountNotLoggedIn.rawValue) { self?.showResult(string: "not logged in") } else { self?.showResult(string: "general error") }
return }
[SMPSumUpSDK checkoutWithRequest:request fromViewController:self completion:^(SMPCheckoutResult *result, NSError *error) { if ([error.domain isEqualToString:SMPSumUpSDKErrorDomain] && (error.code == SMPSumUpSDKErrorAccountNotLoggedIn)) { [self showResultsString:@"not logged in"]; return; }
NS_SWIFT_NAME(SumUpSDKErrorDomain)extern NSString * const SMPSumUpSDKErrorDomain;/** * The error codes returned from the SDK */typedef NS_ENUM(NSInteger, SMPSumUpSDKError) { /// General error SMPSumUpSDKErrorGeneral = 0, /// The merchant's account is not activated SMPSumUpSDKErrorActivationNeeded = 1, /// General error with the merchant's account SMPSumUpSDKErrorAccountGeneral = 20, /// The merchant is not logged in to their account SMPSumUpSDKErrorAccountNotLoggedIn = 21, /// A merchant is logged in already. Call logout before logging in again. SMPSumUpSDKErrorAccountIsLoggedIn = 22, /// Generel checkout error SMPSumUpSDKErrorCheckoutGeneral = 50, /// Another checkout process is currently in progress. SMPSumUpSDKErrorCheckoutInProgress = 51, /// The currency code specified in the checkout request does not match that of the current merchant. SMPSumUpSDKErrorCheckoutCurrencyCodeMismatch = 52, /// The foreign transaction ID specified in the checkout request has already been used. SMPSumUpSDKErrorDuplicateForeignID = 53, /// The access token is invalid. Login to get a valid access token. SMPSumUpSDKErrorInvalidAccessToken = 54, /// The amount entered contains invalid number of decimals. SMPSumUpSDKErrorInvalidAmountDecimals = 55, /// Tap to Pay on iPhone payment method is not available for the current merchant. This may be /// because the payment method is not available in their country. SMPSumUpSDKErrorTapToPayNotAvailable = 100, /// Tap to Pay on iPhone: activation is required. Call `presentTapToPayActivationFromViewController:animated:completionBlock:`. SMPSumUpSDKErrorTapToPayActivationNeeded = 101, /// Tap to Pay on iPhone: an unspecified error occurred SMPSumUpSDKErrorTapToPayInternalError = 102, /// Tap to Pay on iPhone requires an iPhone XS or later and does not work on iPads. SMPSumUpSDKErrorTapToPayMinHardwareNotMet = 103, /// Tap to Pay on iPhone requires a newer version of iOS; please check the documentation for the /// minimum supported version. SMPSumUpSDKErrorTapToPayiOSVersionTooOld = 104, /// Tap to Pay on iPhone has some other (unspecified) requirement(s) that are not met. SMPSumUpSDKErrorTapToPayRequirementsNotMet = 105,} NS_SWIFT_NAME(SumUpSDKError);
public enum SumUpSDKError : Int, @unchecked Sendable {
/// General error case general = 0
/// The merchant's account is not activated case activationNeeded = 1
/// General error with the merchant's account case accountGeneral = 20
/// The merchant is not logged in to their account case accountNotLoggedIn = 21
/// A merchant is logged in already. Call logout before logging in again. case accountIsLoggedIn = 22
/// Generel checkout error case checkoutGeneral = 50
/// Another checkout process is currently in progress. case checkoutInProgress = 51
/// The currency code specified in the checkout request does not match that of the current merchant. case checkoutCurrencyCodeMismatch = 52
/// The foreign transaction ID specified in the checkout request has already been used. case duplicateForeignID = 53
/// The access token is invalid. Login to get a valid access token. case invalidAccessToken = 54
/// The amount entered contains invalid number of decimals. case invalidAmountDecimals = 55
/// Tap to Pay on iPhone payment method is not available for the current merchant. This may be /// because the payment method is not available in their country. case tapToPayNotAvailable = 100
/// Tap to Pay on iPhone: activation is required. Call `presentTapToPayActivationFromViewController:animated:completionBlock:`. case tapToPayActivationNeeded = 101
/// Tap to Pay on iPhone: an unspecified error occurred case tapToPayInternalError = 102
/// Tap to Pay on iPhone requires an iPhone XS or later and does not work on iPads. case tapToPayMinHardwareNotMet = 103
/// Tap to Pay on iPhone requires a newer version of iOS; please check the documentation for the /// minimum supported version. case tapToPayiOSVersionTooOld = 104
/// Tap to Pay on iPhone has some other (unspecified) requirement(s) that are not met. case tapToPayRequirementsNotMet = 105}
Handling Payment Checkout
Section titled “Handling Payment Checkout”Detailed information on the payment checkout.
Note on Tipping
Section titled “Note on Tipping”There are three modes for tipping:
No tipping. Leave
tipAmount
set to nil when creating theSMPCheckoutRequest
object.Programmatic tipping via the
tipAmount
property. Ask the user in your own UI for an appropriate tip amount and then set thetipAmount
property onSMPCheckoutRequest
. This will be added to the total amount, but will be displayed to the user separately during checkout.Tip on Card Reader. TCR prompts the customer directly on the card reader's display for a tip amount, rather than prompting for a tip amount on the iPhone or iPad display.
Definitions
Section titled “Definitions”You have an option to add the paymentMethod
to checkout request, or skip it and let it default to Card Reader payment, as shown in the examples below. You can also familiarize yourself with the payment properties before moving on to implementation.
/** * Creates a new checkout request. * * Be careful when creating the NSDecimalNumber to not falsely use the NSNumber class creator methods. * * @param totalAmount The total amount to be charged to a customer. Cannot be nil. * @param title An optional title to be displayed in the merchant's history and on customer receipts. * @param currencyCode Currency Code in which the total should be charged (ISO 4217 code, see SMPCurrencyCode). Cannot be nil, has to match the currency of the merchant logged in. Use [[[SMPSumUpSDK currentMerchant] currencyCode] and ensure its length is not 0. * * @return A new request object or nil if totalAmount or currencyCode are nil. */+ (SMPCheckoutRequest *)requestWithTotal:(NSDecimalNumber *)totalAmount title:(nullable NSString *)title currencyCode:(NSString *)currencyCode paymentMethod:(SMPPaymentMethod)paymentMethod;
/** * Creates a new checkout request using a card reader as the method of payment. * * Be careful when creating the NSDecimalNumber to not falsely use the NSNumber class creator methods. * * @param totalAmount The total amount to be charged to a customer. Cannot be nil. * @param title An optional title to be displayed in the merchant's history and on customer receipts. * @param currencyCode Currency Code in which the total should be charged (ISO 4217 code, see SMPCurrencyCode). Cannot be nil, has to match the currency of the merchant logged in. Use [[[SMPSumUpSDK currentMerchant] currencyCode] and ensure its length is not 0. * * @return A new request object or nil if totalAmount or currencyCode are nil. */+ (SMPCheckoutRequest *)requestWithTotal:(NSDecimalNumber *)totalAmount title:(nullable NSString *)title currencyCode:(NSString *)currencyCode;
/** * The total amount to be charged to a customer. * * @note Will not be nil if the instance was created using either * requestWithTotal:title:currencyCode:paymentOptions: or * requestWithTotal:title:currencyCode: */@property (nonatomic, readonly, nullable) NSDecimalNumber *totalAmount;
/// A title to be displayed in the merchant's history and on customer receipts.@property (nonatomic, readonly, nullable) NSString *title;
/** * Currency code in which the total should be charged (ISO 4217 code, see SMPCurrencyCode). * * @note Will not be nil if the instance was created using either * requestWithTotal:title:currencyCode:paymentOptions: or * requestWithTotal:title:currencyCode: */@property (nonatomic, readonly, nullable) NSString *currencyCode;
/** * An (optional) ID to be associated with this transaction. * See https://docs.sumup.com/rest-api/#tag/Transactions * on how to retrieve a transaction using this ID. * This ID has to be unique in the scope of a SumUp merchant account and its sub-accounts. * It must not be longer than 128 characters and can only contain printable ASCII characters. */@property (nonatomic, copy, nullable) NSString *foreignTransactionID;
/** * An optional additional tip amount to be charged to a customer. * * @note This property will be ignored if the connected card reader supports the * Tip on Card Reader (TCR) feature and if it is enabled by setting * tipOnCardReaderIfAvailable to YES. * * Important: the customer may use a reader that does not support TCR. * You must handle this case yourself in order to avoid no tip from being prompted. * * To do this: * * Before calling SMPSumUpSDK checkoutWithRequest:fromViewController:completion:, * check SMPSumUpSDK.isTipOnCardReaderAvailable: * * - If NO, you should prompt the user for a tip amount yourself and set tipAmount * * - If YES, you may set tipOnCardReaderIfAvailable to YES. * Do not prompt the user for a tip amount or set tipAmount if you do this. * * Will be added to the totalAmount. Must be greater than zero if set. */@property (nonatomic, copy, nullable) NSDecimalNumber *tipAmount;
/** * Enables Tip on Card Reader (TCR), if the feature is available. * * @note TCR prompts the customer directly on the card reader's display for a tip amount, * rather than prompting for a tip amount on the iPhone or iPad display. * * Not all card readers support this feature. To find out if the feature is supported for the * last-used card reader, check SMPSumUpSDK.isTipOnCardReaderAvailable. * * Setting this property to YES when the feature is not available will do nothing. */@property (nonatomic) BOOL tipOnCardReaderIfAvailable;
/** * An optional count for the display of the number of sale items throughout the checkout process. * Default is zero which will hide the display of the item count. * This value is currently not reflected in the merchant's history * or the customer receipts. */@property (nonatomic) NSUInteger saleItemsCount;
/** * An optional flag to skip the confirmation screen in checkout. * If set, the checkout will be dismissed w/o user interaction. * Default is SMPSkipScreenOptionNone. */@property (nonatomic) SMPSkipScreenOptions skipScreenOptions;
/** * The method of payment to use during checkout; for example, a bluetooth-connected card reader, or Tap to Pay on iPhone. * * Defaults to `SMPPaymentMethodCardReader`. */@property (nonatomic) SMPPaymentMethod paymentMethod;
Implement Full Checkout
Section titled “Implement Full Checkout”In this step, we implement the checkout.
- Verify that Merchant is logged in and using a valid currency code.
- Define total amount to be charged. Please note that you need to pass an
NSDecimalNumber
as the total value. WhileNSDecimalNumber
is a subclass ofNSNumber
it is not advised to use the convenience method ofNSNumber
to create anNSDecimalNumber
. - Set up the request.
- Add a tip if selected (see the section about tipping).
- Check if the option to skip receipt is enabled, if so, execute it.
- Check for
foreignTransactionID
. - Execute the request with error handling and confirmation.
- Verify that the checkout started correctly.
fileprivate func requestCheckout() { // ensure that we have a valid merchant guard let merchantCurrencyCode = SumUpSDK.currentMerchant?.currencyCode else { showResult(string: "not logged in") return }
guard let totalText = textFieldTotal?.text else { return }
// create an NSDecimalNumber from the totalText // please be aware to not use NSDecimalNumber initializers inherited from NSNumber let total = NSDecimalNumber(string: totalText) guard total != NSDecimalNumber.zero else { return }
// setup payment request let request = CheckoutRequest(total: total, title: textFieldTitle?.text, currencyCode: merchantCurrencyCode)
// add tip if selected if let selectedTip = segmentedControlTipping?.selectedSegmentIndex, selectedTip > 0, tipAmounts.indices ~= selectedTip { let tipAmount = tipAmounts[selectedTip] request.tipAmount = tipAmount }
// set screenOptions to skip if switch is set to on if let skip = switchSkipReceiptScreen?.isOn, skip { request.skipScreenOptions = .success }
// the foreignTransactionID is an **optional** parameter and can be used // to retrieve a transaction from SumUp's API. See -[SMPCheckoutRequest foreignTransactionID] request.foreignTransactionID = "your-unique-identifier-\(ProcessInfo.processInfo.globallyUniqueString)"
SumUpSDK.checkout(with: request, from: self) { [weak self] (result: CheckoutResult?, error: Error?) in if let safeError = error as NSError? { print("error during checkout: \(safeError)")
if (safeError.domain == SumUpSDKErrorDomain) && (safeError.code == SumUpSDKError.accountNotLoggedIn.rawValue) { self?.showResult(string: "not logged in") } else { self?.showResult(string: "general error") }
return }
guard let safeResult = result else { print("no error and no result should not happen") return }
print("result_transaction==\(String(describing: safeResult.transactionCode))")
if safeResult.success { print("success") var message = "Thank you - \(String(describing: safeResult.transactionCode))"
if let info = safeResult.additionalInfo, let tipAmount = info["tip_amount"] as? Double, tipAmount > 0, let currencyCode = info["currency"] as? String { message = message.appending("\ntip: \(tipAmount) \(currencyCode)") }
self?.showResult(string: message) } else { print("cancelled: no error, no success") self?.showResult(string: "No charge (cancelled)") } }
// after the checkout is initiated we expect a checkout to be in progress if !SumUpSDK.checkoutInProgress { // something went wrong: checkout was not started showResult(string: "failed to start checkout") }}
- (IBAction)buttonChargeTapped:(id)sender { // check total and currency code NSString *total = [[self textFieldTotal] text]; NSString *currencyCode = [[SMPSumUpSDK currentMerchant] currencyCode];
if (([total doubleValue] <= 0) || ![currencyCode length]) { [self showResultsString:@"not logged in"]; return; }
SMPCheckoutRequest *request;
request = [SMPCheckoutRequest requestWithTotal:[NSDecimalNumber decimalNumberWithString:total] title:self.textFieldTitle.text currencyCode:currencyCode];
// Tip is optional. Default is no tip. NSInteger selectedTipSegment = self.segmentedControlTipping.selectedSegmentIndex;
if (selectedTipSegment > 0) { [request setTipAmount:[[self tipAmounts] objectAtIndex:selectedTipSegment]]; }
// Skip receipt screen if toggle is set to on if (self.switchSkipReceiptScreen.isOn) { [request setSkipScreenOptions:SMPSkipScreenOptionSuccess]; }
// the foreignTransactionID is an optional parameter and can be used // to retrieve a transaction from SumUp's API. See -[SMPCheckoutRequest foreignTransactionID] [request setForeignTransactionID:[NSString stringWithFormat:@"your-unique-identifier-%@", [[NSProcessInfo processInfo] globallyUniqueString]]];
[SMPSumUpSDK checkoutWithRequest:request fromViewController:self completion:^(SMPCheckoutResult *result, NSError *error) { if ([error.domain isEqualToString:SMPSumUpSDKErrorDomain] && (error.code == SMPSumUpSDKErrorAccountNotLoggedIn)) { [self showResultsString:@"not logged in"]; return; }
NSMutableArray<NSString *> *strings = [NSMutableArray array]; [strings addObject:[NSString stringWithFormat:@"%@ - %@", result.success ? @"Thank you" : @"No charge", result.transactionCode ? : @"no transaction"]];
if (result.transactionCode) { // get optional tip amount NSNumber *tipAmount = result.additionalInfo[@"tip_amount"];
// display tip only if greater than zero if ([tipAmount isKindOfClass:[NSNumber class]] && (tipAmount.doubleValue > 0)) { [strings addObject:[NSString stringWithFormat:@"%@ (incl. %@ tip) %@", result.additionalInfo[@"amount"], tipAmount, result.additionalInfo[@"currency"]]]; } else { [strings addObject:[NSString stringWithFormat:@"%@ %@ (no tip)", result.additionalInfo[@"amount"], result.additionalInfo[@"currency"]]]; } }
[self showResultsString:[strings componentsJoinedByString:@"\n"]];
if (result.success) { [self.textFieldTitle setText:nil]; } }];
// something went wrong checkout was not started if (![SMPSumUpSDK checkoutInProgress]) { [self showResultsString:@"failed to start checkout"]; }}
Credit/debit selection (processAs property)
Section titled “Credit/debit selection (processAs property)”Some countries require the customer to select Credit or Debit at the beginning of the checkout. This is because a payment card may contain multiple applications linked with different accounts, making it necessary for the customer to specify which application should be used to process the transaction.
For countries that do not require credit/debit selection, you can set the processAs
property of SMPCheckoutRequest
to SMPProcessAsNotSet
.
To tell if the current country requires processAs
to be set to a value other than SMPProcessAsNotSet
, check SMPSumUpSDK.isProcessAsRequired
.
If needed, your app should set the processAs
property of SMPCheckoutRequest
to SMPProcessAsCredit
or SMPProcessAsDebit
after showing its own UI that prompts the customer to select Credit or Debit.
SDK 6.0 and earlier presented two screens during the checkout that prompted the user to select Credit or Debit, and if Credit, to also choose the number of installments. This functionality is now deprecated. However, it is still available if you need more time to migrate your app to use the above programmatic method. To keep the old behavior, set processAs
to SMPProcessAsPromptUser
.
Installments
Section titled “Installments”When SMPProcessAsCredit
is used, you should obtain the number of installments from the customer using your own UI. Assign the positive, non-zero value to numberOfInstallments
on SMPCheckoutRequest
.
Implementing Tap-to-Pay
Section titled “Implementing Tap-to-Pay”With Tap to Pay on iPhone merchants can accept contactless card payments on their iPhone without needing a card reader.
To add Tap to Pay on iPhone to your app:
- Request the Tap to Pay on iPhone entitlement from Apple, receive approval, and then add the
com.apple.developer.proximity-reader.payment.acceptance
entitlement to your app. Setting up the entitlement. - This feature requires an iPhone XS or later, running iOS 16.4 (iOS 16.7 starting July 8th) or later (ideally 17.5 or later.) The feature does not work on iPad.
- For debugging and testing you will need to be logged into an iPhone with a non-Sandbox Apple ID. Using a Sandbox Apple ID requires both Apple and SumUp implementations to connect to their respective non-production (test) backends, which the SDK does not support.
- During testing use a SumUp test account, to avoid transactions going to the acquirer and transferring real money.
In your code:
- Make a call to check feature availability: is the Tap to Pay on iPhone payment method available for the current merchant?
- Trigger activation if needed. Activation sets up the iPhone to receive payments, shows the merchant how to use the feature, and links the SumUp account and Apple ID.
- Start the checkout.
Check feature availability
Section titled “Check feature availability”- Call
checkTapToPayAvailability
onSMPSumUpSDK
to check the availability of the Tap to Pay on iPhone payment method. This call, which requires the SDK to be in a logged-in state, may internally perform one or more network calls. - If the feature is not available, your app could, as an example, hide or disable a button or menu item representing the Tap to Pay on iPhone payment method.
- The feature is generally available when the following criteria are fulfilled:
- the iPhone model and iOS version requirements are met
- the user logs in with a SumUp account registered in one of the countries where SumUp supports Tap to Pay on iPhone (temporarily with exception of Brazil)
Perform activation if needed
Section titled “Perform activation if needed”- Activation must be completed before the first transaction can be performed. Activation means:
- the merchant links their Apple ID with their SumUp account
- the iPhone is prepared, which can take 45 seconds or longer
- This needs to be done once per merchant account, per device.
- In addition to determining feature availability,
checkTapToPayAvailability
also indicates whether Tap to Pay on iPhone has been activated yet for the current merchant. - If it has not yet been activated then you should trigger activation by calling
presentTapToPayActivation
at a convenient time. Calling it more than once will still show the user education screens each time. Independently, the activation from the initial setup will remain valid.
Definitions
Section titled “Definitions”These methods handle Tap to Pay processing. Note that the SDK supports both Completion Block and async implementation.
/** * Checks whether the Tap to Pay on iPhone payment method is available for the current merchant and whether or * not it requires activation to be performed via a call to * `presentTapToPayActivationFromViewController:animated:completionBlock:`. * * For the merchant to be able to use this payment method the following must be true: * * - The feature must be available in the merchant's country * * - It must be activated. This is where the merchant's Apple ID is linked with their SumUp account and the * iPhone is prepared to work as a card reader. As this can take a minute or so the first time, the * merchant is shown a UI that introduces them to the feature as it initializes in the background. * * The merchant must be logged in before you call this method. * * @param availability YES if the feature is available for the current merchant and it's OK to start activation. * @param isActivated YES if activation has already been done for this device and merchant account */open class func checkTapToPayAvailability(completion block: @escaping (Bool, Bool, (any Error)?) -> Void)
/** * Checks whether the Tap to Pay on iPhone payment method is available for the current merchant and whether or * not it requires activation to be performed via a call to * `presentTapToPayActivationFromViewController:animated:completionBlock:`. * * For the merchant to be able to use this payment method the following must be true: * * - The feature must be available in the merchant's country * * - It must be activated. This is where the merchant's Apple ID is linked with their SumUp account and the * iPhone is prepared to work as a card reader. As this can take a minute or so the first time, the * merchant is shown a UI that introduces them to the feature as it initializes in the background. * * The merchant must be logged in before you call this method. * * @param availability YES if the feature is available for the current merchant and it's OK to start activation. * @param isActivated YES if activation has already been done for this device and merchant account */open class func checkTapToPayAvailability() async throws -> (Bool, Bool)
/** * Performs activation for Tap to Pay on iPhone. This prepares the device, introduces the merchant to the * feature and links their Apple ID to their SumUp account (which will require confirmation from the merchant.) * * Call `checkTapToPayAvailability:` before calling this method to find out if this payment method is available * and if activation is needed. * * The merchant must be logged in before you call this method. * * Tap to Pay on iPhone requirements: * * - The hosting app must have the `com.apple.developer.proximity-reader.payment.acceptance` * entitlement. * * - The merchant must have an iPhone XS or later with iOS 16.4 or later (iOS 17 or later recommended.) * The feature does not work with iPads. * * @param fromViewController The UIViewController instance from which the UI should be presented modally. * @param animated Pass YES to animate the transition. * @param block The completion block is called after the view controller has been dismissed. */open class func presentTapToPayActivation(from fromViewController: UIViewController, animated: Bool, completionBlock block: SMPCompletionBlock? = nil)
/** * Performs activation for Tap to Pay on iPhone. This prepares the device, introduces the merchant to the * feature and links their Apple ID to their SumUp account (which will require confirmation from the merchant.) * * Call `checkTapToPayAvailability:` before calling this method to find out if this payment method is available * and if activation is needed. * * The merchant must be logged in before you call this method. * * Tap to Pay on iPhone requirements: * * - The hosting app must have the `com.apple.developer.proximity-reader.payment.acceptance` * entitlement. * * - The merchant must have an iPhone XS or later with iOS 16.4 or later (iOS 17 or later recommended.) * The feature does not work with iPads. * * @param fromViewController The UIViewController instance from which the UI should be presented modally. * @param animated Pass YES to animate the transition. * @param block The completion block is called after the view controller has been dismissed. */open class func presentTapToPayActivation(from fromViewController: UIViewController, animated: Bool) async throws -> Bool
/** * Checks whether the Tap to Pay on iPhone payment method is available for the current merchant and whether or * not it requires activation to be performed via a call to * `presentTapToPayActivationFromViewController:animated:completionBlock:`. * * For the merchant to be able to use this payment method the following must be true: * * - The feature must be available in the merchant's country * * - It must be activated. This is where the merchant's Apple ID is linked with their SumUp account and the * iPhone is prepared to work as a card reader. As this can take a minute or so the first time, the * merchant is shown a UI that introduces them to the feature as it initializes in the background. * * The merchant must be logged in before you call this method. * * @param availability YES if the feature is available for the current merchant and it's OK to start activation. * @param isActivated YES if activation has already been done for this device and merchant account */+ (void)checkTapToPayAvailability:(void (^ _Nonnull)(BOOL isAvailable, BOOL isActivated, NSError * _Nullable error))block NS_SWIFT_NAME(checkTapToPayAvailability(completion:));
/** * Performs activation for Tap to Pay on iPhone. This prepares the device, introduces the merchant to the * feature and links their Apple ID to their SumUp account (which will require confirmation from the merchant.) * * Call `checkTapToPayAvailability:` before calling this method to find out if this payment method is available * and if activation is needed. *ń * The merchant must be logged in before you call this method. * * Tap to Pay on iPhone requirements: * * - The hosting app must have the `com.apple.developer.proximity-reader.payment.acceptance` * entitlement. * * - The merchant must have an iPhone XS or later with iOS 16.4 or later (iOS 17 or later recommended.) * The feature does not work with iPads. * * @param fromViewController The UIViewController instance from which the UI should be presented modally. * @param animated Pass YES to animate the transition. * @param block The completion block is called after the view controller has been dismissed. */+ (void)presentTapToPayActivationFromViewController:(UIViewController *)fromViewController animated:(BOOL)animated completionBlock:(nullable SMPCompletionBlock)block;
Implementation
Section titled “Implementation”SumUpSDK.checkTapToPayAvailability { isAvailable, isActivated, error in
if let error { // An error occurred return }
if !isAvailable { // Tap to Pay on iPhone is not available for the merchant return }
if !isActivated { // Tap to Pay on iPhone needs activation - call presentTapToPayActivation return }
// The app is ready to take Tap to Pay on iPhone payments!}
[SMPSumUpSDK checkTapToPayAvailability:^(BOOL isAvailable, BOOL isActivated, NSError * _Nullable error) { if (error == nil) { if (!isAvailable) { // Tap to Pay on iPhone is not available for the merchant return; }
if (!isActivated) { // Tap to Pay on iPhone needs activation - call presentTapToPayActivation return; }
// The app is ready to take Tap to Pay on iPhone payments!
} else { // An error occurred }}];
Testing your Integration
Section titled “Testing your Integration”In your debug setup you can call +[SMPSumUpSDK testSDKIntegration]
or SumUpSDK.testIntegration()
in Swift. It will run various checks and print its findings to the console. Please do not call it in your Release build.
SDK Structure
Section titled “SDK Structure”The SDK uses Objective C header files, but XCode can also display its public types as Swift. The table below outlines the interfaces in the SDK and their purpose.
Header (Swift alias) | Purpose |
---|---|
SMPSumUpSDK.h (SumUpSDK) | Includes methods and properties for handling authentication, initial SDK setup, presenting checkout view, and testing your integration. Bundles all other headers and serves as the main SDK interface. |
SMPCheckoutRequest.h (CheckoutRequest) | Includes methods and properties handling checkout requests, such as amounts, currencies, and payment methods |
SMPCheckoutResult.h (CheckoutResult) | Handles checkout result structure, including status and transaction code |
SMPCurrencyCodes.h | Defines available currency codes |
SMPMerchant.h (Merchant) | Describes a Merchant, including Merchant Code (identifier) and currency used by merchant |
SMPSkipScreenOptions.h (SkipScreenOptions) | Describes options allowing to skip transaction confirmation screen |
SumUpSDK.h | Declares project version |
Sample App
Section titled “Sample App”SumUp provides a sample app which implements main SDK components in a sample App Delegate and View Controller. Check the examples below for highlights provided in both Swift and Objective C. Clone the provided repository and check the SampleApp directory to use it.
Known Issues
Section titled “Known Issues”- In Tap-to-Pay solutions, if entitlements are not correctly set up in your app,
presentTapToPayActivation
may show an error Alert withFailed to show Terms of Service
. - Businesses using SumUp sub-accounts must first activate the feature on their main account before using it on devices logged in with sub-accounts, otherwise an error message will appear during activation for the sub-account user.
- Bluetooth permissions will be requested even if the merchant does not plan to use any of the SumUp Bluetooth card readers. This will be fixed in an upcoming release 6.1.
- Distributing XCFrameworks with the latest Carthage version (0.35.0) is not yet available. There is an open issue (#2799) to solve this.
Community
Section titled “Community”Got questions or found a bug? Get in contact with our integration team by sending an email to integration@sumup.com.
Out of Scope
Section titled “Out of Scope”The following functions are handled by the SumUp APIs:
What's Next?
Section titled “What's Next?”Check other resources we have, such as: