Skip to main content
RapidDev - Software Development Agency
flutterflow-tutorials

How to Create a Custom Payment Widget for Your FlutterFlow App

Integrate Stripe payments by creating a Cloud Function that generates a Stripe Checkout Session URL from cart items, then redirecting users to Stripe's hosted page via Launch URL. Build an order summary Component showing line items, subtotal, tax, and total before redirecting. Handle payment confirmation via a Stripe webhook Cloud Function that updates the orders collection in Firestore. Never put Stripe secret keys in client-side code.

What you'll learn

  • How to create a Cloud Function that generates a Stripe Checkout Session
  • How to build an order summary UI with line items and total calculation
  • How to handle payment confirmation via Stripe webhook
  • How to secure Stripe keys using server-side Cloud Functions only
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner6 min read30-40 minFlutterFlow Pro+ (Cloud Functions required)March 2026RapidDev Engineering Team
TL;DR

Integrate Stripe payments by creating a Cloud Function that generates a Stripe Checkout Session URL from cart items, then redirecting users to Stripe's hosted page via Launch URL. Build an order summary Component showing line items, subtotal, tax, and total before redirecting. Handle payment confirmation via a Stripe webhook Cloud Function that updates the orders collection in Firestore. Never put Stripe secret keys in client-side code.

Integrating Stripe Checkout Payments in FlutterFlow

Every monetized app needs payment processing. Stripe Checkout is the safest and fastest integration — Stripe handles the payment form, PCI compliance, and receipts. Your FlutterFlow app creates a session via Cloud Function and redirects users to Stripe's hosted page.

Prerequisites

  • FlutterFlow Pro plan or higher
  • A Stripe account with API keys (test mode)
  • A Cloud Function environment (Firebase Functions or Supabase Edge Functions)
  • A Firestore orders collection

Step-by-step guide

1

Set up Stripe API keys securely in Cloud Function environment variables

In your Cloud Function environment (Firebase or Supabase), add STRIPE_SECRET_KEY as an environment variable with your test mode secret key (sk_test_...). Never put this key in FlutterFlow API headers, Custom Code, or anywhere in client-side code. Also add STRIPE_WEBHOOK_SECRET for webhook signature verification. The publishable key (pk_test_...) can be used client-side if needed for Stripe Elements, but we use Checkout which does not need it.

Expected result: Stripe secret key is stored securely in server-side environment variables only.

2

Create the Cloud Function to generate a Stripe Checkout Session

Write a Cloud Function (HTTP triggered) that receives cart items (array of name, price, quantity) and userId. The function creates a Stripe Checkout Session: stripe.checkout.sessions.create({ line_items: cartItems.map(item => ({price_data: {currency: 'usd', product_data: {name: item.name}, unit_amount: item.price * 100}, quantity: item.quantity})), mode: 'payment', success_url: 'https://yourapp.com/order-confirmed?session_id={CHECKOUT_SESSION_ID}', cancel_url: 'https://yourapp.com/checkout', metadata: {userId} }). Return the session.url to the client.

create_checkout_session.js
1const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
2
3exports.createCheckoutSession = async (req, res) => {
4 const { items, userId } = req.body;
5 const session = await stripe.checkout.sessions.create({
6 line_items: items.map(item => ({
7 price_data: {
8 currency: 'usd',
9 product_data: { name: item.name },
10 unit_amount: Math.round(item.price * 100),
11 },
12 quantity: item.quantity,
13 })),
14 mode: 'payment',
15 success_url: `https://yourapp.com/order-confirmed?session_id={CHECKOUT_SESSION_ID}`,
16 cancel_url: 'https://yourapp.com/checkout',
17 metadata: { userId },
18 });
19 res.json({ url: session.url });
20};

Expected result: The Cloud Function returns a Stripe Checkout URL when called with cart items.

3

Build the order summary page with line items and total

Create a CheckoutPage. Display cart items in a ListView: each Row shows item name, quantity, and price. Below the list, add a Divider, then Rows for Subtotal (sum of item.price * quantity), Tax (subtotal * tax rate), and Total (subtotal + tax) in bold. Use a Custom Function to calculate these values from the cart items App State array. Add a 'Proceed to Payment' button at the bottom.

Expected result: An order summary showing all cart items with calculated subtotal, tax, and total.

4

Call the Cloud Function and redirect to Stripe Checkout

On the Proceed to Payment button tap, add an API Call action targeting your Cloud Function URL. Pass the cart items and userId in the request body. On success, extract the session.url from the response. Add a Launch URL action with the checkout URL. Stripe opens in the device browser where the user completes payment. On success, Stripe redirects to your success_url.

Expected result: Tapping the button calls the Cloud Function and redirects the user to Stripe's hosted checkout page.

5

Handle payment confirmation with a Stripe webhook Cloud Function

Create a second Cloud Function for the webhook endpoint. Stripe sends a POST to this URL on events like checkout.session.completed. Verify the webhook signature using stripe.webhooks.constructEvent(body, sig, STRIPE_WEBHOOK_SECRET). On verified checkout.session.completed event, extract the session metadata (userId) and create/update a document in the orders collection: userId, items, amount, paymentStatus: 'paid', stripeSessionId, paidAt. Register the webhook URL in Stripe Dashboard → Webhooks.

