# Update iOS SDK from v2 to v3 (/sdk/ios/update-ios)

Update your PayPal Mobile SDK v2 iOS integration to v3.0.0.



This guide describes how to move an existing PayPal Mobile SDK v2 (2.x) iOS integration to v3.0.0. The largest changes are in PayPal Checkout: the client was replaced with a new class in a new module, checkout is now session-first, `CoreConfig` requires a `merchantID`, return URLs moved into a URL config, and App Switch now requires Universal Links (v2's web flow used a hardcoded callback scheme for its own redirects).

## Review what changed in PayPal Checkout [#review-what-changed-in-paypal-checkout]

| Area            | v2 (2.x)                                               | v3                                                                                                                                                   |
| --------------- | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| Client class    | `PayPalWebCheckoutClient` (module `PayPalWebPayments`) | `PayPalClient` (module `PayPalPayments`)                                                                                                             |
| `CoreConfig`    | client ID + environment                                | adds required `merchantID`, optional `bnCode`                                                                                                        |
| Session         | none                                                   | `createPayPalSession(sessionType:userIdentity:urlConfig:userAction:)` is required before `start()`                                                   |
| Return URLs     | hardcoded `sdk.ios.paypal` callback scheme             | `PayPalURLConfig` passed to `createPayPalSession()`. App Switch uses Universal Links                                                                 |
| `start()`       | `start(request:)`                                      | `start(orderID:completion:)`                                                                                                                         |
| Result          | completion or delegate                                 | completion with `.success` or `.failure`; cancellation is a `.failure`, so check `PayPalError.isCheckoutCanceled(error)` or `isVaultCanceled(error)` |
| Return handling | handled internally by `ASWebAuthenticationSession`     | forward the Universal Link through `handleReturnURL(url)`                                                                                            |

Card (ACDC) keeps its own client; the main change it inherits is the `merchantID` on `CoreConfig`. Card's `approveOrder()` still resolves 3DS inline on iOS.

## Before you upgrade [#before-you-upgrade]

* Get your merchant ID, the encrypted merchant account ID, from the [PayPal Developer Dashboard](/dashboard/), which is now required to initialize the SDK.
* Add an **Associated Domains** entitlement and serve an AASA file for your return domain. v3 App Switch returns through Universal Links, whereas v2's web flow used the hardcoded `sdk.ios.paypal` scheme for its own redirect.
* Toolchain is unchanged: Xcode 15+, iOS 16+, Swift 5.9+.

## Update the dependency [#update-the-dependency]

Bump `CorePayments` and swap the PayPal Checkout product for its v3 successor. The module was renamed along with the client:

```ruby
# Podfile
pod 'PayPal/CorePayments', '~> 3.0'
pod 'PayPal/PayPalPayments', '~> 3.0'   # was PayPal/PayPalWebPayments in v2
pod 'PayPal/PaymentButtons', '~> 3.0'
pod 'PayPal/FraudProtection', '~> 3.0'
```

## Migrate PayPal Checkout [#migrate-paypal-checkout]

Use this diff to guide the change:

```diff
  let config = CoreConfig(
      clientID: "<CLIENT_ID>",
      environment: .sandbox,
+     merchantID: "<MERCHANT_ID>"   // now required, distinct from your client ID
  )

- let client = PayPalWebCheckoutClient(config: config)
+ let client = PayPalClient(config: config)
+ let urlConfig = PayPalURLConfig(
+     returnAppURL: URL(string: "https://example.com/merchant-app/return")!,
+     cancelAppURL: URL(string: "https://example.com/merchant-app/cancel")!,
+     fallbackSchemeURL: URL(string: "merchantapp://return")!
+ )

  func onPayPalButtonTapped() async throws {
+     // NEW: prepare the session before start()
+     client.createPayPalSession(
+         sessionType: .checkout,
+         userIdentity: PayPalUserIdentity(email: "buyer@example.com", phone: nil),
+         urlConfig: urlConfig,
+         userAction: .continue
+     )
      let orderID = try await myServer.createOrder()
-     client.start(request: PayPalWebCheckoutRequest(orderID: orderID)) { result in /* ... */ }
+     client.start(orderID: orderID) { result in
+         switch result {
+         case .success(let checkout): captureOrder(checkout.orderID)
+         case .failure(let error):
+             if PayPalError.isCheckoutCanceled(error) {
+                 showCheckoutScreen()
+             } else {
+                 showError(error.localizedDescription)
+             }
+         }
+     }
  }

+ // NEW in v3: forward the Universal Link return to the SDK
+ func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
+     guard let url = userActivity.webpageURL else { return }
+     client.handleReturnURL(url)
+ }
```

## Configure Info.plist and entitlements [#configure-infoplist-and-entitlements]

Add the custom-scheme `fallbackSchemeURL` under `CFBundleURLTypes`. It's optional on `PayPalURLConfig`; see [Install and set up](/sdk/ios/install-and-setup#3-register-your-return-links) for why you should set it regardless. Also declare `paypal` under `LSApplicationQueriesSchemes` so the SDK can detect the PayPal app, and add the Associated Domains entitlement for your return domain. v2's web flow needed none of these for PayPal Checkout, because its return handling was internal to `ASWebAuthenticationSession`, built on the hardcoded `sdk.ios.paypal` scheme.

> **Info:** `sdk.ios.paypal` isn't retired in v3. It's still the SDK's internal callback scheme for Card's 3D Secure `ASWebAuthenticationSession` challenge, and it also still backs the PayPal Checkout in-app-browser fallback's own redirect internally. What changed is the buyer-facing, merchant-configured return path for PayPal Checkout and saving payment methods: that's now Universal Links, with `fallbackSchemeURL` as backup, not something built on `sdk.ios.paypal` that you need to register or handle yourself.

## Verify the upgrade [#verify-the-upgrade]

* The project compiles with `PayPalClient` (module `PayPalPayments`) and no references to `PayPalWebCheckoutClient` or `PayPalWebPayments` remain.
* A sandbox checkout completes end to end: `createPayPalSession(sessionType:)` → `start(orderID:)` → return through `handleReturnURL(url)` → capture.
* `sessionNotStarted` does not occur, confirming `createPayPalSession()` runs before `start()`.

## See also [#see-also]

* [Install and set up](/sdk/ios/install-and-setup): add the SDK, initialize `CoreConfig`, and register your return links.
* [PayPal Checkout integration guide](/sdk/ios/add-payment-methods/paypal-checkout): integrate One-Time Checkout, save payment methods, Pay Later, and PayPal Credit.
* [Troubleshooting](/sdk/ios/troubleshooting): diagnose common build and integration failures by symptom.
