# Card payments without bank authentication Build a simpler mobile integration with regional limitations. # iOS > This is a iOS for when platform is ios. View the full page at https://docs.stripe.com/payments/mobile/without-card-authentication?platform=ios. This integration supports businesses accepting only US and Canadian cards. It’s simpler to build, but doesn’t scale to support a global customer base. ### How this integration works Banks in regions such as Europe and India often require two-factor authentication to confirm a purchase. If you primarily do business in the US and Canada, ignoring *card authentication* (A bank might require the customer to authenticate a card payment before processing. Implementation varies by bank but commonly consists of a customer entering in a security code sent to their phone) can simplify your integration, as banks rarely request it in these regions. When a bank requires authentication, this basic integration immediately declines the payment (similar to a card decline), instead of handling authentication to complete the payment asynchronously. The benefit is that the payment succeeds or declines immediately and payment confirmation happens on the server, so you can handle immediate post-payment actions without a *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests). ### How it compares to the global integration | Feature | This Integration | Global Integration | | -------------------------------------------------------------------- | ---------------- | ------------------ | | Custom payment form | ✔ | ✔ | | Sensitive data never touches your server | ✔ | ✔ | | Works for your US and Canada customers | ✔ | ✔ | | Declines payments with incorrect card details or no funds | ✔ | ✔ | | Declines payments with bank authentication requests | ✔ | | | Works for your global customers | | ✔ | | Automatically handles card payments that require bank authentication | | ✔ | | Webhooks recommended for post-payment tasks | | ✔ | | Easily scales to other payment methods (for example, bank debits) | | ✔ | Growing or global businesses should use Stripe’s [global integration](https://docs.stripe.com/payments/accept-a-payment.md) to support bank requests for two-factor authentication and allow customers to pay with more payment methods. ## Install the Stripe iOS SDK [Client-side] First, you need a Stripe account. [Register now](https://dashboard.stripe.com/register). The [Stripe iOS SDK](https://github.com/stripe/stripe-ios) is open source, [fully documented](https://stripe.dev/stripe-ios/index.html), and compatible with apps supporting iOS 13 or above. #### Swift Package Manager To install the SDK, follow these steps: 1. In Xcode, select **File** > **Add Package Dependencies…** and enter `https://github.com/stripe/stripe-ios-spm` as the repository URL. 1. Select the latest version number from our [releases page](https://github.com/stripe/stripe-ios/releases). 1. Add the **StripePaymentsUI** product to the [target of your app](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app). #### CocoaPods 1. If you haven’t already, install the latest version of [CocoaPods](https://guides.cocoapods.org/using/getting-started.html). 1. If you don’t have an existing [Podfile](https://guides.cocoapods.org/syntax/podfile.html), run the following command to create one: ```bash pod init ``` 1. Add this line to your `Podfile`: ```podfile pod 'StripePaymentsUI' ``` 1. Run the following command: ```bash pod install ``` 1. Don’t forget to use the `.xcworkspace` file to open your project in Xcode, instead of the `.xcodeproj` file, from here on out. 1. In the future, to update to the latest version of the SDK, run: ```bash pod update StripePaymentsUI ``` #### Carthage 1. If you haven’t already, install the latest version of [Carthage](https://github.com/Carthage/Carthage#installing-carthage). 1. Add this line to your `Cartfile`: ```cartfile github "stripe/stripe-ios" ``` 1. Follow the [Carthage installation instructions](https://github.com/Carthage/Carthage#if-youre-building-for-ios-tvos-or-watchos). Make sure to embed all of the required frameworks listed [here](https://github.com/stripe/stripe-ios/tree/master/StripePaymentsUI/README.md#manual-linking). 1. In the future, to update to the latest version of the SDK, run the following command: ```bash carthage update stripe-ios --platform ios ``` #### Manual Framework 1. Head to our [GitHub releases page](https://github.com/stripe/stripe-ios/releases/latest) and download and unzip **Stripe.xcframework.zip**. 1. Drag **StripePaymentsUI.xcframework** to the **Embedded Binaries** section of the **General** settings in your Xcode project. Make sure to select **Copy items if needed**. 1. Repeat step 2 for all required frameworks listed [here](https://github.com/stripe/stripe-ios/tree/master/StripePaymentsUI/README.md#manual-linking). 1. In the future, to update to the latest version of our SDK, repeat steps 1–3. > For details on the latest SDK release and past versions, see the [Releases](https://github.com/stripe/stripe-ios/releases) page on GitHub. To receive notifications when a new release is published, [watch releases](https://help.github.com/en/articles/watching-and-unwatching-releases-for-a-repository#watching-releases-for-a-repository) for the repository. Configure the SDK with your Stripe [publishable key](https://dashboard.stripe.com/test/apikeys) on app start. This enables your app to make requests to the Stripe API. #### Swift ```swift import UIKitimportStripePaymentsUI @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {StripeAPI.defaultPublishableKey = "<>" // do any other necessary launch configuration return true } } ``` > Use your [test keys](https://docs.stripe.com/keys.md#obtain-api-keys) while you test and develop, and your [live mode](https://docs.stripe.com/keys.md#test-live-modes) keys when you publish your app. ## Collect card details [Client-side] Securely collect card information on the client with [STPPaymentCardTextField](https://stripe.dev/stripe-ios/stripe-payments-ui/Classes/STPPaymentCardTextField.html), a drop-in UI component provided by the SDK that collects the card number, expiration date, CVC, and postal code. ![](https://d37ugbyn3rpeym.cloudfront.net/docs/mobile/ios/card-field.mp4) Create an instance of the card component and a **Pay** button with the following code: #### Swift ```swift import UIKit import StripePaymentsUI class CheckoutViewController: UIViewController { lazy var cardTextField: STPPaymentCardTextField = { let cardTextField = STPPaymentCardTextField() return cardTextField }() lazy var payButton: UIButton = { let button = UIButton(type: .custom) button.layer.cornerRadius = 5 button.backgroundColor = .systemBlue button.titleLabel?.font = UIFont.systemFont(ofSize: 22) button.setTitle("Pay", for: .normal) button.addTarget(self, action: #selector(pay), for: .touchUpInside) return button }() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white let stackView = UIStackView(arrangedSubviews: [cardTextField, payButton]) stackView.axis = .vertical stackView.spacing = 20 stackView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(stackView) NSLayoutConstraint.activate([ stackView.leftAnchor.constraint(equalToSystemSpacingAfter: view.leftAnchor, multiplier: 2), view.rightAnchor.constraint(equalToSystemSpacingAfter: stackView.rightAnchor, multiplier: 2), stackView.topAnchor.constraint(equalToSystemSpacingBelow: view.safeAreaLayoutGuide.topAnchor, multiplier: 2), ]) } @objc func pay() { // ... } } ``` Run your app and make sure your checkout page shows the card component. When the customer taps **Pay**, call [createPaymentMethod](https://stripe.dev/stripe-ios/stripe-payments/Classes/STPAPIClient.html#/c:@CM@StripePayments@StripeCore@objc\(cs\)STPAPIClient\(im\)createPaymentMethodWithPayment:completion:) to collect the card details and create a [PaymentMethod](https://docs.stripe.com/api/payment_methods.md). Send the ID of the PaymentMethod to your server. #### Swift ```swift func pay() { // Create a PaymentMethod with the card text field's card details STPAPIClient.shared.createPaymentMethod(with: cardTextField.paymentMethodParams) { (paymentMethod, error) in guard let paymentMethod = paymentMethod else { // Display the error to the customer return } let paymentMethodID = paymentMethod.stripeId // Send paymentMethodID to your server for the next step } } ``` ## Make a payment [Server-side] Set up an endpoint on your server to receive the request from the client. Use the official libraries for access to the Stripe API from your server: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` Stripe uses a [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) object to represent your intent to collect payment from a customer, tracking charge attempts and payment state changes throughout the process. Create an HTTP endpoint to respond to the request from step 2. In that endpoint, you should decide how much to charge the customer. To create a payment, create a PaymentIntent using the PaymentMethod ID from step 2 with the following parameters: Always decide how much to charge on the server, a trusted environment, as opposed to the client. This prevents malicious customers from being able to choose their own prices. #### curl ```curl # Check the status of the PaymentIntent to make sure it succeeded curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -d amount=1099 \ -d currency=usd \ # A PaymentIntent can be confirmed some time after creation, # but here we want to confirm (collect payment) immediately. -d confirm=true \ -d payment_method="{{PAYMENT_METHOD_ID}}" \ # If the payment requires any follow-up actions from the # customer, like two-factor authentication, Stripe will error # and you will need to prompt them for a new payment method. -d error_on_requires_action=true ``` > If you set [error_on_requires_action](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-error_on_requires_action) to `true` when confirming a payment, Stripe automatically fails the payment if it requires two-factor authentication from the user. #### Payment Intents API response When you make a payment with the API, the response includes a status of the PaymentIntent. If the payment was successful, it will have a status of `succeeded`. ```json { "id": "pi_0FdpcX589O8KAxCGR6tGNyWj", "object": "payment_intent", "amount": 1099, "charges": { "object": "list", "data": [ { "id": "ch_GA9w4aF29fYajT", "object": "charge", "amount": 1099, "refunded": false, "status": "succeeded", } ] }, "client_secret": "pi_0FdpcX589O8KAxCGR6tGNyWj_secret_e00tjcVrSv2tjjufYqPNZBKZc", "currency": "usd", "last_payment_error": null,"status": "succeeded", } ``` If the payment is declined, the response includes the error code and error message. Here’s an example of a payment that failed because two-factor authentication was required for the card. ```json { "error": {"code": "authentication_required", "decline_code": "authentication_not_handled", "doc_url": "https://docs.stripe.com/error-codes#authentication-required", "message": "This payment required an authentication action to complete, but `error_on_requires_action` was set. When you're ready, you can upgrade your integration to handle actions at https://stripe.com/docs/payments/payment-intents/upgrade-to-handle-actions.", "payment_intent": { "id": "pi_1G8JtxDpqHItWkFAnB32FhtI", "object": "payment_intent", "amount": 1099, "status": "requires_payment_method", "last_payment_error": { "code": "authentication_required", "decline_code": "authentication_not_handled", "doc_url": "https://docs.stripe.com/error-codes#authentication-required", "message": "This payment required an authentication action to complete, but `error_on_requires_action` was set. When you're ready, you can upgrade your integration to handle actions at https://stripe.com/docs/payments/payment-intents/upgrade-to-handle-actions.", "type": "card_error" }, }, "type": "card_error" } } ``` ## Test the integration There are several test cards you can use in a testing environment to make sure this integration is ready. Use them with any CVC, postal code, and future expiration date. | Number | Description | | ---------------- | ----------------------------------------------------------------------------------------------------------------- | | 4242424242424242 | Succeeds and immediately processes the payment. | | 4000000000009995 | Always fails with a decline code of `insufficient_funds`. | | 4000002500003155 | Requires authentication, which in this integration will fail with a decline code of `authentication_not_handled`. | See the full list of [test cards](https://docs.stripe.com/testing.md). ## Upgrade your integration to handle card authentication Congratulations! You completed a payments integration for basic card payments. Note that this integration **declines cards that require authentication during payment**. If you start seeing payments in the Dashboard listed as `Failed`, then it’s time to [upgrade your integration](https://docs.stripe.com/payments/payment-intents/upgrade-to-handle-actions.md). Stripe’s global integration handles these payments instead of automatically declining them. # Android > This is a Android for when platform is android. View the full page at https://docs.stripe.com/payments/mobile/without-card-authentication?platform=android. This integration supports businesses accepting only US and Canadian cards. It’s simpler to build, but doesn’t scale to support a global customer base. ### How this integration works Banks in regions such as Europe and India often require two-factor authentication to confirm a purchase. If you primarily do business in the US and Canada, ignoring *card authentication* (A bank might require the customer to authenticate a card payment before processing. Implementation varies by bank but commonly consists of a customer entering in a security code sent to their phone) can simplify your integration, as banks rarely request it in these regions. When a bank requires authentication, this basic integration immediately declines the payment (similar to a card decline), instead of handling authentication to complete the payment asynchronously. The benefit is that the payment succeeds or declines immediately and payment confirmation happens on the server, so you can handle immediate post-payment actions without a *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests). ### How it compares to the global integration | Feature | This Integration | Global Integration | | -------------------------------------------------------------------- | ---------------- | ------------------ | | Custom payment form | ✔ | ✔ | | Sensitive data never touches your server | ✔ | ✔ | | Works for your US and Canada customers | ✔ | ✔ | | Declines payments with incorrect card details or no funds | ✔ | ✔ | | Declines payments with bank authentication requests | ✔ | | | Works for your global customers | | ✔ | | Automatically handles card payments that require bank authentication | | ✔ | | Webhooks recommended for post-payment tasks | | ✔ | | Easily scales to other payment methods (for example, bank debits) | | ✔ | Growing or global businesses should use Stripe’s [global integration](https://docs.stripe.com/payments/accept-a-payment.md) to support bank requests for two-factor authentication and allow customers to pay with more payment methods. ## Install the Stripe Android SDK [Client-side] Next, you need a Stripe account. [Register now](https://dashboard.stripe.com/register). The [Stripe Android SDK](https://github.com/stripe/stripe-android) is open source and [fully documented](https://stripe.dev/stripe-android/). To install the SDK, add `stripe-android` to the `dependencies` block of your [app/build.gradle](https://developer.android.com/studio/build/dependencies) file: #### Kotlin ```kotlin plugins { id("com.android.application") } android { ... } dependencies { // ... // Stripe Android SDK implementation("com.stripe:stripe-android:23.0.2") // Include the financial connections SDK to support US bank account as a payment method implementation("com.stripe:financial-connections:23.0.2") } ``` > For details on the latest SDK release and past versions, see the [Releases](https://github.com/stripe/stripe-android/releases) page on GitHub. To receive notifications when a new release is published, [watch releases for the repository](https://docs.github.com/en/github/managing-subscriptions-and-notifications-on-github/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository). Configure the SDK with your Stripe [publishable key](https://dashboard.stripe.com/apikeys) so that it can make requests to the Stripe API, such as in your `Application` subclass: #### Kotlin ```kotlin import com.stripe.android.PaymentConfiguration class MyApp : Application() { override fun onCreate() { super.onCreate() PaymentConfiguration.init( applicationContext, "<>" ) } } ``` > Use your [test keys](https://docs.stripe.com/keys.md#obtain-api-keys) while you test and develop, and your [live mode](https://docs.stripe.com/keys.md#test-live-modes) keys when you publish your app. ## Collect card details [Client-side] Securely collect card information on the client with [CardInputWidget](https://stripe.dev/stripe-android/payments-core/com.stripe.android.view/-card-input-widget/index.html), a drop-in UI component provided by the SDK that collects the card number, expiration date, CVC, and postal code. ![](https://d37ugbyn3rpeym.cloudfront.net/docs/mobile/android/android-card-input-widget-with-postal.mp4) Create an instance of the card component and a **Pay** button by adding the following to your checkout page’s layout: ```xml