Last updated: October 14, 2026
Move an existing PayPal Mobile SDK v2.x Android integration to v3.0.0. Plan for a client rename and a new required merchantId, plus moving return URLs out of your Orders API call, which affects both your app and your server.
The largest changes are in PayPal Checkout:
CoreConfig requires a merchantId.The following table summarizes the key PayPal Checkout changes from v2 to v3.
| Area | v2 | v3 |
|---|---|---|
| Client class | PayPalWebCheckoutClient | PayPalClient |
CoreConfig | clientId + environment | adds required merchantId, optional bnCode; environment renamed to coreEnvironment |
| Session | none | You must call createPayPalSession() before start() / vault() |
| Return URLs | urlScheme on the client + experienceContext URLs in the Orders API | ReturnToAppUrlConfig passed to createPayPalSession(); not set in the Orders API |
start() | start(activity, request) | start(activity, orderId, callback) |
| Result | PayPalWebCheckoutFinishStartResult through finishStart(intent) | The start() callback reports PayPalPresentAuthChallengeResult (Success/Failure), showing only whether the SDK presented the checkout UI. The actual checkout outcome, PayPalFinishStartResult (Success/Canceled/Failure/NoResult), arrives separately through finishStart(intent) when the buyer returns |
| Return handling | finishStart(intent) returns the result | Same method name, finishStart(intent), called from onNewIntent; now returns PayPalFinishStartResult? |
Card (ACDC) keeps its own client; the main change it inherits is the merchantId on CoreConfig. Card's approveOrder() / presentAuthChallenge() / finishApproveOrder() result-type pattern is unchanged from 2.x.
Bump each PayPal module to the v3 release. PayPal renamed the PayPal Checkout artifact from paypal-web-payments to paypal-payments. The other module names are unchanged:
dependencies {
implementation 'com.paypal.android:paypal-payments:3.0.0' // was paypal-web-payments in v2
implementation 'com.paypal.android:payment-buttons:3.0.0'
implementation 'com.paypal.android:fraud-protection:3.0.0'
}Use this diff to guide the change:
val config = CoreConfig(
clientId = "<CLIENT_ID>",
+ merchantId = "<MERCHANT_ID>", // now required, distinct from your client ID
- environment = Environment.SANDBOX
+ coreEnvironment = CoreEnvironment.SANDBOX // renamed from `environment` in v3
)
- val client = PayPalWebCheckoutClient(context, config, "my-url-scheme")
+ val client = PayPalClient(context, config)
+ val urlConfig = ReturnToAppUrlConfig(
+ returnAppUrl = "https://example.com/merchant-app/return",
+ cancelAppUrl = "https://example.com/merchant-app/cancel",
+ fallbackSchemeUrl = "merchantapp://return"
+ )
fun onPayPalButtonTapped() {
+ // NEW: prepare the session before start()
+ client.createPayPalSession(
+ tokenType = TokenType.ORDER_ID,
+ userIdentity = PayPalUserIdentity(email = "[email protected]"),
+ urlConfig = urlConfig,
+ userAction = PayPalUserAction.CONTINUE
+ )
val orderId = myServer.createOrder()
- client.start(this, PayPalWebCheckoutRequest(orderId)) { /* PayPalPresentAuthChallengeResult */ }
+ client.start(this, orderId, object : PayPalResultCallback {
+ override fun onPayPalResult(result: PayPalPresentAuthChallengeResult) {
+ when (result) {
+ is PayPalPresentAuthChallengeResult.Success -> { /* checkout UI presented; the outcome arrives in onNewIntent */ }
+ is PayPalPresentAuthChallengeResult.Failure -> showError(result.error)
+ }
+ }
+ })
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
- client.finishStart(intent)?.let { /* PayPalWebCheckoutFinishStartResult */ }
+ client.finishStart(intent)?.let { result ->
+ when (result) {
+ is PayPalFinishStartResult.Success -> captureOrder(result.orderId)
+ is PayPalFinishStartResult.Canceled -> showCheckoutScreen()
+ is PayPalFinishStartResult.Failure -> showError(result.error)
+ PayPalFinishStartResult.NoResult -> { /* intent was not a checkout return */ }
+ }
+ }
}In v2, you set experienceContext.returnUrl / cancelUrl when creating the order. In v3, those move to the SDK through ReturnToAppUrlConfig. Remove them from your Orders v2 create call for the session-based flow. Your manifest App Link and custom-scheme fallback stay as they were.
In v2, selecting PAY_LATER / PAYPAL_CREDIT funding required the non-session start(activity, request: PayPalWebCheckoutRequest, callback) overload. v3 removed both that overload and PayPalWebCheckoutRequest.
Funding-source selection moves entirely to your server: set payment_source.paypal.experience_context.payment_method_selected to PAYPAL (default), PAYPAL_PAY_LATER, or PAYPAL_CREDIT when you create the order. The client-side createPayPalSession() → start(activity, orderId, callback) flow is identical regardless of funding source.
PayPalClient and no references to PayPalWebCheckoutClient remain.createPayPalSession() → start(activity, orderId, callback) → finishStart(intent) in onNewIntent → capture.PayPalEvent.SESSION_NOT_STARTED event does not fire, confirming createPayPalSession() runs before start().CoreConfig, and register your return links.Cards
Accept an Advanced Credit and Debit Card (ACDC) payment in your Android app with PayPal Mobile SDK. Optionally, save the card for future use.
From v1 to v2
Update your Android integration from PayPal Mobile SDK v1 to v2. Move to sealed result callbacks, manual 3D Secure handling, and remove PayPal Native Payments.