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

How to Integrate Cryptocurrency Payments in FlutterFlow

Accept cryptocurrency payments in FlutterFlow using Coinbase Commerce — a Cloud Function creates a charge via the Coinbase Commerce API, returns a hosted checkout URL, and your app launches it. Coinbase handles BTC, ETH, USDC, LTC, and 10+ other currencies. When payment is confirmed, Coinbase sends a webhook to a second Cloud Function that updates the order status in Firestore. Always wait for the charge:confirmed webhook (at least 1 blockchain confirmation) before fulfilling the order.

What you'll learn

  • How to create a Coinbase Commerce charge via a Cloud Function and launch the hosted crypto checkout
  • How to receive and verify Coinbase Commerce webhooks to confirm payment and update order status
  • How to display payment status with transaction hash and blockchain explorer link in FlutterFlow
  • When to use Coinbase Commerce (hosted, easy) versus direct Web3 wallet integration (advanced)
  • Why waiting for at least one blockchain confirmation before fulfilling orders is critical
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner11 min read45-60 minFlutterFlow Free+March 2026RapidDev Engineering Team
TL;DR

Accept cryptocurrency payments in FlutterFlow using Coinbase Commerce — a Cloud Function creates a charge via the Coinbase Commerce API, returns a hosted checkout URL, and your app launches it. Coinbase handles BTC, ETH, USDC, LTC, and 10+ other currencies. When payment is confirmed, Coinbase sends a webhook to a second Cloud Function that updates the order status in Firestore. Always wait for the charge:confirmed webhook (at least 1 blockchain confirmation) before fulfilling the order.

Coinbase Commerce hosted checkout for Bitcoin, ETH, and USDC payments

Accepting cryptocurrency payments in FlutterFlow is simpler than most developers expect. Coinbase Commerce provides a hosted payment page that handles wallet connection, blockchain transaction monitoring, and confirmation — similar to how Stripe Checkout handles credit cards. Your FlutterFlow app calls a Cloud Function to create a payment charge, receives a hosted checkout URL, and launches it. Coinbase handles the rest. This tutorial covers the complete crypto payment flow: creating charges, launching the hosted checkout, handling webhook confirmations, and displaying transaction status. The advanced Web3 wallet-to-wallet approach (using the web3dart package) is also introduced for developers who need custom in-app payment UI.

Prerequisites

  • A Coinbase Commerce account at commerce.coinbase.com (free to create, requires business verification for live payments)
  • A Firebase project connected to FlutterFlow with Blaze plan for Cloud Functions
  • An existing checkout or purchase flow in your FlutterFlow app where you want to add crypto payment as an option
  • Basic understanding of Firebase Cloud Functions and Firestore

Step-by-step guide

1

Set up Coinbase Commerce and get your API key and webhook secret

Sign up at commerce.coinbase.com. After account setup, go to Settings → Security. Generate a new API Key — copy it securely, you will only see it once. Also copy the Webhook Secret displayed on the same page — this is used to verify that webhook requests actually come from Coinbase and not a third party. In Firebase Secret Manager (Google Cloud Console → Secret Manager), create two secrets: COINBASE_COMMERCE_API_KEY and COINBASE_COMMERCE_WEBHOOK_SECRET. Store the respective values. Never put these in FlutterFlow code or API Manager headers. Back in Coinbase Commerce, go to Settings → Notifications and add your webhook endpoint URL — you will create this Cloud Function in Step 3 and add the URL here. The webhook URL format will be: https://us-central1-your-project.cloudfunctions.net/coinbaseWebhook.

Expected result: Coinbase Commerce account has an API key and webhook secret stored in Firebase Secret Manager. Webhook endpoint URL is configured in Coinbase Commerce settings.

2

Create the Cloud Function to generate Coinbase Commerce charges

Create an HTTPS Cloud Function named createCryptoCharge. It receives a POST request from FlutterFlow with amount, currency (USD), productName, orderId, and userId. Using the Coinbase Commerce API, call POST https://api.commerce.coinbase.com/charges with headers X-CC-Api-Key and X-CC-Version: 2018-03-22. The request body includes name (product name), description, pricing_type: fixed_price, local_price: {amount, currency: USD}, and metadata: {orderId, userId}. The API returns a charge object with a hosted_url — return this URL to FlutterFlow. Also write an order document to Firestore: orders/{orderId} with status 'pending_payment', chargeCode, chargeId, amount, userId, createdAt. FlutterFlow will then launch the hosted_url using the Launch URL action.