Expected result: Stripe notifies your Cloud Function when payment completes, which updates the Firestore orders collection.

Complete working example

create_checkout_session.js
1// Cloud Function: Create Stripe Checkout Session
2const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
3const admin = require('firebase-admin');
4admin.initializeApp();
5
6exports.createCheckoutSession = async (req, res) => {
7 try {
8 const { items, userId } = req.body;
9
10 if (!items || !items.length) {
11 return res.status(400).json({ error: 'No items provided' });
12 }
13
14 const session = await stripe.checkout.sessions.create({
15 line_items: items.map(item => ({
16 price_data: {
17 currency: 'usd',
18 product_data: { name: item.name },
19 unit_amount: Math.round(item.price * 100),
20 },
21 quantity: item.quantity,
22 })),
23 mode: 'payment',
24 success_url: `https://yourapp.com/confirmed?sid={CHECKOUT_SESSION_ID}`,
25 cancel_url: 'https://yourapp.com/checkout',
26 metadata: { userId },
27 });
28
29 res.json({ url: session.url, sessionId: session.id });
30 } catch (err) {
31 res.status(500).json({ error: err.message });
32 }
33};
34
35// Webhook Handler
36exports.stripeWebhook = async (req, res) => {
37 const sig = req.headers['stripe-signature'];
38 let event;
39 try {
40 event = stripe.webhooks.constructEvent(
41 req.rawBody, sig, process.env.STRIPE_WEBHOOK_SECRET
42 );
43 } catch (err) {
44 return res.status(400).send(`Webhook Error: ${err.message}`);
45 }
46
47 if (event.type === 'checkout.session.completed') {
48 const session = event.data.object;
49 await admin.firestore().collection('orders').add({
50 userId: session.metadata.userId,
51 amount: session.amount_total / 100,
52 currency: session.currency,
53 paymentStatus: 'paid',
54 stripeSessionId: session.id,
55 paidAt: admin.firestore.FieldValue.serverTimestamp(),
56 });
57 }
58 res.json({ received: true });
59};

Common mistakes when creating a Custom Payment Widget for Your FlutterFlow App

Why it's a problem: Putting the Stripe secret key in FlutterFlow API headers or Custom Code

How to avoid: Only store the Stripe secret key in Cloud Function environment variables. Client-side code should never see or transmit it.

Why it's a problem: Not verifying the webhook signature in the payment handler

How to avoid: Always verify the signature using stripe.webhooks.constructEvent() with the STRIPE_WEBHOOK_SECRET. Reject unverified events.

Why it's a problem: Calculating the payment amount on the client side

How to avoid: Calculate the final amount in the Cloud Function by looking up prices from your database, not by trusting client-sent prices.

Best practices

  • Never expose Stripe secret keys in client-side code — use Cloud Functions only
  • Always verify webhook signatures before processing payment events
  • Use test mode keys (sk_test_) during development and switch to live keys for production
  • Calculate prices server-side to prevent client-side manipulation
  • Store order data in Firestore with payment status for order management
  • Handle both success and cancel redirect URLs in the Checkout Session
  • Test with Stripe test card numbers (4242 4242 4242 4242) before going live

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I need to integrate Stripe Checkout in my FlutterFlow app. Write a Cloud Function that creates a Checkout Session from cart items, returns the URL, and handles the webhook for payment confirmation. Include order summary UI and Firestore order tracking.

FlutterFlow Prompt

Create a checkout page with a ListView of cart items showing name, quantity, and price. Add subtotal, tax, and total rows below with a Proceed to Payment button at the bottom.

Frequently asked questions

Can I embed Stripe's payment form directly in my app?

It is technically possible using Stripe Elements via a WebView Custom Widget, but Stripe Checkout (hosted page) is strongly recommended. It handles PCI compliance, 3D Secure, and all payment methods without you building a form.

How do I handle subscription payments?

Change the Checkout Session mode from 'payment' to 'subscription' and use Stripe Price IDs instead of inline price_data. Stripe handles recurring billing automatically.

What happens if the user closes the browser during payment?

The Checkout Session expires after 24 hours. No charge occurs. The cancel_url redirect only triggers if the user clicks 'Back'. Use webhooks as the source of truth for payment status, not redirect URLs.

Can I use PayPal instead of Stripe?

Stripe Checkout supports PayPal as a payment method. Enable it in your Stripe Dashboard under Payment Methods. Users see both card and PayPal options on the checkout page.

How do I issue refunds?

Use the Stripe Dashboard for manual refunds, or create a Cloud Function calling stripe.refunds.create({payment_intent: 'pi_xxx'}) for programmatic refunds triggered from your app.

Can RapidDev help with payment integration?

Yes. RapidDev can implement Stripe Checkout, subscription billing, webhook handlers, refund flows, and revenue dashboards for your FlutterFlow app.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.