Last updated: October 14, 2026
Plan for a client rename, a new required merchantID, and return URLs that move into a URL config, which affects both your app code and your Universal Link setup.
The largest changes are in PayPal Checkout:
CoreConfig requires a merchantID.| Area | v2 (2.x) | v3 |
|---|---|---|
| Client class | PayPalWebCheckoutClient (module PayPalWebPayments) | PayPalClient (module PayPalPayments) |
CoreConfig | client ID + environment | adds required merchantID, optional bnCode |
| Session | none | You must call createPayPalSession(sessionType:userIdentity:urlConfig:userAction:) 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.
sdk.ios.paypal scheme for its own redirect.Bump CorePayments and swap the PayPal Checkout product for its v3 successor. PayPal renamed the module along with the client:
# 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'Use this diff to guide the change:
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)
+ }Add the custom-scheme fallbackSchemeURL under CFBundleURLTypes. It's optional on PayPalURLConfig; see Install and set up for why you should set it regardless. Also declare paypal under LSApplicationQueriesSchemes so the SDK can detect the PayPal app. Then 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.
sdk.ios.paypal isn't retired
The sdk.ios.paypal scheme isn't retired in v3. It's still the SDK's internal callback scheme for Card's 3D Secure ASWebAuthenticationSession challenge, and it still backs the internal redirect of the PayPal Checkout in-app-browser fallback. What changed is the return path that you configure for PayPal Checkout and saving payment methods. That path is now Universal Links, with fallbackSchemeURL as backup. You don't register or handle sdk.ios.paypal yourself.
PayPalClient (module PayPalPayments) and no references to PayPalWebCheckoutClient or PayPalWebPayments remain.createPayPalSession(sessionType:) → start(orderID:) → return through handleReturnURL(url) → capture.sessionNotStarted error does not occur, confirming createPayPalSession() runs before start().CoreConfig, and register your return links.Cards
Accept an Advanced Credit and Debit Card (ACDC) payment in your iOS app with PayPal Mobile SDK. Optionally, save the card for future use.
From v1 to v2
Update your iOS integration from PayPal Mobile SDK v1 to v2. Move from delegate callbacks to completion handlers and async/await. Adopt the unified CoreSDKError type. Handle cancellations as errors.