# iOS SDK

import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components';
import Image from '@components/content/Image.astro';


SumUp provides a [native iOS SDK](https://github.com/sumup/sumup-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](https://github.com/sumup/sumup-ios-sdk/tree/master/SampleApp/SumUpSDKSampleApp), which you can run out-of-the-box to immediately test the implementation in practice.

## Prerequisites

* Registered for a merchant account via SumUp's [country websites](https://sumup.com/) or use a [sandbox merchant account](/terminal-payments/quickstart/#sandbox-merchant-account).
* Received SumUp card terminal: Solo Lite, Solo, Air, 3G, PIN+.
* Requested an Affiliate (Access) Key in the [Developer Settings](https://me.sumup.com/settings/developer) of the SumUp Dashboard.
* Deployment Target iOS 16.0 or later.
* Recommended to use on Xcode 26.2 and iOS SDK 16 or later.
* iPhone or iPad.
* If your device is managed by an organization, make sure app installation is permitted.

## Sandbox Merchant Account

Use the shared [Quickstart sandbox setup](/terminal-payments/quickstart/#sandbox-merchant-account) to create and test with a sandbox merchant account before integrating the iOS SDK.

### Compatibility

* 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's `Info.plist` or the "General" tab in Xcode's Target Editor.

### Match Affiliate Key to App Bundle ID

iOS SDK uses the Affiliate Key from your merchant account to authenticate your app.

1. Log in to SumUp with your merchant account and open the [Developer Settings](https://me.sumup.com/settings/developer) page.
2. Create an Affiliate Key if you don't have one yet.
3. 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

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:

```txt
NSLocationWhenInUseUsageDescription
NSBluetoothAlwaysUsageDescription
NSBluetoothPeripheralUsageDescription (unless your deployment target is at least iOS 13)
```

Check the [Sample App property list](https://github.com/sumup/sumup-ios-sdk/tree/master/SampleApp/SumUpSDKSampleApp/SumUpSDKSampleApp-Info.plist) for reference.

<Aside>
You can provide localization by providing a localized [InfoPlist.strings](https://github.com/sumup/sumup-ios-sdk/tree/master/SampleApp/SumUpSDKSampleApp/en.lproj/InfoPlist.strings) file.

```txt
/* Localized versions of Info.plist keys */

"NSLocationWhenInUseUsageDescription" = "To provide a secure payment service, we need to know your location.\nWithout location information, you cannot accept payments using this app.";

"NSBluetoothPeripheralUsageDescription" = "The app needs to connect to Bluetooth peripherals to detect the SumUp Card Terminal correctly. Please confirm with \"OK\" as you cannot use your card reader otherwise.";

"NSBluetoothAlwaysUsageDescription" = "The app needs to connect to Bluetooth peripherals to detect the SumUp Card Terminal correctly. Please confirm with \"OK\" as you cannot use your card reader otherwise.";
```

For further information, see the iOS Developer Library on [location usage on iOS 8 and later](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW26), [Bluetooth peripheral usage](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW20).

</Aside>

### Location Services Requirement

<Aside type="danger">
**Mandatory Location Access**

For security, compliance, and fraud prevention, the SumUp SDK **requires active location services** to process any transaction.

If a user denies location permissions (e.g., selecting "Never" in the iOS settings), the SDK will be unable to validate the payment environment. This often results in a generic and misleading **"Server Error"** message on the UI or a `SMPSumUpSDKErrorCheckoutGeneral` (Error Code 50) in the callback.

**Integration Best Practices:**
* **Explicit Description:** Ensure your `NSLocationWhenInUseUsageDescription` clearly states that location is mandatory for processing card payments.
* **Pre-flight Check:** We recommend checking the `CLLocationManager.authorizationStatus()` before calling the checkout method. If access is denied, guide the user to the system settings to enable it.
* **User Guidance:** If you receive a General Error (50), verify the location permissions before retrying the transaction.
</Aside>

## Fast-Track Implementation

If you want to dive straight into implementation, carry out the following steps:

### Card Reader Flow

1. [Install the SDK](#adding-sdk-framework-to-project).
2. [Import the SDK into your project file](#importing-sdk).
3. [Initialize the SDK with an Affiliate Key](#initialization).
4. [Log the user in](#logging-the-user-in).
5. [Prepare user's device for checkout](#prepare-for-checkout).
6. [Allow the user to select a card reader](#present-checkout-preferences).
7. Finally, [implement the full checkout](#implement-full-checkout).

### 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](https://developer.apple.com/design/human-interface-guidelines/tap-to-pay-on-iphone) to save time when Apple reviews your app.
* Also consider [Apple’s marketing guidelines](https://developer.apple.com/tap-to-pay/marketing-guidelines/) and use standard assets where possible.

1. [Install the SDK](#adding-sdk-framework-to-project).
2. [Import the SDK into your project file](#importing-sdk).
3. [Initialize the SDK with an Affiliate Key](#initialization).
4. [Log the user in](#logging-the-user-in).
5. Follow steps under [Implementing Tap-to-Pay](#implementing-tap-to-pay).

## Integrating iOS SDK

### 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:


<Tabs>

<TabItem label="Swift Package Manager">

The latest Swift Package Manager version added support to [distribute binary frameworks as Swift Packages](https://developer.apple.com/documentation/swift_packages/distributing_binary_frameworks_as_swift_packages).

Follow this workaround to manage SumUp iOS SDK versions via Swift PM in those cases:

<Steps>
1. Add the package dependency to the repository `https://github.com/sumup/sumup-ios-sdk` (*File > Swift Packages > Add Package Dependency...*) with the version `Up to Next Major: 7.0.0`
2. Leave the checkbox unchecked for the SumUpSDK at the integration popup (*Add Package to ...:*)
3. 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.
4. Make sure the [required Info.plist keys](#add-property-list-keys-to-project) are present.
</Steps>

To learn more about adding Swift Package dependencies, please refer to the [official documentation](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app).

</TabItem>

<TabItem label="Use XCFramework directly">

<Steps>
1. Drag and drop the `SumUpSDK.xcframework` to your Xcode project's "Frameworks,
Libraries, and Embedded Content" on the project General Settings tab.
2. Make sure the [required Info.plist keys](#add-property-list-keys-to-project) are present.
</Steps>

</TabItem>

<TabItem label="Cocoapods">

```ruby
target '<Your Target Name>' do
    pod 'SumUpSDK', '~> 7.0.0'
end
```

</TabItem>

<TabItem label="Carthage">

Distributing XCFrameworks with the latest Carthage version (0.40.0) is not yet available.
There is an open issue ([#2799](https://github.com/Carthage/Carthage/issues/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:

<Steps>
1. Add the following line to your `Cartfile`:
    ```txt
    github "sumup/sumup-ios-sdk"
    ```
2. Run `carthage update sumup-ios-sdk`
3. Drag and drop the `Carthage/Build/iOS/SumUpSDK.xcframework` to your Xcode project's "Frameworks,
Libraries, and Embedded Content" on the General settings tab.
4. Make sure the [required Info.plist keys](#add-property-list-keys-to-project) are present.
</Steps>

To learn more about setting up your project for Carthage, please refer to the [official documentation](https://github.com/Carthage/Carthage#if-youre-building-for-ios-tvos-or-watchos).

</TabItem>
</Tabs>

### 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.

### 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.

<Image alt="Login screen" src="/img/guides/use_location.png" width="40%" />

<Tabs>

<TabItem label="Swift">

```swift
import SumUpSDK
import UIKit

@UIApplicationMain
class 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
    }

}
```

</TabItem>

<TabItem label="Objective-C">

```objc
#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;
}
```

</TabItem>

</Tabs>

### Authentication - Component Definitions

SumUp iOS SDK supports either the OAuth 2.0 Authorization Code Flow login with Access Token or a modally presented login from a View Controller (as you can see implemented in the Sample App). We strongly recommend the OAuth 2.0 approach for new integrations, due to support for MFA, better overall security, and possible deprecation of the View Controller in the future.

<Tabs>

<TabItem label="Login Access Token (OAuth 2.0)">
```objc
/**
 *  Logs in a merchant with an access token acquired via /tools/authorization/oauth/.
 *  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;
```
</TabItem>

<TabItem label="Login View Controller">

```objc
/**
 *  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;
```


</TabItem>

<TabItem label="Logout">
```objc
/**
 *  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;
```
</TabItem>

</Tabs>

### Implementing Authentication with OAuth 2.0

SumUp can issue Access Tokens in accordance with the OAuth 2.0 Authorization Code Flow, which is our recommended authorization approach (Client Credentials Flow is not supported by this SDK). See the [Authorization Documentation](/tools/authorization/oauth/#authorization-code-flow) for more details.

### Implementing Authentication with View Controller

If you want to use the View Controller embedded in the SDK, this section explains how to do it. Please note that OAuth 2.0 Authorization Code Flow is supported and recommended, and the View Controller may become deprecated in the future.

#### Logging the User In

Following app authentication, a registered SumUp merchant account needs to be logged in. Present a login screen from your UIViewController:

<Image alt="Login screen" src="/img/guides/login.png" width="40%" />

<Tabs>

<TabItem label="Swift">

```swift
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()
    }
}
```

</TabItem>

<TabItem label="Objective C">

```objc
- (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];
                                }];
}
```

</TabItem>

</Tabs>

#### Logging the User Out

Similarly, you can log the user out.

<Tabs>

<TabItem label="Swift">

```swift
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()
    }
}
```

</TabItem>

<TabItem label="Objective C">

```objc
- (IBAction)buttonLogoutTapped:(id)sender {
    [SMPSumUpSDK logoutWithCompletionBlock:^(BOOL success, NSError *error) {
        [self updateButtonState];
    }];
}
```

</TabItem>

</Tabs>

### 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.

<Tabs>

<TabItem label="Prepare for Incoming Checkout">
```objc
/**
 *  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;
```


</TabItem>

<TabItem label="Present Checkout Preferences">
```objc
/**
 *  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;
```


</TabItem>

<TabItem label="Present Checkout View">
```objc
/**
 *  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;
```


</TabItem>

</Tabs>

### Adding Payment Checkout View

In this step, we implement the payment checkout.

#### Prepare for Checkout

<Tabs>

<TabItem label="Objective C">
```objc
- (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;
}
```

</TabItem>

<TabItem label="Swift">

```swift
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
    }
}
```

</TabItem>

</Tabs>

#### 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.

<Image alt="Search Bluetooth" src="/img/guides/find_bluetooth.png" width="40%" />

<Image alt="Terminal selection" src="/img/guides/Multiple_terminals.png" width="40%" />

<Tabs>

<TabItem label="Swift">

```swift
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)
    }
}
```

</TabItem>

<TabItem label="Objective C">

```objc
- (IBAction)buttonOpenPreferencesTapped:(id)sender {
    [SMPSumUpSDK presentCheckoutPreferencesFromViewController:self
                                                     animated:YES
                                                   completion:^(BOOL success, NSError *_Nullable error) {
                                                       if (!success || error) {
                                                           [self showResultsString:@"not logged in"];
                                                       }
                                                   }];
}
```

</TabItem>

</Tabs>

#### Present Checkout View

Prepare a checkout request that encapsulates the information regarding the transaction.

<Image alt="Checkout screen" src="/img/guides/checkout.png" width="40%" />

<Tabs>

<TabItem label="Swift">

```swift
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
    }
```

</TabItem>

<TabItem label="Objective C">

```objc
[SMPSumUpSDK checkoutWithRequest:request fromViewController:self completion:^(SMPCheckoutResult *result, NSError *error) {
    if ([error.domain isEqualToString:SMPSumUpSDKErrorDomain] && (error.code == SMPSumUpSDKErrorAccountNotLoggedIn)) {
        [self showResultsString:@"not logged in"];
        return;
    }
```

</TabItem>

<TabItem label="Error codes Objective C">

```objc
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,
    /// General 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,
    /// The processAs property of CheckoutRequest is not valid
    SMPSumUpSDKErrorInvalidProcessAs               = 56,
    /// The numberOfInstallments property of CheckoutRequest is not valid
    SMPSumUpSDKErrorInvalidNumberOfInstallments    = 57,
    /// Reader wake error during Prepare for Checkout process.
    /// Includes when a reader has never been paired.
    SMPSumUpSDKErrorPrepareCheckoutReaderWakeFailed = 60,
    /// 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);
```

</TabItem>

<TabItem label="Error codes Swift">

```swift
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

    /// General 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

    /// The processAs property of CheckoutRequest is not valid
    case invalidProcessAs = 56

    /// The numberOfInstallments property of CheckoutRequest is not valid
    case invalidNumberOfInstallments = 57

    /// Reader wake error during Prepare for Checkout process.
    /// Includes when a reader has never been paired.
    case prepareCheckoutReaderWakeFailed = 60

    /// 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
}
```


</TabItem>

</Tabs>


### Handling Payment Checkout

Detailed information on the payment checkout.

#### Note on Tipping

There are three modes for tipping:

<Steps>

1. No tipping. Leave `tipAmount` set to nil when creating the `SMPCheckoutRequest` object.

2. Programmatic tipping via the `tipAmount` property. Ask the user in your own UI for an appropriate tip amount and then set the `tipAmount` property on `SMPCheckoutRequest`. This will be added to the total amount, but will be displayed to the user separately during checkout.

3. 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.
    <Aside type="caution">
    Not all card readers support this feature. To find out if the feature is supported for the last-used card reader, you should always check `SMPSumUpSDK.isTipOnCardReaderAvailable`. 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 on `SMPCheckoutRequest`
    - If YES, you may set `tipOnCardReaderIfAvailable` on `SMPCheckoutRequest` to YES. Do not prompt the user for a tip amount or set tipAmount if you do this.
    </Aside>

</Steps>

#### 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.

<Tabs>

<TabItem label="Checkout Request with any Payment Method">

```objc
/**
 *  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;
```


</TabItem>

<TabItem label="Checkout Request with Card Reader Only">

```objc
/**
 *  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;
```


</TabItem>

<TabItem label="Payment Properties">
```objc
/**
 *  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;
```


</TabItem>

</Tabs>

#### Implement Full Checkout

In this step, we implement the checkout.

1. Verify that Merchant is logged in and using a valid currency code.
2. Define total amount to be charged. Please note that you need to pass an `NSDecimalNumber` as the total value. While `NSDecimalNumber` is a subclass of `NSNumber` it is not advised to use the convenience method of `NSNumber` to create an `NSDecimalNumber`.
3. Set up the request.
4. Add a tip if selected ([see the section about tipping](#note-on-tipping)).
5. Check if the option to skip receipt is enabled, if so, execute it.
6. Check for `foreignTransactionID`.
7. Execute the request with error handling and confirmation.
8. Verify that the checkout started correctly.


<Tabs>

<TabItem label="Swift">

```swift
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")
        }
}
```

</TabItem>

<TabItem label="Objective C">

```objc
- (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"];
    }
}
```

</TabItem>

</Tabs>


### 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`.

<Aside type="caution">
* For countries that require credit/debit selection, using `SMPProcessAsNotSet` will cause the transaction to fail.
* Not all countries support `processAs`. Setting `processAs` for unsupported countries may cause the transaction to fail. Currently supported countries are: Brazil, Chile and Colombia.
</Aside>

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 behaviour, set `processAs` to `SMPProcessAsPromptUser`.

#### 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

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](https://developer.apple.com/documentation/proximityreader/setting-up-the-entitlement-for-tap-to-pay-on-iphone?language=objc).
* 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 sandbox merchant 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

* Call `checkTapToPayAvailability` on `SMPSumUpSDK` 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

* 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

These methods handle Tap to Pay processing. Note that the SDK supports both Completion Block and async implementation.

<Tabs>

<TabItem label="Swift">

```swift
/**
 *  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
```


</TabItem>

<TabItem label="Objective C">

```objc
/**
 *  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;
```


</TabItem>

</Tabs>

#### Implementation

<Tabs>

<TabItem label="Swift">

```swift
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!
}
```


</TabItem>

<TabItem label="Objective C">

```objc
[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
    }
}];
```


</TabItem>

</Tabs>


### 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

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

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](https://github.com/sumup/sumup-ios-sdk) and check the SampleApp directory to use it.


## Known Issues

* In Tap-to-Pay solutions, if entitlements are not correctly set up in your app, `presentTapToPayActivation` may show an error Alert with `Failed 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](https://github.com/Carthage/Carthage/issues/2799)) to solve this.

## 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

The following functions are handled by the [SumUp APIs](/api/):
* [Refunds](/api/transactions/refund/)
* [Transaction history](/api/transactions/list/)
* [Receipts](/api/receipts/get/)
* [Account management](/api/merchant/)

## What's Next?

Check other resources we have, such as:

* [SumUp Android SDK](https://github.com/sumup/sumup-android-sdk)
* Our [Postman REST API collection](https://github.com/sumup/sumup-postman)