create_crypto_charge.js
1const functions = require('firebase-functions');
2const { defineSecret } = require('firebase-functions/params');
3const admin = require('firebase-admin');
4const axios = require('axios');
5
6if (!admin.apps.length) admin.initializeApp();
7const ccApiKey = defineSecret('COINBASE_COMMERCE_API_KEY');
8
9exports.createCryptoCharge = functions
10 .runWith({ secrets: ['COINBASE_COMMERCE_API_KEY'] })
11 .https.onCall(async (data, context) => {
12 if (!context.auth) throw new functions.https.HttpsError('unauthenticated', 'Login required');
13
14 const { amount, productName, orderId } = data;
15 const response = await axios.post(
16 'https://api.commerce.coinbase.com/charges',
17 {
18 name: productName,
19 description: `Payment for ${productName}`,
20 pricing_type: 'fixed_price',
21 local_price: { amount: String(amount), currency: 'USD' },
22 metadata: { orderId, userId: context.auth.uid }
23 },
24 {
25 headers: {
26 'X-CC-Api-Key': ccApiKey.value(),
27 'X-CC-Version': '2018-03-22',
28 'Content-Type': 'application/json'
29 }
30 }
31 );
32
33 const charge = response.data.data;
34 await admin.firestore().collection('orders').doc(orderId).set({
35 chargeCode: charge.code,
36 chargeId: charge.id,
37 hostedUrl: charge.hosted_url,
38 status: 'pending_payment',
39 amount,
40 userId: context.auth.uid,
41 createdAt: admin.firestore.FieldValue.serverTimestamp()
42 }, { merge: true });
43
44 return { hostedUrl: charge.hosted_url, chargeCode: charge.code };
45 });

Expected result: Cloud Function is deployed and callable from FlutterFlow. Calling it returns a Coinbase Commerce hosted checkout URL and creates a pending order in Firestore.

3

Wire the charge creation to a Pay with Crypto button in FlutterFlow

On your checkout or product page in FlutterFlow, add a Pay with Crypto button (use a Bitcoin or wallet icon from the icon library). In the button's Action Flow: first call the createCryptoCharge Cloud Function (Backend Call → Cloud Function → createCryptoCharge) with the amount from page state and a generated orderId (use the current timestamp as a simple unique ID). Store the returned hostedUrl in a Page State variable cryptoCheckoutUrl. Then add a Launch URL action using the cryptoCheckoutUrl variable. On the device, this opens Coinbase's hosted checkout page in the device's default browser. The hosted page shows a payment address and QR code for the user to send cryptocurrency. After payment, Coinbase redirects back to your app using the redirect_url if you configure one in the charge creation request.

Expected result: Tapping Pay with Crypto button creates a charge and opens the Coinbase Commerce hosted checkout page where the user can pay with any supported cryptocurrency.

4

Handle Coinbase Commerce webhooks to confirm payment

Create a second Cloud Function named coinbaseWebhook as an HTTP trigger. This function receives POST requests from Coinbase when payment status changes. Coinbase sends events: charge:pending (transaction detected on blockchain), charge:confirmed (enough confirmations, payment complete), charge:failed (transaction failed or expired). In the webhook function, verify the request signature: compute HMAC-SHA256 of the raw request body using the COINBASE_COMMERCE_WEBHOOK_SECRET, compare to the X-CC-Webhook-Signature header. If signatures don't match, return 400. If the event type is charge:confirmed, update the Firestore order: set status to 'paid', add txHash (from event.data.payments[0].transaction_id), network, and confirmedAt. If charge:failed, set status to 'payment_failed'.

coinbase_webhook.js
1const functions = require('firebase-functions');
2const { defineSecret } = require('firebase-functions/params');
3const admin = require('firebase-admin');
4const crypto = require('crypto');
5
6const webhookSecret = defineSecret('COINBASE_COMMERCE_WEBHOOK_SECRET');
7
8exports.coinbaseWebhook = functions
9 .runWith({ secrets: ['COINBASE_COMMERCE_WEBHOOK_SECRET'] })
10 .https.onRequest(async (req, res) => {
11 const signature = req.headers['x-cc-webhook-signature'];
12 const rawBody = req.rawBody;
13 const expected = crypto
14 .createHmac('sha256', webhookSecret.value())
15 .update(rawBody)
16 .digest('hex');
17
18 if (signature !== expected) {
19 return res.status(400).send('Invalid signature');
20 }
21
22 const event = req.body;
23 const orderId = event.data?.metadata?.orderId;
24
25 if (event.type === 'charge:confirmed' && orderId) {
26 const payment = event.data.payments?.[0];
27 await admin.firestore().collection('orders').doc(orderId).update({
28 status: 'paid',
29 txHash: payment?.transaction_id || null,
30 network: payment?.network || null,
31 confirmedAt: admin.firestore.FieldValue.serverTimestamp()
32 });
33 } else if (event.type === 'charge:failed' && orderId) {
34 await admin.firestore().collection('orders').doc(orderId).update({
35 status: 'payment_failed'
36 });
37 }
38 return res.status(200).send('OK');
39 });

