# Migrate to Confirmation Tokens Use a ConfirmationToken instead of a PaymentMethod to handle payments This guide demonstrates how to migrate from the legacy [PaymentMethod](https://docs.stripe.com/api/payment_methods.md) to the [ConfirmationToken](https://docs.stripe.com/api/confirmation_tokens.md) in your mobile integration. You can use the ConfirmationToken object instead of the PaymentMethod to: - **Simplify server-side code**: You won’t need to manually construct `mandate_data` or pass `return_url` and `shipping` when you confirm intents. - **Handle data**: It automatically includes shipping information and other payment context for you. | Feature | PaymentMethod (Legacy) | ConfirmationToken | | ---------------------------- | ---------------------- | ----------------- | | Payment confirmation | ✓ | ✓ | | Setup future usage | Manual | Automatic | | Shipping information | Manual | Automatic | | Mandate data | Manual | Automatic | | Return URL | Manual | Automatic | | Server-side CVC recollection | ❌ | ✓ | ## Before you begin This guide assumes you have an existing mobile integration using the legacy PaymentMethod. If you’re building a new integration, follow the [Accept a payment](https://docs.stripe.com/payments/mobile/accept-payment.md) guide, which uses ConfirmationTokens by default. # iOS > This is a iOS for when platform is ios. View the full page at https://docs.stripe.com/payments/mobile/migration-confirmation-tokens?platform=ios. ## Update your client code [Client-side] To access and use payment details, pass a callback that receives a `confirmationToken`: ```swift let intentConfig = PaymentSheet.IntentConfiguration( mode: .payment(amount: 1099, currency: "USD")) { confirmationToken in try await withCheckedThrowingContinuation() { continuation in // If you send paymentMethod.stripeId to your server, send confirmationToken.stripeId instead. let myServerResponse: Result = ... // Make a request to your server switch myServerResponse { case .success(let clientSecret): intentCreationCallback(.success(clientSecret)) case .failure(let error): intentCreationCallback(.failure(error)) }} } ``` ## Update your server code [Server-side] When you accept payments, you can choose where to confirm the PaymentIntent or SetupIntent: - **Client-side confirmation**: Your server creates an unconfirmed Intent and returns its `client_secret` to your app. The mobile SDK then confirms the Intent directly to Stripe. - **Server-side confirmation**: Your app sends the ConfirmationToken to your server, which both creates and confirms the Intent in a single API call by setting `confirm: true`. The confirmation happens entirely on your server when you call the Stripe API, and provides you with more control over the payment flow. #### Client-side confirmation Create the PaymentIntent or SetupIntent by excluding `payment_method`, `return_url`, `mandate_data`, and `shipping`. The mobile SDK handles confirmation on the client-side using the ConfirmationToken: ```javascript app.post('/create-intent', async (req, res) => { try { const args = { amount: 1099, currency: 'usd', automatic_payment_methods: {enabled: true}, }; const intent = await stripe.paymentIntents.create(args); res.json({ client_secret: intent.client_secret }); } catch (err) { res.status(err.statusCode).json({ error: err.message }); } }); ``` #### Server-side confirmation Use the `confirmation_token` parameter when you create and confirm the PaymentIntent or SetupIntent. The ConfirmationToken automatically provides the payment method, mandate data, and return URL. ```javascript app.post('/create-intent', async (req, res) => { try { const args = { amount: 1099, currency: 'usd', automatic_payment_methods: {enabled: true}, confirm: true,confirmation_token: req.body.confirmationTokenId, }; const intent = await stripe.paymentIntents.create(args); res.json({ client_secret: intent.client_secret }); } catch (err) { res.status(err.statusCode).json({ error: err.message }); } }); ``` Any parameters that you provide directly to the PaymentIntent or SetupIntent at confirmation time, such as `shipping`, override the corresponding properties on the ConfirmationToken. # Android > This is a Android for when platform is android. View the full page at https://docs.stripe.com/payments/mobile/migration-confirmation-tokens?platform=android. ## Update your client code [Client-side] To update the `createIntentCallback`, modify it to receive a `confirmationToken`: ```kotlin paymentSheet = PaymentSheet.Builder(::onPaymentSheetResult).createIntentCallback { confirmationToken -> val networkResult = myNetworkClient.createIntent(// Make a request to your server to create a PaymentIntent and return its client secret. // Optionally pass confirmationToken.id if doing server-side confirmation. confirmationTokenId = confirmationToken.id, ) if (networkResult.isSuccess) { CreateIntentResult.Success(networkResult.clientSecret) } else { CreateIntentResult.Failure(networkResult.exception) } } .build(this) ``` ## Update your server code [Server-side] When you accept payments, you can choose where to confirm the PaymentIntent or SetupIntent: - **Client-side confirmation**: Your server creates an unconfirmed Intent and returns its `client_secret` to your app. The mobile SDK then confirms the Intent directly to Stripe. - **Server-side confirmation**: Your app sends the ConfirmationToken to your server, which both creates and confirms the Intent in a single API call by setting `confirm: true`. The confirmation happens entirely on your server when you call the Stripe API, and provides you with more control over the payment flow. #### Client-side confirmation Create the PaymentIntent or SetupIntent by excluding `payment_method`, `return_url`, `mandate_data`, and `shipping`. The mobile SDK handles confirmation on the client-side using the ConfirmationToken: ```javascript app.post('/create-intent', async (req, res) => { try { const args = { amount: 1099, currency: 'usd', automatic_payment_methods: {enabled: true}, }; const intent = await stripe.paymentIntents.create(args); res.json({ client_secret: intent.client_secret }); } catch (err) { res.status(err.statusCode).json({ error: err.message }); } }); ``` #### Server-side confirmation Use the `confirmation_token` parameter when you create and confirm the PaymentIntent or SetupIntent. The ConfirmationToken automatically provides the payment method, mandate data, and return URL. ```javascript app.post('/create-intent', async (req, res) => { try { const args = { amount: 1099, currency: 'usd', automatic_payment_methods: {enabled: true}, confirm: true,confirmation_token: req.body.confirmationTokenId, }; const intent = await stripe.paymentIntents.create(args); res.json({ client_secret: intent.client_secret }); } catch (err) { res.status(err.statusCode).json({ error: err.message }); } }); ``` Any parameters that you provide directly to the PaymentIntent or SetupIntent at confirmation time, such as `shipping`, override the corresponding properties on the ConfirmationToken. # React Native > This is a React Native for when platform is react-native. View the full page at https://docs.stripe.com/payments/mobile/migration-confirmation-tokens?platform=react-native. ## Update your client code [Client-side] To change `confirmHandler` to `confirmationTokenConfirmHandler`, update the callback signature to receive `confirmationToken`: ```jsx intentConfiguration: {confirmationTokenConfirmHandler: async ( confirmationToken, intentCreationCallback ) => { const response = await fetch('/create-intent', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({// Make a request to your server to create a PaymentIntent and return its client secret. // Optionally pass confirmationToken.id if doing server-side confirmation. confirmationTokenId: confirmationToken.id, }), }); const { clientSecret, error } = await response.json(); if (clientSecret) { intentCreationCallback({ clientSecret }); } else { intentCreationCallback({ error }); } }, mode: { amount: 6099, currencyCode: 'USD', }, } ``` ## Update your server code [Server-side] When you accept payments, you can choose where to confirm the PaymentIntent or SetupIntent: - **Client-side confirmation**: Your server creates an unconfirmed Intent and returns its `client_secret` to your app. The mobile SDK then confirms the Intent directly to Stripe. - **Server-side confirmation**: Your app sends the ConfirmationToken to your server, which both creates and confirms the Intent in a single API call by setting `confirm: true`. The confirmation happens entirely on your server when you call the Stripe API, and provides you with more control over the payment flow. #### Client-side confirmation Create the PaymentIntent or SetupIntent by excluding `payment_method`, `return_url`, `mandate_data`, and `shipping`. The mobile SDK handles confirmation on the client-side using the ConfirmationToken: ```javascript app.post('/create-intent', async (req, res) => { try { const args = { amount: 1099, currency: 'usd', automatic_payment_methods: {enabled: true}, }; const intent = await stripe.paymentIntents.create(args); res.json({ client_secret: intent.client_secret }); } catch (err) { res.status(err.statusCode).json({ error: err.message }); } }); ``` #### Server-side confirmation Use the `confirmation_token` parameter when you create and confirm the PaymentIntent or SetupIntent. The ConfirmationToken automatically provides the payment method, mandate data, and return URL. ```javascript app.post('/create-intent', async (req, res) => { try { const args = { amount: 1099, currency: 'usd', automatic_payment_methods: {enabled: true}, confirm: true,confirmation_token: req.body.confirmationTokenId, }; const intent = await stripe.paymentIntents.create(args); res.json({ client_secret: intent.client_secret }); } catch (err) { res.status(err.statusCode).json({ error: err.message }); } }); ``` Any parameters that you provide directly to the PaymentIntent or SetupIntent at confirmation time, such as `shipping`, override the corresponding properties on the ConfirmationToken. > If you previously inspected the PaymentMethod object, you can now access payment method details through the `paymentMethodPreview` property on the ConfirmationToken. ## See also - [Accept a payment](https://docs.stripe.com/payments/mobile/accept-payment.md) - [Finalize payments on the server](https://docs.stripe.com/payments/mobile/finalize-payments-on-the-server.md) - [ConfirmationToken API reference](https://docs.stripe.com/api/confirmation_tokens.md)