# Accept in-app payments Build a customized payments integration in your iOS, Android, or React Native app using the Payment Element. The Payment Element is a customizable component that renders a list of payment methods that you can add into any screen in your app. When customers interact with payment methods in the list, the component opens individual bottom sheets to collect payment details. > #### Accounts v2 API support > > The Payment Sheet doesn’t support *customer-configured Accounts* (Account configurations represent role-based functionality that you can enable for accounts, such as merchant, customer, or recipient). It only supports `Customer` objects. # Accept a payment and save the payment method Use the [Payment Intents API](https://docs.stripe.com/api/payment_intents.md) to save payment details from a purchase. There are several use cases: - Charge a customer for an e-commerce order and store the details for future purchases. - Initiate the first payment of a series of recurring payments. - Charge a deposit and store the details to charge the full amount later. > #### Card-present transactions > > Card-present transactions, such as payments through Stripe Terminal, use a different process for saving the payment method. For details, see [the Terminal documentation](https://docs.stripe.com/terminal/features/saving-payment-details/save-after-payment.md). ## Compliance You’re responsible for your compliance with all applicable laws, regulations, and network rules when saving a customer’s payment details for future use, such as displaying a customer’s payment method to them in the checkout flow for a future purchase or charging them when they’re not actively using your website or app. Before saving or charging a customer’s payment method, make sure you: - Add terms to your website or app that state how you plan to save payment method details, such as: - The customer’s agreement allowing you to initiate a payment or a series of payments on their behalf for specified transactions. - The anticipated timing and frequency of payments (for example, if the charges are for scheduled installments, subscription payments, or unscheduled top-ups). - How you determine the payment amount. - Your cancellation policy, if the payment method is for a subscription service. - Use a saved payment method for only the purpose stated in your terms. - Collect explicit consent from the customer for this specific use. For example, include a "Save my payment method for future checkbox. - Keep a record of your customer’s written agreement to your terms. ## Set up Stripe [Server-side] [Client-side] ### Server-side This integration requires endpoints on your server that talk to the Stripe API. Use our 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' ``` ### Client-side The [React Native SDK](https://github.com/stripe/stripe-react-native) is open source and fully documented. Internally, it uses the [native iOS](https://github.com/stripe/stripe-ios) and [Android](https://github.com/stripe/stripe-android) SDKs. To install Stripe’s React Native SDK, run one of the following commands in your project’s directory (depending on which package manager you use): #### yarn ```bash yarn add @stripe/stripe-react-native ``` #### npm ```bash npm install @stripe/stripe-react-native ``` Next, install some other necessary dependencies: - For iOS, go to the **ios** directory and run `pod install` to ensure that you also install the required native dependencies. - For Android, there are no more dependencies to install. > We recommend following the [official TypeScript guide](https://reactnative.dev/docs/typescript#adding-typescript-to-an-existing-project) to add TypeScript support. ### Stripe initialization To initialize Stripe in your React Native app, either wrap your payment screen with the `StripeProvider` component, or use the `initStripe` initialization method. Only the API [publishable key](https://docs.stripe.com/keys.md#obtain-api-keys) in `publishableKey` is required. The following example shows how to initialize Stripe using the `StripeProvider` component. ```jsx import { useState, useEffect } from 'react'; import { StripeProvider } from '@stripe/stripe-react-native'; function App() { const [publishableKey, setPublishableKey] = useState(''); const fetchPublishableKey = async () => { const key = await fetchKey(); // fetch key from your server here setPublishableKey(key); }; useEffect(() => { fetchPublishableKey(); }, []); return ( {/* Your app code here */} ); } ``` > Use your API [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. ## Enable payment methods View your [payment methods settings](https://dashboard.stripe.com/settings/payment_methods) and enable the payment methods you want to support. You need at least one payment method enabled to create a *PaymentIntent* (The Payment Intents API tracks the lifecycle of a customer checkout flow and triggers additional authentication steps when required by regulatory mandates, custom Radar fraud rules, or redirect-based payment methods). By default, Stripe enables cards and other prevalent payment methods that can help you reach more customers, but we recommend turning on additional payment methods that are relevant for your business and customers. See [Payment method support](https://docs.stripe.com/payments/payment-methods/payment-method-support.md) for product and payment method support, and our [pricing page](https://stripe.com/pricing/local-payment-methods) for fees. ## Collect payment details [Client-side] ### Initialize the Embedded Payment Element Use the `useEmbeddedPaymentElement` hook to create and display the Embedded Payment Element in your React Native app. This hook requires two configuration objects: - `EmbeddedPaymentElementConfiguration`: General settings (for example, `returnURL`). - `IntentConfiguration`: Payment-specific details (for example, amount, currency, and a `confirmationTokenConfirmHandler` callback). The hook returns an object with the `embeddedPaymentElementView` React component and other helper methods. For a full list of options and return values, see the [Stripe React Native SDK docs](https://stripe.dev/stripe-react-native/api-reference/interfaces/UseEmbeddedPaymentElementResult.html). > Implementing `confirmationTokenConfirmHandler` is required, but for this step you can leave it as an empty function and implement it later. ```jsx import { useState, useCallback, useEffect } from 'react'; import { useEmbeddedPaymentElement, IntentConfiguration, EmbeddedPaymentElementConfiguration, IntentCreationCallbackParams, } from '@stripe/stripe-react-native'; function MyCheckoutComponent() { const [intentConfig, setIntentConfig] = useState(null); const [elementConfig, setElementConfig] = useState(null); const initialize = useCallback(() => { const newIntentConfig: IntentConfiguration = { mode: { amount: 1099, currencyCode: 'USD', setupFutureUse: 'OffSession', }, confirmationTokenConfirmHandler: async ( confirmationToken, callback: (params: IntentCreationCallbackParams) => void ) => { // You'll implement this in the "Confirm the payment" section below }, }; const newElementConfig: EmbeddedPaymentElementConfiguration = { merchantDisplayName: 'Your Business Name', returnURL: 'your-app://stripe-redirect', }; setIntentConfig(newIntentConfig); setElementConfig(newElementConfig); }, []); const { embeddedPaymentElementView, paymentOption, confirm, update, clearPaymentOption, loadingError, isLoaded, } = useEmbeddedPaymentElement( intentConfig!, elementConfig! ); useEffect(() => { initialize(); }, [initialize]); } ``` ### Add the Embedded Payment Element view After the `useEmbeddedPaymentElement` hook has successfully initialized, include the `embeddedPaymentElementView` in your component to display the Embedded Payment Element in your checkout UI. > If `isLoaded` never becomes `true`, verify that `embeddedPaymentElementView` remains in your component’s render tree at all times. On Android, the native view must be mounted for initialization to complete. Use opacity to control visibility instead of conditionally rendering the view, as shown in the example below. ```jsx import { View, Text, ActivityIndicator } from 'react-native'; function MyCheckoutComponent() { // Other component code remains the same return ( {/* Handle loading errors through the loadingError property */} {loadingError && ( Failed to load payment form: {loadingError.message || String(loadingError)} )} {/* Keep the view in the render tree for Android, control visibility with opacity */} {embeddedPaymentElementView} {/* Show loading indicator while the view is loading */} {!loadingError && !isLoaded && ( )} ); } ``` Now you can run your app and see the Embedded Mobile Payment Element. ### (Optional) Display the selected payment option The `useEmbeddedPaymentElement` hook provides a `paymentOption` property in its return object. You can use this to access details about the customer’s selected payment option, such as a label (for example, “····4242”), image (for example, a VISA logo), or billing details to display in your UI. The `paymentOption` property is reactive, meaning it automatically updates when the selected payment option changes. You don’t need to implement a separate delegate method. Instead, you can use this property directly in your component, and React re-renders the component whenever the `paymentOption` changes. ```jsx import { View, Text, Image } from 'react-native'; function MyCheckoutComponent() { // Other component code remains the same return ( // Other component code remains the same // Display the currently selected payment option (label and image) {paymentOption?.image && ( )} Selected: {paymentOption?.label ?? 'None'} ); } ``` ### (Optional) Update payment details As the customer performs actions that change the payment details (for example, applying a discount code), update the `EmbeddedPaymentElement` instance to reflect the new values by calling the update method. Some payment methods, like Apple Pay and Google Pay, show the amount in the UI, so make sure it’s always accurate and up to date. When the update call completes, update your UI. The update call might change the customer’s currently selected payment option. > Always use `await` when calling the `update` API to ensure loading states are properly sequenced. Without `await`, the loading indicator might disappear before the update completes. ```jsx import { useState, useCallback } from 'react'; import { View, Button, ActivityIndicator } from 'react-native'; function MyCheckoutComponent() { // Other component code remains the same const [isUpdating, setIsUpdating] = useState(false); const handleUpdate = useCallback(async () => { // Create a new IntentConfiguration object with updated values const updatedIntentConfig: IntentConfiguration = { ...intentConfig!, mode: { amount: 999, // Updated amount after applying discount code currencyCode: 'USD', setupFutureUse: 'OffSession', }, }; setIsUpdating(true); try { await update(updatedIntentConfig); } catch (error) { // Handle any unexpected errors console.error('Unexpected error during update:', error); } finally { setIsUpdating(false); } }, [intentConfig, update]); // Example of how to use the handleUpdate function const applyDiscountCode = useCallback(async (discountCode: string) => { // Validate discount code with your server try { const response = await fetch('https://your-server.com/apply-discount', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ discountCode }), }); if (response.ok) { // Update the intent configuration with the new amount await handleUpdate(); } } catch (error) { console.error('Failed to apply discount:', error); } }, [handleUpdate]); return ( {/* Hide view and show loading indicator during update */} {embeddedPaymentElementView} {isUpdating && ( )}