Expected result: Webhook function receives Coinbase events, verifies signatures, and updates order status in Firestore. FlutterFlow's real-time listener shows payment confirmation within seconds.

5

Display payment status with transaction hash and blockchain explorer link

In FlutterFlow, add a payment status page or modal that shows real-time order status. Add a Backend Query (real-time listener) on the orders/{orderId} document. Display status conditionally: if status is 'pending_payment', show a CircularProgressIndicator with text 'Waiting for payment...'. If status is 'paid', show a green checkmark, the transaction hash truncated (first 8 + last 8 characters), and a Launch URL button that opens the blockchain explorer: for Ethereum mainnet, the URL is https://etherscan.io/tx/{txHash}; for Bitcoin, https://www.blockchain.com/btc/tx/{txHash}. If status is 'payment_failed', show a red error state with a Retry button that creates a new charge. The real-time listener updates the UI within 1-3 seconds of the webhook firing.

Expected result: Payment status page updates automatically from pending to confirmed as the transaction processes. Transaction hash is displayed with a link to the blockchain explorer.

Complete working example

coinbase_webhook.js
1// Cloud Function: coinbaseWebhook
2// Receives Coinbase Commerce payment events
3// Verifies webhook signature and updates Firestore order status
4
5const functions = require('firebase-functions');
6const { defineSecret } = require('firebase-functions/params');
7const admin = require('firebase-admin');
8const crypto = require('crypto');
9
10if (!admin.apps.length) admin.initializeApp();
11const webhookSecret = defineSecret('COINBASE_COMMERCE_WEBHOOK_SECRET');
12
13exports.coinbaseWebhook = functions
14 .runWith({ secrets: ['COINBASE_COMMERCE_WEBHOOK_SECRET'] })
15 .https.onRequest(async (req, res) => {
16 if (req.method !== 'POST') return res.status(405).send('Method Not Allowed');
17
18 // Verify Coinbase signature
19 const signature = req.headers['x-cc-webhook-signature'];
20 const rawBody = req.rawBody || JSON.stringify(req.body);
21 const computed = crypto
22 .createHmac('sha256', webhookSecret.value())
23 .update(rawBody)
24 .digest('hex');
25
26 if (!signature || signature !== computed) {
27 console.error('Invalid webhook signature');
28 return res.status(400).send('Invalid signature');
29 }
30
31 const event = req.body;
32 const orderId = event.data?.metadata?.orderId;
33 const db = admin.firestore();
34
35 try {
36 switch (event.type) {
37 case 'charge:confirmed': {
38 const payment = event.data.payments?.[0];
39 await db.collection('orders').doc(orderId).update({
40 status: 'paid',
41 txHash: payment?.transaction_id || null,
42 network: payment?.network || null,
43 cryptoCurrency: payment?.value?.crypto?.currency || null,
44 confirmedAt: admin.firestore.FieldValue.serverTimestamp()
45 });
46 console.log(`Order ${orderId} confirmed. TX: ${payment?.transaction_id}`);
47 break;
48 }
49 case 'charge:failed':
50 await db.collection('orders').doc(orderId).update({
51 status: 'payment_failed',
52 failedAt: admin.firestore.FieldValue.serverTimestamp()
53 });
54 break;
55 case 'charge:pending':
56 await db.collection('orders').doc(orderId).update({
57 status: 'payment_pending_confirmation'
58 });
59 break;
60 default:
61 console.log(`Unhandled event type: ${event.type}`);
62 }
63 } catch (err) {
64 console.error('Webhook processing error:', err);
65 return res.status(500).send('Processing error');
66 }
67
68 return res.status(200).send('OK');
69 });

Common mistakes

Why it's a problem: Marking an order as paid on charge:pending instead of waiting for charge:confirmed

How to avoid: Only update order status to 'paid' and fulfill the order on the charge:confirmed webhook event, which means at least 1 blockchain confirmation has been received. Coinbase Commerce handles the confirmation threshold per network (ETH is 1 confirmation, BTC is 3 confirmations by default). Show the user a 'Payment detected, waiting for confirmation' state between pending and confirmed.

Why it's a problem: Skipping webhook signature verification in the coinbaseWebhook Cloud Function

How to avoid: Always verify the X-CC-Webhook-Signature header using HMAC-SHA256 with your Coinbase Commerce webhook secret before processing any webhook event. Return HTTP 400 for any request with an invalid or missing signature. This is non-negotiable for production systems.

Why it's a problem: Calling the Coinbase Commerce API directly from FlutterFlow's API Manager instead of through a Cloud Function

How to avoid: All Coinbase Commerce API calls must go through a Cloud Function that reads the API key from Firebase Secret Manager at runtime. FlutterFlow calls the Cloud Function — the Cloud Function calls Coinbase Commerce.

