---
metadata:
  - name: generator
    content: Diplodoc Platform v5.54.5
alternate:
  - https://pay.yandex.ru/docs/en/custom/ios-sdk.md
  - href: en/custom/ios-sdk.md
    type: text/markdown
    title: Markdown version
  - href: ../llms.txt
    type: text/markdown
    title: llms.txt
---
> **Documentation Index:** Fetch the complete configuration index at https://pay.yandex.ru/docs/en/llms.txt

# iOS SDK guide

## Requirements for connecting {#requirements}

Required iOS SDK version: 12.0.

Yandex Pay SDK uses YandexLoginSDK. Set it up by following the [instructions](https://yandex.ru/dev/mobileauthsdk/doc/sdk/concepts/ios/2.0.0/sdk-ios-install.html).

Once you configure YandexLoginSDK, make sure that your app has access to Yandex Pay added in Yandex OAuth. To do this, go to the app editing page and under **Which data do you need?**, select `Yandex Pay` → `Pay by Yandex Pay`.

## Yandex Pay SDK installation {#install-sdk}

<!-- source: en/_includes/ios-sdk-installation.md -->
{% list tabs %}

- CocoaPods

   1. Add a `pod 'YandexPaySDK/Static'` or `pod 'YandexPaySDK/Dynamic'` dependency to the `Podfile` for your target.
   1. If there's no `Podfile` in your project, initialize it according to the `CocoaPods` instructions and repeat the previous step.
   1. Set up the dependencies by executing `pod install --repo-update`.
   1. Open the generated `.xcworkspace` and assemble the project.

- Swift Package Manager (SPM)

   Add to Package.swift:

   ```swift
   ... = Package(
     ...
     targets: [
         .binaryTarget(name: "YandexPaySDK",
                       url: "https://yandexpay-ios-sdk.s3.yandex.net/1.2.1/YandexPaySDK_121222_7524285.xcframework.zip",
                       checksum: "714698b6e5ff407a76304ce8cf7801fcfc143e432157a1c6624abb04c51bfc2e"),
     ]
     ...
   )
   ```

   Only a dynamic library with all the necessary dependencies is currently supported.
   The source code can't be shared because of PCI DSS restrictions.

{% endlist %}
<!-- endsource: en/_includes/ios-sdk-installation.md -->

## Yandex Pay SDK initialization {#sdk-initialization}

<!-- source: en/_includes/ios-sdk-initialization.md -->
Initialize the SDK in your project's `AppDelegate.swift` in the `application(_:didFinishLaunchingWithOptions:)`:

{% list tabs %}

- Swift

   ```swift
   import YandexPaySDK

   func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
       do {
           // Specify the configuration
           let merchant = YandexPaySDKMerchant(
               // Merchant ID in Yandex Pay
               id: "MERCHANT_ID",
               // Merchant name
               name: "MERCHANT_NAME",
               // Merchant URL
               url: "https://example.org/"
           )
           let configuration = YandexPaySDKConfiguration(
               // Required environment
               environment: .sandbox,
               // Merchant information
               merchant: merchant,
               // Localization
               locale: .ru
           )
           // Initialize the SDK
           try YandexPaySDKApi.initialize(configuration: configuration)
       } catch {
           // Handle the error appropriately
           assertionFailure("Unable to initialize YandexPaySDKApi.")
       }

       // Initialize UIWindow and ViewController
       let controller = ViewController()
       let window = UIWindow(frame: UIScreen.main.bounds)
       window.rootViewController = controller
       window.makeKeyAndVisible()
       self.window = window

       return true
   }
   ```

- Objective-C

   ```objc
   #import <YandexPaySDK/YandexPaySDK-Swift.h>

       // Specify the configuration
       YandexPaySDKMerchant* merchant = [[YandexPaySDKMerchant alloc] initWithMerchantId: @"MERCHANT_ID" // Merchant ID in YandexPay
                                                                                    name: @"MERCHANT_NAME" // Merchant name
                                                                                     url: @"https://example.org/"]; // Merchant URL
       // Required environment
       YandexPaySDKConfiguration* configuration = [[YandexPaySDKConfiguration alloc] initWithEnvironment: YandexPaySDKEnvironmentSandbox
                                                                                                merchant: merchant // Merchant information
                                                                                                  locale: YandexPaySDKLocaleRU]; // Localization
       // Initialize the SDK
       NSError *initializationError;
       [YandexPaySDKApi initializeWithConfiguration: configuration error:&initializationError];

       // Handle the error appropriately
       if (initializationError != nil) {
           [NSException raise:@"FailedToInitializePay" format:@"Subclasses must implement a valid init method"];
       }

       // Initialize UIWindow and ViewController
       UIViewController *controller = [[ViewController alloc] init];
       UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
       [window setRootViewController:controller];
       [window makeKeyAndVisible];
       _window = window;

       return YES;
   ```

{% endlist %}

Add a `YandexPaySDK` notification about the app lifecycle events in your project's `AppDelegate.swift`.

{% list tabs %}

- Swift

   ```swift
   import YandexPaySDK

   func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
       YandexPaySDKApi.instance.applicationDidReceiveUserActivity(userActivity)
       return true
   }

   func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
       YandexPaySDKApi.instance.applicationDidReceiveOpen(url, sourceApplication: options[.sourceApplication] as? String)
       return true
   }

   func applicationWillEnterForeground(_ application: UIApplication) {
       YandexPaySDKApi.instance.applicationWillEnterForeground()
   }

   func applicationDidBecomeActive(_ application: UIApplication) {
       YandexPaySDKApi.instance.applicationDidBecomeActive()
   }
   ```

- Objective-C

   ```objc
   #import <YandexPaySDK/YandexPaySDK-Swift.h>

   - (void)application:(UIApplication *)application didUpdateUserActivity:(NSUserActivity *)userActivity {
       [[YandexPaySDKApi instance] applicationDidReceiveUserActivity:userActivity];
   }

   - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
       [[YandexPaySDKApi instance] applicationDidReceiveOpen:url sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]];
       return YES;
   }

   - (void)applicationWillEnterForeground:(UIApplication *)application {
       [[YandexPaySDKApi instance] applicationWillEnterForeground];
   }

   - (void)applicationDidBecomeActive:(UIApplication *)application {
       [[YandexPaySDKApi instance] applicationDidBecomeActive];
   }
   ```

{% endlist %}
<!-- endsource: en/_includes/ios-sdk-initialization.md -->

## Adding Yandex Pay checkout button on the screen in a Swift project {#add-button-swift}

In the `ViewController` of the screen where you need to add the button, create the button using the `createCheckoutButton(configuration:delegate:)` method of the `YandexPaySDKApi` class:

```swift
import YandexPaySDK

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        // Check that the SDK is initialized
        guard YandexPaySDKApi.isInitialized else {
          assertionFailure("YandexPaySDK is not initialized.")
          return
        }

        // Specify the theme for the button
        let theme: YandexPayButtonTheme
        if #available(iOS 13.0, *) {
            // Using the `dynamic` parameter, you can specify whether the button needs
            // to change its color palette when the system theme changes
            theme = YandexPayButtonTheme(appearance: .dark, dynamic: true)
        } else {
            theme = YandexPayButtonTheme(appearance: .dark)
        }

        // Initialize the configuration
        let configuration = YandexPayButtonConfiguration(theme: theme)

        // Create the button
        let button = YandexPaySDKApi.instance.createCheckoutButton(configuration: configuration, delegate: self)

        // Specify the corner radius for the button (the default value is 8px)
        button.layer.cornerRadius = .zero

        // Add the button to the hierarchy
        view.addSubview(button)

        // Add the layout for the button
        button.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            button.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            button.widthAnchor.constraint(equalToConstant: 250)
        ])
    }
}
```

The button used for interacting with the client app uses the delegate `YandexPayCheckoutButtonDelegate`. Implement this delegate to pass it to the button at creation:

```swift
import YandexPaySDK

extension ViewController: YandexPayCheckoutButtonDelegate {

    // Process the checkout result
    func yandexPayCheckoutButton(_ button: YandexPayButton, didCompletePaymentWithResult result: YPCheckoutResult) {
        switch result {
        case .succeeded(let checkoutInfo):
            // The checkout was successful
        case .failed(let checkoutError):
            // There was an error during checkout
        case .cancelled:
            // The user closed/swiped the YandexPay form
        }
    }

    // Provide UIViewController from which you need to show the YandexPay form by clicking a button
    func yandexPayCheckoutButtonDidRequestViewControllerForPresentation(_ button: YandexPayButton) -> UIViewController? {
        return self
    }

    // Provide information about the order
    func yandexPayCheckoutButtonDidRequestPaymentSheet(_ button: YandexPayButton) -> YPCheckoutPaymentSheet? {
        return YPCheckoutPaymentSheet(
            // Currency code
            currencyCode: .rub,
            // information about the user cart
            cart: YPPaymentCart(items: [
                YPProduct(id: "1", total: "434.39", quantity: YPQuantity(count: "1")),
                YPProduct(id: "2", total: "1474.86", quantity: YPQuantity(count: "2")),
            ]),
            orderId: nil,
            metadata: nil
        )
    }
}
```

## Adding a YandexPay checkout button to the screen in the Objective-C project {#add-button-objc}

You can only use Yandex Pay SDK from Objective-C when initializing a `YandexPaySDKApi` object and reporting the application lifecycle to the SDK. To create a button, `YPCheckoutPaymentSheet` object, and to start responding to the events emitted by the button, implement a layer in Swift that can be called from Objective-C.

To create such a layer:

1. Make this layer available in Objective-C by inheriting this class from `NSObject` or an ancestor of `NSObject`.
1. Use the `@objc` attribute to label the properties and methods of this layer that should be available from Objective-C.
1. Make classes from Objective-C available in Swift, adding their header files to the bridging header of your project.
1. Establish communication between the container and, for example, the `UIViewController` object written in Objective-C by using a delegate object or otherwise.

Example of the layer object:

```swift
import YandexPaySDK

// In this example, we use a delegate object to report events
// from the UIViewController container written in Objective-C.
// To make this protocol available in Objective-C, we label it using the @objc
// attribute.
@objc
protocol YandexPayCheckoutButtonContainerDelegate: AnyObject {
    // We will use this method to notify  
    // that the checkout token was received successfully.
    func yandexPayCheckoutButtonDidSucceedWithOrderId(_ orderId: String)

    // we will use this method to report an error
    // that arose in the process.
    func yandexPayCheckoutButtonDidFail()

    // We'll use this method to notify about cancellation.
    func yandexPayCheckoutButtonDidCancel()

    // We'll use this method to get UIViewController
    // of the object for which you need to show the Yandex Pay form.
    func yandexPayCheckoutButtonDidRequestViewController() -> UIViewController?

    // In the example, we'll use a separate method to get
    // information about user cart. The CardProduct model is written
    // in Objective-C and we use it here because it's header file
    // has been added to the bridging header file of the project.
    func yandexPayCheckoutButtonDidRequestCardProducts() -> [CardProduct]
}

// A layer object that will include the Yandex Pay button
// and interact with the button and with the Objective-C code.
final class YandexPayCheckoutButtonContainer: UIView {

    // We label the properties that should be available from Objective-C
    // with the @objc attribute.
    @objc
    weak var delegate: YandexPayCheckoutButtonContainerDelegate?

    private var payButton: YandexPayButton!

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }

    // This container only includes a button, so let's override
    // intrinsicContentSize. If your container is more sophisticated,
    // you can use any view layout for it at your discretion.
    override var intrinsicContentSize: CGSize {
        return payButton.intrinsicContentSize
    }

    private func setupView() {
        // Check whether the SDK has been initialized.
        guard YandexPaySDKApi.isInitialized else {
            assertionFailure("YandexPaySDKApi is not initialized.")
            return
        }

        // Specify a theme for the button.
        let payButtonTheme = YandexPayButtonTheme(appearance: .dark, dynamic: true)

        // Specify the button layout.
        let payButtonConfiguration = YandexPayButtonConfiguration(theme: payButtonTheme)

        // Create a button using YandexPaySDKApi.
        payButton = YandexPaySDKApi.instance.createCheckoutButton(configuration: payButtonConfiguration, delegate: self)

        // Add the button to the hierarchy.
        payButton.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        payButton.frame = bounds
        addSubview(payButton)
    }
}

// Implement the button's delegate to get events from it.
extension YandexPayCheckoutButtonContainer: YandexPayCheckoutButtonDelegate {
    func yandexPayCheckoutButton(_ button: YandexPayButton, didCompletePaymentWithResult result: YPCheckoutResult) {
        // Get events about a successfully received token or an error.
        switch result {
        case .succeeded(let checkoutInfo):
            // Use the delegate object to notify the Objective-C code that the token was received.
            // payment token
            delegate?.yandexPayCheckoutButtonDidSucceedWithOrderId(checkoutInfo.orderId)
        case .failed:
            // Use the delegate object to report the error to the Objective-C code.
            delegate?.yandexPayCheckoutButtonDidFail()
        case .cancelled:
            // Use the delegate object to notify the Objective-C code about a cancellation.
            delegate?.yandexPayCheckoutButtonDidCancel()
        @unknown default:
            break
        }
    }

    func yandexPayCheckoutButtonDidRequestViewControllerForPresentation(_ button: YandexPayButton) -> UIViewController? {
        // Use the delegate object to request, from the Objective-C code, the UIViewController
        // object in which the Yandex Pay form should be shown.
        return delegate?.yandexPayCheckoutButtonDidRequestViewController()
    }

    func yandexPayCheckoutButtonDidRequestPaymentSheet(_ button: YandexPayButton) -> YPCheckoutPaymentSheet? {
        guard let delegate = delegate else {
            assertionFailure("Delegate is missing.")
            return nil
        }

        // Construct the YPCheckoutPaymentSheet object here and return it to
        // the button. Naturally, when creating the YPCheckoutPaymentSheet object,
        // you need to use a certain business logic written in
        // Objective-C. To interact with this business logic,
        // you can use the same delegate object
        // or other Objective-C
        // classes (for example, some services or interactors)
        // that encapsulate this logic. To do this,
        // make these classes available in Swift by adding their
        // header files to the bridging header file of your project.
        // Note that if you implement your business logic in
        // Objective-C, it will use models implemented in
        // Objective-C. That's why here you can implement their mapping
        // to YandexPaySDK models.

        // In this example, we use a delegate object.
        let products = delegate.yandexPayCheckoutButtonDidRequestCardProducts()

        // Construct YPCheckoutPaymentSheet
        return YPCheckoutPaymentSheet(
            currencyCode: .rub,
            cart: YPPaymentCart(items: products.map {
                YPProduct(id: $0.productID, total: $0.total, quantity: YPQuantity(count: $0.quantity))
            }),
            orderId: nil,
            metadata: nil
        )
    }
}
```

Here's an example of a UIViewController object interacting with the layer:

```objc
#import <YandexPaySDK/YandexPaySDK-Swift.h>

// Add conformance to the protocol.
@interface ViewController (ViewControllerYandexPayButtonContainer) <YandexPayCheckoutButtonContainerDelegate>

@end

// Declare private methods.
@interface ViewController ()

- (void)showAlertWithMessage:(NSString *)message;

@end

// Implement the ViewController class.
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor systemBackgroundColor];

    // Use the layer object to show the Yandex Pay button.
    YandexPayCheckoutButtonContainer *container = [[YandexPayCheckoutButtonContainer alloc] init];

    // Specify the delegate object for the layer.
    container.delegate = self;

    // Add the layer object to the hierarchy.
    container.translatesAutoresizingMaskIntoConstraints = false;
    [self.view addSubview:container];
    [[container.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor] setActive:TRUE];
    [[container.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor] setActive:TRUE];
}

- (void)showAlertWithMessage:(NSString *)message {
    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Message" message:message preferredStyle:UIAlertControllerStyleAlert];
    [controller addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
    [self presentViewController:controller animated:TRUE completion:nil];
}

- (void)yandexPayCheckoutButtonDidSucceedWithOrderId:(NSString *)orderId {
    // We've got a token and can now check out
    // using this token.
    [self showAlertWithMessage:[NSString stringWithFormat:@"Checkout complete: %@", orderId]];

    // Access the payment gateway
    // ...
}

- (void)yandexPayCheckoutButtonDidFail {
    // We received an error event.
    [self showAlertWithMessage:@"Checkout failed"];
}

- (void)yandexPayCheckoutButtonDidCancel {
    // We received a cancellation event.
    [self showAlertWithMessage:@"Checkout was cancelled by the user"];
}

- (UIViewController *)yandexPayCheckoutButtonDidRequestViewController {
    // Return the current UIViewController to render the form.
    return self;
}

- (NSArray<CardProduct *> *)yandexPayCheckoutButtonDidRequestCardProducts {
    // If needed, transmit the order data and other
    // data using the delegate or by any other convenient method.
    NSMutableArray *products = [[NSMutableArray alloc] init];
    [items addObject:[[CardProduct alloc] initWithProductID:@"ID-1" total:@"1000.00" quantity: @"1"]];
    [items addObject:[[CardProduct alloc] initWithProductID:@"ID-2" total:@"500.00" quantity: @"2"]];
    return products;
}

@end
```

As the `CardProduct` structure, you can use any of your models implemented in Objective-C, and here it is used as an illustration.

CardProduct.h file:

```objc
@interface Product : NSObject

@property (readonly, copy, nonatomic) NSString *productID;
@property (readonly, copy, nonatomic) NSString *total;
@property (readonly, copy, nonatomic) NSString *quantity;

- (instancetype)initWithProductID:(NSString *)productID
                            total:(NSString *)total
                         quantity:(NSString *)quantity;

@end
```

You can use an asynchronous delegate object, if you cannot instantly provide `YPCheckoutPaymentSheet`:

1. Create a button using a specialized method of the`YandexPaySDKApi` class:

   ```swift
   import YandexPaySDK

   payButtonAsync = YandexPaySDKApi.instance.createCheckoutButton(configuration: configuration, asyncDelegate: self)
   ```

1. Implement the delegate `YandexPayButtonAsyncDelegate`:

   ```swift
   import YandexPaySDK

   extension ViewController: YandexPayButtonAsyncDelegate
     func yandexPayCheckoutButton(_ button: YandexPayButton, didCompletePaymentWithResult result: YPCheckoutResult) {
        // ...
     }

     func yandexPayCheckoutButtonDidRequestViewControllerForPresentation(_ button: YandexPayButton) -> UIViewController? {
       // ...
     }

     func yandexPayCheckoutButtonDidRequestPaymentSheet(_ button: YandexPayButton, completion: @escaping (YPCheckoutPaymentSheet?) -> Void) {
       // Show a loader on the button using the provided method or use your custom loader if needed
       payButtonAsync.setLoaderVisible(true, animated: true)

       // Make an asynchronous call
       DispatchQueue.global().asyncAfter(deadline: .now() + 2.0) { [weak self] in
         // Get YPCheckoutPaymentSheet
         let paymentSheet = YPCheckoutPaymentSheet(...)

         DispatchQueue.main.async {
           // Hide the loader
           self?.payButtonAsync.setLoaderVisible(false, animated: true)

           // Call the completion block
           completion(paymentSheet)
         }
       }
     }
   ```
