Integrating Stripe Payments in Mobile Apps

Handling secure payments and payouts is a critical component of many modern apps, especially those offering paid services or marketplaces. One robust solution for this domain is Stripe. Below I’ll walk through advanced use cases such as setting up PaymentIntents, ephemeral keys, connected accounts, and some behind-the-scenes tasks with Firebase Cloud Functions—all of which I have personally coded in production for my projects.

Why Use Stripe?

  1. Security: Stripe offers top-tier PCI compliance and thorough documentation.
  2. Global Support: It handles multiple currencies and languages, simplifying worldwide deployment.
  3. Feature Breadth: Beyond simple charges, it supports advanced flows—like PaymentIntents, subscription management, Apple/Google Pay, connected accounts for payouts, etc.
  4. Developer-friendly: Clean REST APIs, webhooks, and official SDKs for popular platforms.

High-Level Architecture

My production systems typically revolve around these elements:

  1. Backend (e.g., Node.js, Firebase Functions, or custom server)

    • Securely stores Stripe API keys.
    • Creates ephemeral keys, PaymentIntents, and handles card confirmations or verification flows.
    • Manages connected accounts for multi-sided marketplaces (if your business includes payouts to external sellers).
    • Often includes scheduling modules to handle delayed transfers or refunds.
  2. Client-Side (Mobile App)

    • Initiates payment flows using ephemeral keys from the backend.
    • Displays payment sheets or minimal UI for card input.
    • Optionally integrates Google Pay or Apple Pay for frictionless checkout.
    • Subscribes to real-time push notifications for status updates.

A Note on Push Notifications

In my case, I also integrated FCM tokens and push-notification logic so that users and technicians receive timely payment or order updates. A specialized scheduling function scans Firestore for scheduled notifications, then sends them at the correct time. While this may not be strictly related to Stripe, it’s an essential part of delivering a cohesive mobile commerce experience.

Payment Flow in a Nutshell

A typical in-app payment flow might look like this:

  1. User Chooses Product: The user selects a product or a service in your app.
  2. Backend Request: The mobile client calls your backend with product details (price, currency, etc.).
  3. Server Creates PaymentIntent: The server uses the Stripe API to create a PaymentIntent with the desired amount and currency.
  4. Ephemeral Key Generation: The server also retrieves or creates a Stripe Customer and returns an EphemeralKey for the client’s current session.
  5. Display Payment UI: Your app either uses Stripe’s native Payment Sheet or a custom card entry form.
  6. Confirm Payment: The user enters payment details, Stripe processes them, and you receive a callback or webhook confirming success.

Example Pseudocode for Payment Creation

Below is a small snippet that reflects the approach I coded. On my backend, I store secrets as environment variables and then set up ephemeral keys accordingly:

const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);

async function createPaymentIntent({ amount, currency, customerId }) {
  // Validate amounts and currency server-side
  const paymentIntent = await stripe.paymentIntents.create({
    amount: amount, // e.g., 999 for $9.99
    currency: currency, // e.g., 'usd'
    customer: customerId, // existing or newly created customer
    payment_method_types: ["card"],
    // Additional configuration if needed
  });

  return paymentIntent.client_secret; // pass to the mobile app
}

I typically wrap this in a Firebase Function or similar cloud function to securely interface with the mobile client. My real implementation also incorporates ephemeral key generation to allow dynamic updates to PaymentIntents from the client side, plus a few checks to ensure consistent currency and correct environment usage (test vs. production).

Payouts with Connected Accounts

One advanced scenario is paying out to third parties—common in multi-vendor marketplaces or gig-economy apps. Stripe’s Connect flow allows you to:

  1. Create a connected account for each seller/technician.
  2. Collect payments from end customers.
  3. Programmatically distribute earnings to connected accounts.

Example Flow

  • User Orders a Service: Payment goes into your platform’s Stripe account.
  • Service Completed: The code calls stripe.transfers.create() or schedules future transfers to the connected account.
  • Notification: The user and service provider receive updates on transaction statuses.

I wrote a back-end routine that:

  1. Confirms a PaymentIntent is successful.
  2. Looks up the relevant connected account.
  3. Schedules or processes a transfer to that connected account—sometimes with a short delay, giving me time for validation.

A simplified version:

await stripe.transfers.create({
  amount: 2000, // e.g., 2000 = $20.00
  currency: "usd",
  destination: "acct_12345XYZ", // The connected account ID
});

Behind the scenes, it’s crucial to handle potential transfer failures, partial refunds, and edge cases like insufficient platform balance or incomplete KYC for the connected account. In my own code, I sometimes store these transfers in Firestore and run a scheduled function (Pub/Sub trigger) to finalize them once the funds fully settle.

Implementation Nuances

  1. Sensitive API Keys: Keep them strictly on the server side. Do not embed secret keys in mobile code.
  2. Ephemeral Keys: They are short-lived. Renew them if a user session is extended or re-authenticated.
  3. Webhooks: Stripe can push real-time event notifications (e.g., payment_intent.succeeded, payment_intent.payment_failed). Make sure to securely handle these events in your backend for accurate status updates.
  4. Testing: Stripe’s sandbox environment with test card numbers is extremely helpful. Properly integrate test keys first, then pivot to live keys when you’re ready.
  5. Multi-Environment Strategy: I maintain separate function entry points for test vs. production flows, ensuring that test transactions never pollute the real environment.

Interfacing with Firebase and Flutter

On the Flutter side, I rely on the flutter_stripe plugin to present the payment sheet or a custom card field. Meanwhile, my Firebase Functions handle ephemeral key creation, PaymentIntent creation, and additional push logic. This pattern ensures the app remains lightweight, with all critical secrets and logic secured in the cloud.

Conclusion

Stripe offers a powerful suite of payment APIs for mobile apps. Through PaymentIntents and ephemeral keys, you can securely accept one-time card payments, manage recurring billing, or even orchestrate multi-party payouts with Connect. The code I wrote for my own applications carefully orchestrates these building blocks—ensuring a frictionless user experience, robust error handling, and a secure payment pipeline.

Whether you need a quick “pay now” button or a sophisticated marketplace system, Stripe remains a reliable choice for in-app transactions. By focusing on well-structured backend endpoints, ephemeral key generation, and thoughtful error handling, you can confidently deploy production-grade payment solutions. My own additions—like scheduling push notifications and building advanced logic for delayed payouts—further showcase how integrating Stripe can be extended to meet real-world business complexities. If you’re building a mobile commerce or gig-economy platform, Stripe is definitely worth a serious look.




Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • What I Learned from “Infrastructure as Code - The Big Picture”
  • Leveling Up My Dev & PM Toolkit—24 Hours Inside a Full‑Cycle Game‑Development Bootcamp
  • Why I Studied Clinical Depression—and How It Shapes My Work and Leadership
  • Shipping Bug‑Free iOS Apps With a Lean SDET Strategy
  • Beyond the Buzzwords — A Field Manual for Functional, Integration, Smoke and Regression Testing