Best practices

  • Set a charge expiration time in your createCryptoCharge call (Coinbase Commerce default is 1 hour) — expired charges prevent stale payment links from being used days later
  • Show the supported cryptocurrencies prominently on the payment selection screen — Coinbase Commerce supports BTC, ETH, LTC, USDC, DAI, APE, DOGE, and more, and users appreciate knowing their preferred currency is accepted
  • Display real-time conversion amounts in the payment selection screen (e.g., $49.99 ≈ 0.00052 BTC) by calling CoinGecko's free price API, so users know the crypto amount before going to checkout
  • Store the chargeCode in Firestore alongside orderId — Coinbase Commerce charge codes are short alphanumeric strings (e.g., 'ABCD1234') that are easier to reference in customer support conversations than long UUIDs
  • Add a payment polling fallback: if the webhook fails to arrive within 30 minutes, have the FlutterFlow app call an HTTP Cloud Function that queries the Coinbase Commerce API directly for charge status
  • Test your integration in Coinbase Commerce test mode before going live — use the sandbox environment to simulate charge:confirmed and charge:failed events without real transactions

Still stuck?

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

ChatGPT Prompt

I am building a FlutterFlow app that needs to accept cryptocurrency payments. Write me: (1) A Firebase Cloud Function that creates a Coinbase Commerce charge and returns the hosted checkout URL, (2) A second Cloud Function that receives Coinbase Commerce webhooks, verifies the signature with HMAC-SHA256, and updates an order document in Firestore when payment is confirmed, (3) How to display payment status with transaction hash and blockchain explorer link in FlutterFlow.

FlutterFlow Prompt

Add a Pay with Crypto button to my checkout page. When tapped, call the createCryptoCharge Cloud Function with the order amount and product name, store the returned hostedUrl in page state, then launch that URL. After launching, show a payment status card that listens to the Firestore orders document in real time and updates from Pending to Confirmed when the webhook fires.

Frequently asked questions

Which cryptocurrencies does Coinbase Commerce support?

Coinbase Commerce currently supports Bitcoin (BTC), Ethereum (ETH), USD Coin (USDC), Litecoin (LTC), Bitcoin Cash (BCH), Dogecoin (DOGE), DAI, Shiba Inu (SHIB), ApeCoin (APE), and several others. The list changes as Coinbase adds or removes support for networks. Check commerce.coinbase.com for the current supported currencies list. Your charge automatically generates payment addresses for all supported currencies, and customers choose which to pay with on the hosted checkout page.

How long does a Coinbase Commerce payment take to confirm?

Confirmation time depends on the cryptocurrency used and network congestion. ETH is typically 15-30 seconds for one confirmation. BTC is 10-60 minutes per confirmation (Coinbase requires 3 confirmations). USDC on Ethereum is the same as ETH. For time-sensitive transactions, USDC on faster chains (Polygon, Base) is the quickest option. Coinbase Commerce's hosted checkout page shows the user a real-time confirmation countdown.

Do I need a Coinbase account to accept Coinbase Commerce payments?

Yes. Coinbase Commerce requires a Coinbase account for business verification and to receive payouts. Funds collected via Coinbase Commerce are held in your Coinbase Commerce wallet and can be converted to USD and transferred to a bank account, or held as cryptocurrency. Payouts are handled entirely through the Coinbase Commerce dashboard, not FlutterFlow.

Can I use Coinbase Commerce in countries where Coinbase is restricted?

Coinbase Commerce is available in most countries where Coinbase operates. Some countries have restrictions on Coinbase (China, Iran, North Korea, and other sanctioned countries). Your customers can be in any country that can legally use cryptocurrency and access the Coinbase Commerce hosted page. Check Coinbase's supported regions list at commerce.coinbase.com/faq for the current availability.

What fees does Coinbase Commerce charge?

Coinbase Commerce charges 1% fee on all transactions. This is deducted from the received amount before it appears in your Commerce wallet. There are no monthly fees or setup costs — you only pay the 1% when you receive a payment. Compare: Stripe charges 2.9% + $0.30 per transaction for credit cards. Crypto via Coinbase Commerce at 1% is cheaper for medium and large transaction amounts.

Can RapidDev help integrate a more advanced crypto payment system in FlutterFlow?

Yes. Advanced crypto payment requirements — multi-currency support with real-time conversion rates, WalletConnect integration for direct MetaMask payments, token-gated content access, NFT-based subscriptions, or crypto invoicing with automatic USD conversion — go significantly beyond the Coinbase Commerce hosted checkout pattern. RapidDev has built Web3 payment integrations for FlutterFlow apps across DeFi, gaming, and creator economy use cases.

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.