Stripe in React Native: Payment Sheet, Apple Pay and Google Pay
Accept payments in React Native with Stripe: Payment Sheet setup in Expo, the server side, Apple Pay and Google Pay, webhooks, and when Stripe is allowed.
Full-Stack, Mobile & AI Engineer
Stripe is the default way many teams take card payments, and its React Native SDK has become good enough that a secure, polished checkout takes a day or two instead of a week. The parts that still trip teams up are not the UI: they're the server side, webhooks, and knowing when Apple and Google require their own billing instead.
This guide shows how to add Stripe to a React Native app with Expo in 2026: the Payment Sheet, the server endpoint it needs, Apple Pay and Google Pay, webhooks that confirm payment, and the store rules that decide whether you can use Stripe at all.
Key takeaways
- Use Stripe's Payment Sheet (
@stripe/stripe-react-native) for a prebuilt, secure checkout that supports cards, Apple Pay and Google Pay. - Your server creates the PaymentIntent and sends the app a client secret. The app never decides the amount.
- Webhooks confirm the payment. Fulfil orders on
payment_intent.succeeded, not when the sheet closes. - Stripe is allowed for physical goods and real-world services, and for some cases like person-to-person services. Digital content in iOS apps generally needs Apple's in-app purchase, apart from US-storefront external links.
- Standard US card pricing is 2.9% + 30¢ per successful charge; check Stripe's pricing page for your country.
How Stripe works in a mobile app
Stripe never trusts the app with the important decisions. Your server creates a PaymentIntent for the amount, the app shows Stripe's Payment Sheet so card details go straight to Stripe (never to your servers), and Stripe tells your server the outcome through a webhook. Stripe also offers a lower-level CardField for a custom card form, but the Payment Sheet handles cards, wallets, saved methods and 3D Secure for you, which is why it's the default choice. It works in Expo with a development build.
Step 1: install and configure
npx expo install @stripe/stripe-react-nativeAdd the config plugin in app.json so the native setup for Apple Pay and Google Pay is applied at build time:
{
"expo": {
"plugins": [
[
"@stripe/stripe-react-native",
{ "merchantIdentifier": "merchant.com.yourcompany.app", "enableGooglePay": true }
]
]
}
}Wrap your app with the provider:
import { StripeProvider } from "@stripe/stripe-react-native";
export default function App() {
return (
<StripeProvider
publishableKey={STRIPE_PUBLISHABLE_KEY}
merchantIdentifier="merchant.com.yourcompany.app"
urlScheme="yourapp"
>
<Root />
</StripeProvider>
);
}Because the SDK includes native code, you'll run it in a development build, not Expo Go.
Step 2: the server endpoint
Your backend creates the customer, an ephemeral key and the PaymentIntent, using your secret key, which never goes in the app:
// POST /payment-sheet (Node, with the official stripe package)
const customer = await stripe.customers.create();
const ephemeralKey = await stripe.ephemeralKeys.create(
{ customer: customer.id },
{ apiVersion: STRIPE_API_VERSION } // the API version your mobile SDK expects
);
const paymentIntent = await stripe.paymentIntents.create({
amount: order.totalInCents, // calculated on the server from the order
currency: "usd",
customer: customer.id,
automatic_payment_methods: { enabled: true },
metadata: { orderId: order.id },
});
res.json({
paymentIntent: paymentIntent.client_secret,
ephemeralKey: ephemeralKey.secret,
customer: customer.id,
});In a real app you'd reuse the Stripe customer for a signed-in user rather than creating one each time, so saved cards appear on their next purchase.
Step 3: present the Payment Sheet
import { useStripe } from "@stripe/stripe-react-native";
export function useCheckout() {
const { initPaymentSheet, presentPaymentSheet } = useStripe();
return async function checkout(orderId: string) {
const { paymentIntent, ephemeralKey, customer } = await api.post("/payment-sheet", { orderId });
const { error: initError } = await initPaymentSheet({
merchantDisplayName: "Your Studio",
customerId: customer,
customerEphemeralKeySecret: ephemeralKey,
paymentIntentClientSecret: paymentIntent,
applePay: { merchantCountryCode: "US" },
googlePay: { merchantCountryCode: "US", testEnv: __DEV__ },
returnURL: "yourapp://stripe-redirect",
});
if (initError) throw initError;
const { error } = await presentPaymentSheet();
if (error) return { ok: false, reason: error.code }; // includes "Canceled"
return { ok: true }; // now confirm with the server
};
}When presentPaymentSheet resolves without an error, the payment has been submitted. Still check the order's status from your server before showing a final confirmation.
Step 4: confirm with webhooks
Stripe sends events to a webhook endpoint you register. Fulfil the order there:
payment_intent.succeeded: mark the order paid, send the receipt, book the class.payment_intent.payment_failed: record the failure and let the user retry.
Verify each webhook's signature with your endpoint secret, store event IDs so a repeated event is ignored, and respond quickly, doing slow work in a background job.
From the field: On MOVE, a subscription fitness platform with 100K+ active users, I built the mobile app, the API layer, payments and analytics, with Stripe and RevenueCat in the stack. Across 12+ apps with payments, the pattern doesn't change: the app starts the payment, the server decides the amount, and a verified webhook decides whether it happened.
Apple Pay and Google Pay
The Payment Sheet shows Apple Pay and Google Pay automatically when you pass the applePay and googlePay options and the device supports them. For Apple Pay you also need a merchant identifier in your Apple Developer account and a payment processing certificate, which Stripe's dashboard helps you create. Google Pay needs enableGooglePay in the plugin and a production review in the Google Pay console before going live.
Saved cards and repeat payments
For apps where people pay more than once (bookings, deliveries, top-ups), saving a card makes the second payment a single tap:
- Reuse one Stripe customer per signed-in user, stored against your user record, instead of creating a new customer for every checkout.
- Pass that customer and an ephemeral key to the Payment Sheet, and it shows the user's saved cards automatically.
- Use a SetupIntent when you want to save a card without charging it, for example during onboarding or before a free trial of a real-world service.
Memberships and recurring charges
For recurring payments that are allowed outside in-app purchase, such as gym memberships or service subscriptions, use Stripe Billing on the server: create a subscription for the customer, and let Stripe handle renewals, retries and invoices. Your app only collects the payment method. Listen for invoice events (invoice.paid, invoice.payment_failed) in your webhook to extend or pause access, and send users to a page where they can update their card when a renewal fails.
Testing before you go live
- Use test-mode keys in development and preview builds, and live keys only in production.
- Use Stripe's test cards:
4242 4242 4242 4242succeeds, and4000 0025 0000 3155requires 3D Secure authentication, which is the flow most likely to break in a mobile app. - Forward webhooks to your machine with the Stripe CLI (
stripe listen --forward-to localhost:3000/webhooks) so you can test fulfilment locally. - Test cancellations and failures: close the sheet midway, decline a card, and lose connection after paying, then confirm your server still ends up with the right order status.
When you're allowed to use Stripe in an app
| What you sell | iOS | Android |
|---|---|---|
| Physical goods (products shipped to people) | Stripe allowed | Stripe allowed |
| Real-world services (classes, bookings, rides) | Stripe allowed | Stripe allowed |
| Real-time person-to-person services (tutoring, training, consultations) | Stripe allowed (guideline 3.1.3(d)) | Check Google's payments policy |
| Digital content or features used in the app | In-app purchase required (US storefront may link out) | Google Play Billing required (alternatives in some regions) |
FAQ
How do I accept payments in a React Native app?
For physical goods and services, use a payment provider SDK such as Stripe's: your server creates a PaymentIntent, the app shows the Payment Sheet, and a webhook confirms success. For digital content, use Apple's and Google's in-app purchase systems, often through a service like RevenueCat.
Does Stripe's React Native SDK work with Expo?
Yes. Install @stripe/stripe-react-native with npx expo install, add its config plugin for Apple Pay and Google Pay, and run the app in a development build. It isn't available in Expo Go because it includes native code.
How much does Stripe charge?
Stripe's standard US pricing for domestic cards is 2.9% plus 30¢ per successful transaction, with different rates in other countries and for international cards. Check Stripe's pricing page for your account's country.
Can I use Stripe instead of Apple in-app purchase?
Only for what Apple allows: physical goods, services consumed outside the app, certain person-to-person services, and, on the US storefront, links to external purchases. Digital content and features used inside an iOS app generally require Apple's in-app purchase.
Next steps
If you're adding payments to a React Native app and want the client, server and webhooks done right first time, I can build the whole flow and test it end to end. Get in touch, or see how I work as a React Native developer.
Sources
- Accept in-app payments (React Native), Stripe
- Stripe React Native SDK, GitHub
- Receive Stripe events in your webhook endpoint, Stripe
- Stripe pricing, Stripe
- App Review Guidelines (3.1), Apple
Related
KNET Payment Integration for Mobile Apps: A Practical Guide
How KNET payment gateway integration works in mobile apps: bank vs payment provider, the hosted-page flow in React Native, verification and testing.
In-App Purchases in React Native: RevenueCat vs Going Direct
React Native in-app purchases in 2026: RevenueCat vs expo-iap and react-native-iap, server validation, Android acknowledgement and when each choice wins.
RevenueCat with Expo: Paywalls, Entitlements and Webhooks
A practical RevenueCat guide for Expo apps: setup, offerings, purchases, entitlements, paywalls, restores, backend webhooks, and RevenueCat vs Stripe.
