DEV Community

Famitha M A
Famitha M A

Posted on

How to Add Payment Processing to Your React Native App (2026 Guide)

TL;DR

  • Decide first: digital goods (subscriptions, unlocks) or physical goods/services. That decision, not the SDK, determines what you're allowed to use.
  • Physical goods or services: Stripe + Apple Pay + Google Pay via @stripe/stripe-react-native.
  • Digital goods: native IAP through RevenueCat (react-native-purchases). US external web checkout and EU alternative processors are now legal, but IAP is still the safe global default.
  • The client integration is ~30% of the work. Webhooks, idempotency, and receipt validation are the other 70%.
  • Never test on a live card. Stripe test mode, Apple sandbox testers, and Play license testers cover every failure path.

Every founder building a React Native app hits the same wall: the demo works, users love it, and then someone asks, "So how do people actually pay?" What sounds like a one-afternoon integration turns into a week of reading Apple's guidelines, comparing Stripe versus RevenueCat, and arguing about whether your feature counts as "digital goods." The stack is not the hard part. The rules around the stack are.

The decision that comes before the code

Before you touch an SDK, answer one question: is what your app sells a digital good or a physical good? This is not a UX distinction. It's the rule Apple and Google use to decide whether you're allowed to use Stripe at all.

  • Digital goods: subscriptions, premium unlocks, in-game currency, credits, cloud storage, ad-removal. Apple and Google have historically required these to go through their native in-app purchase (IAP) system and taken a 15–30% commission (30% for large developers on standard transactions and year-one subscriptions, 15% after year two or under the Small Business Program).
  • Physical goods and real-world services: t-shirts, meal kits, ride-sharing, bookings. These have always been allowed to use third-party processors like Stripe or PayPal at standard card fees (~2.9% + $0.30).

For a long time, that was the whole story. Then Epic v. Apple in the US and the DMA in the EU cracked it open. As of late 2025, US developers can link out to an external web checkout for digital goods too (Apple still shows a warning sheet), and EU users on iOS can use fully alternative payment providers inside the app. Your practical options in 2026:

  • Physical/services app: use Stripe (or PayPal, Adyen, Braintree) natively in-app.
  • Digital goods, US-only: IAP is still simplest, but external web checkout via Stripe is now legal.
  • Digital goods, EU: alternative in-app payment providers are allowed.
  • Digital goods, global: use IAP for the safest cross-border coverage, or add a web-checkout fallback.

Pick the answer before you pick an SDK. Everything downstream depends on it.

Payment options compared

Option Best for Fees RN SDK App Store safe
Stripe Physical goods, services, B2B 2.9% + $0.30 @stripe/stripe-react-native Yes for physical, conditionally for digital
RevenueCat (wraps IAP) Subscriptions, digital goods Free < $2.5k MRR, then 1% react-native-purchases Yes (uses Apple/Google IAP)
Apple Pay / Google Pay Fast checkout on top of a processor Same as processor Built into Stripe SDK Yes for physical goods
PayPal / Braintree Markets where PayPal is preferred 2.9% + fixed community SDKs Same rules as Stripe
Native IAP directly Digital goods, no abstraction 15–30% Apple/Google expo-in-app-purchases / react-native-iap Yes (required by default)

For 90% of React Native apps in 2026, the answer is one of two combos: Stripe + Apple/Google Pay for physical goods or services, or RevenueCat on top of native IAP for subscriptions and digital unlocks. Let's build both.

Setting up Stripe

Stripe's official SDK handles PCI compliance for you (card details never touch your server), supports Apple Pay and Google Pay out of the box, and has first-class Expo support via a config plugin.

Step 1: install.

# Expo (recommended)
npx expo install @stripe/stripe-react-native

# Bare React Native
npm install @stripe/stripe-react-native
cd ios && pod install
Enter fullscreen mode Exit fullscreen mode

With Expo, add the plugin to app.json:

{
  "expo": {
    "plugins": [
      ["@stripe/stripe-react-native", {
        "merchantIdentifier": "merchant.com.yourapp",
        "enableGooglePay": true
      }]
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 2: wrap your app in StripeProvider.

import { StripeProvider } from '@stripe/stripe-react-native';

export default function App() {
  return (
    <StripeProvider
      publishableKey={process.env.EXPO_PUBLIC_STRIPE_PUBLISHABLE_KEY!}
      merchantIdentifier="merchant.com.yourapp"
      urlScheme="yourapp"
    >
      <RootNavigator />
    </StripeProvider>
  );
}
Enter fullscreen mode Exit fullscreen mode

The publishable key is safe to ship in the bundle. The secret key never leaves your backend.

Step 3: create a Payment Intent on your server. This is the piece a lot of tutorials skip. Stripe requires a server-side call so the amount is not manipulable from the client.

// Backend: /api/create-payment-intent
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

export async function POST(req: Request) {
  const { amount, currency = 'usd' } = await req.json();

  const paymentIntent = await stripe.paymentIntents.create({
    amount,
    currency,
    automatic_payment_methods: { enabled: true },
  });

  return Response.json({ clientSecret: paymentIntent.client_secret });
}
Enter fullscreen mode Exit fullscreen mode

Step 4: present the Payment Sheet. Stripe's pre-built, PCI-compliant UI supports cards, Apple Pay, Google Pay, and 40+ local payment methods depending on your country.

import { useStripe } from '@stripe/stripe-react-native';

function CheckoutScreen({ amount }: { amount: number }) {
  const { initPaymentSheet, presentPaymentSheet } = useStripe();

  async function pay() {
    const res = await fetch('/api/create-payment-intent', {
      method: 'POST',
      body: JSON.stringify({ amount }),
    });
    const { clientSecret } = await res.json();

    await initPaymentSheet({
      merchantDisplayName: 'Your App',
      paymentIntentClientSecret: clientSecret,
      applePay: { merchantCountryCode: 'US' },
      googlePay: { merchantCountryCode: 'US', testEnv: __DEV__ },
    });

    const { error } = await presentPaymentSheet();
    if (error) console.log(error.message);
    else Alert.alert('Payment complete');
  }

  return <Button title="Pay" onPress={pay} />;
}
Enter fullscreen mode Exit fullscreen mode

That's a functioning payment flow. Cards, Apple Pay, and Google Pay all light up in the same sheet with no extra integration work. If you'd rather not hand-wire this, RapidNative generates this exact stack (checkout screen, provider, payment intent endpoint, webhook handler) from a plain-English prompt, and the code exports to your own repo.

Handling in-app purchases for digital goods

Selling subscriptions, credits, or premium unlocks? You'll almost certainly go through StoreKit and Google Play Billing. Wiring these APIs directly is painful: different receipt formats, different renewal semantics, different edge cases for pauses, grace periods, refunds, and family sharing. Nearly every serious React Native app in 2026 uses RevenueCat to abstract this away.

Step 1: install.

npx expo install react-native-purchases
Enter fullscreen mode Exit fullscreen mode

Step 2: configure at app start.

import Purchases from 'react-native-purchases';

Purchases.configure({
  apiKey: Platform.OS === 'ios'
    ? process.env.EXPO_PUBLIC_RC_IOS_KEY!
    : process.env.EXPO_PUBLIC_RC_ANDROID_KEY!,
});
Enter fullscreen mode Exit fullscreen mode

Step 3: fetch offerings and present a paywall.

const offerings = await Purchases.getOfferings();
const monthly = offerings.current?.availablePackages.find(
  (p) => p.packageType === 'MONTHLY'
);

if (monthly) {
  const { customerInfo } = await Purchases.purchasePackage(monthly);
  const isPro = customerInfo.entitlements.active['pro'] !== undefined;
}
Enter fullscreen mode Exit fullscreen mode

RevenueCat handles receipt validation, cross-platform sync, subscription state, and analytics. You configure products in App Store Connect and Google Play Console, mirror them in RevenueCat, and let the SDK reconcile everything. The commission is still Apple's or Google's. RevenueCat itself is free below $2,500/month in tracked revenue, then 1%.

One warning: do not route digital-goods subscriptions through Stripe just to dodge the 30% cut globally. Apple will reject the app. The narrow exception (US external web-checkout linking) requires the StoreKit External Purchase Link entitlement plus an explicit user warning sheet. Worth doing at scale, not worth the review risk for a first launch.

Adding Apple Pay and Google Pay

Good news: if you integrated the Payment Sheet above, Apple Pay and Google Pay are already working. The sheet auto-detects device capability and shows the right button.

Two extra steps to get store-approved:

  1. Apple Pay: enable the Apple Pay capability in your Apple Developer account, create a merchant ID (merchant.com.yourapp), and add it to the Expo config plugin. Test on a real device: the simulator doesn't run Apple Pay.
  2. Google Pay: enable Google Pay in the Google Pay Business Console, register your app, and turn on the googlePay flag. Test on a real Android device with a saved card.

Both are free on top of Stripe, and they dramatically improve conversion. Stripe's own data shows one-tap payments increase mobile checkout completion by 60–70%. Treat them as table stakes, not features.

The backend half nobody talks about

Client-side integration is maybe 30% of a real payment system. The other 70% lives on your server:

  • Webhooks. Stripe (and RevenueCat) push events for every state change: payment_intent.succeeded, invoice.payment_failed, customer.subscription.updated. You need an endpoint that verifies signatures, reads the event, and updates your database. Skipping this is the number-one cause of "user paid but the app says they didn't" bugs.
  • Idempotency. Payment operations must be safe to retry. Use idempotency keys on Stripe requests and dedupe webhook events by ID. Networks fail; users retry; you cannot charge twice.
  • Receipt validation. For IAP, Apple and Google receipts must be validated server-side. RevenueCat does this for you. Rolling your own? The App Store Server API docs are your source of truth.
  • Subscription lifecycle. Grace periods, billing retries, pauses, refunds, and family sharing mean "active" is not a single boolean. Model it as state, not a flag.
  • Compliance. Even with Stripe absorbing PCI scope, you still need Strong Customer Authentication (SCA) in the EU/UK. The Payment Sheet handles the 3DS challenge automatically, but your backend must handle the requires_action state.

This is where most hand-rolled payment integrations quietly leak revenue.

Testing payments safely

Never run a first payment against a live card. Both Stripe and RevenueCat have first-class sandbox modes:

  • Stripe test mode: use test API keys and Stripe's published test cards. 4242 4242 4242 4242 for success, 4000 0000 0000 9995 for insufficient funds, 4000 0025 0000 3155 to trigger 3D Secure. Run every failure branch before switching to live keys.
  • Apple sandbox: create a Sandbox Tester in App Store Connect, sign into it on your test device under Settings → App Store → Sandbox Account, then run TestFlight or a dev build. Sandbox subscriptions renew every 5 minutes instead of monthly, which is how you test renewals in a reasonable amount of time.
  • Google Play: add license testers in the Play Console, upload to an internal test track, and purchase without being charged.
  • Real devices: Apple Pay and Google Pay don't work in simulators. Test the payment sheet the way an end user actually sees it.

Write end-to-end tests for the happy path, the SCA path, the network-failure path, the webhook-late path, and the cancellation path. If those five work, you have a payment system. If any of them fails silently, you have a support ticket queue.

Ship payments, not payment bugs

Adding payment processing to a React Native app in 2026 is a solved problem, but only if you make the digital-vs-physical decision first, treat webhooks as first-class code, and test the failure paths as hard as the happy path. Stripe + Apple Pay + Google Pay covers most physical-goods and services apps. RevenueCat covers most subscription apps. The rest is discipline: idempotency, sandbox testing, and a webhook handler you actually trust.

What are you wiring payments into right now? Drop a comment with your stack (and any App Store review horror stories).

Top comments (0)