Skip to main content
RapidDev - Software Development Agency
lovable-integrationsEdge Function Integration

How to Integrate Lovable with Coinbase Commerce API

Integrating Coinbase Commerce with Lovable uses Edge Functions to create crypto payment charges, verify webhook signatures, and track payment status. Store your Coinbase Commerce API key and webhook secret in Cloud Secrets, create an Edge Function to generate payment charges and verify incoming webhooks, and accept Bitcoin, Ethereum, and other crypto payments in your app. Setup takes 35 minutes.

What you'll learn

  • How to set up Coinbase Commerce and obtain API credentials
  • How to create cryptocurrency payment charges via an Edge Function
  • How to implement Coinbase Commerce webhook verification for payment confirmation
  • How to handle the complete crypto payment lifecycle (pending, confirmed, failed)
  • How to build a product checkout flow that accepts Bitcoin, Ethereum, and USDC
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate14 min read35 minutesPaymentMarch 2026RapidDev Engineering Team
TL;DR

Integrating Coinbase Commerce with Lovable uses Edge Functions to create crypto payment charges, verify webhook signatures, and track payment status. Store your Coinbase Commerce API key and webhook secret in Cloud Secrets, create an Edge Function to generate payment charges and verify incoming webhooks, and accept Bitcoin, Ethereum, and other crypto payments in your app. Setup takes 35 minutes.

Why integrate Coinbase Commerce with Lovable?

Cryptocurrency payments represent a growing segment of digital commerce, particularly for digital products, international transactions where traditional payment rails are expensive or unavailable, and communities that prefer the censorship-resistance of blockchain payments. Coinbase Commerce is the developer-friendly crypto payment processor: it creates a payment request (charge), the buyer sends crypto to the generated address, and Coinbase detects the payment automatically. No exchange accounts or crypto wallets are required from your customers beyond a basic crypto wallet.

For Lovable developers, Coinbase Commerce is particularly interesting for: digital product stores serving global markets where credit cards are less accessible, creator economy tools where fans can support creators with crypto tips, Web3 applications where users already hold crypto, and markets where payment privacy is valued. Coinbase Commerce accepts Bitcoin, Ethereum, Litecoin, Bitcoin Cash, Dai, and USD Coin — covering the major cryptocurrencies most users already hold.

The technical integration is straightforward: create a charge object (specifying the price in your currency and what the buyer is purchasing), redirect the buyer to Coinbase's hosted checkout page, and handle webhook events when payment is confirmed. Coinbase handles all blockchain complexity — address generation, transaction monitoring, and confirmations. Your Edge Function only needs to create charges and verify webhook signatures.

Integration method

Edge Function Integration

Coinbase Commerce has no native Lovable connector. Integration requires Supabase Edge Functions to create payment charges via the Commerce API, redirect users to Coinbase's hosted checkout page, and verify incoming webhook signatures when payment status changes. The Commerce API key and webhook secret are stored in Cloud Secrets. All API calls run server-side to protect credentials.

Prerequisites

  • A Lovable project with Cloud enabled
  • A Coinbase Commerce account — create free at commerce.coinbase.com
  • Coinbase Commerce API key from Settings → Security in your Commerce dashboard
  • Coinbase Commerce webhook secret configured for your endpoint URL
  • Basic understanding of how crypto payment addresses work (users send to a generated address)

Step-by-step guide

1

Set up Coinbase Commerce and get credentials

Go to commerce.coinbase.com and create a Coinbase Commerce account (separate from Coinbase Exchange — you don't need to hold crypto or have an exchange account). After email verification, you can immediately accept payments. In your Commerce dashboard, navigate to Settings → Security. Click 'Create an API key'. Give it a name like 'Lovable App' and copy the API key — it's shown only once. This key is used in the Authorization header as 'Bearer {apikey}' for all Commerce API requests. Still in Settings → Security, scroll down to 'Webhook subscriptions'. Click 'Add an endpoint' and enter your webhook URL: https://your-project.supabase.co/functions/v1/coinbase-webhooks (your Edge Function URL). Select the events you want to receive: charge:created, charge:confirmed, charge:failed, charge:delayed, charge:pending, charge:resolved. Coinbase provides a webhook signing secret for each endpoint — copy this secret for webhook verification. Coinbase Commerce has no sandbox mode — all charges are real and must be paid with real crypto. For testing, create small charges (e.g., $0.01 USD) and pay them with a small crypto amount. Alternatively, use Coinbase Commerce's 'dummy' payment feature in the dashboard that simulates payment without actual crypto transaction for development testing.

Pro tip: Coinbase Commerce's hosted checkout handles all currency conversion automatically — you price in USD (or another fiat currency) and Coinbase shows the equivalent in BTC, ETH, etc. at the current exchange rate. Users pay in their preferred cryptocurrency and you receive the value in your local currency converted at settlement.

Expected result: You have a Coinbase Commerce API key and webhook secret. The webhook endpoint URL is registered in the Commerce dashboard with the relevant events selected.

2

Store credentials in Cloud Secrets

Open your Lovable project, click '+', select 'Cloud', and expand Secrets. Add COINBASE_COMMERCE_API_KEY with your Commerce API key. Add COINBASE_COMMERCE_WEBHOOK_SECRET with the signing secret for your webhook endpoint. Add COINBASE_COMMERCE_API_BASE with 'https://api.commerce.coinbase.com'. The API key grants full access to your Commerce account including creating charges, listing them, and canceling them. If compromised, someone could create fraudulent charges or access your payment history. Store it exclusively in Cloud Secrets. The webhook secret is used to verify that incoming webhook requests are genuinely from Coinbase Commerce and not spoofed by a malicious actor sending fake payment confirmations. Without signature verification, someone could send a fake 'payment confirmed' webhook and trigger your fulfillment logic without actually paying. Always verify signatures before processing webhook events — Lovable's security model blocks approximately 1,200 API key exposures daily, but application-level signature verification is your responsibility.

Pro tip: Create separate Coinbase Commerce API keys for development and production if you're testing with real small transactions. This keeps your development payment history separate from production. The webhook secret is endpoint-specific — each registered webhook endpoint gets its own secret.

Expected result: COINBASE_COMMERCE_API_KEY, COINBASE_COMMERCE_WEBHOOK_SECRET, and COINBASE_COMMERCE_API_BASE appear in Cloud Secrets.

3

Create the charge creation Edge Function

Create the Edge Function that generates Coinbase Commerce payment charges. A charge is the central concept in Commerce: it represents a payment request for a specific amount. Each charge gets a unique ID, a hosted checkout URL, and payment addresses for each supported cryptocurrency. The charge creation request requires: name (what the buyer is purchasing), description (more detail), pricing_type ('fixed_price' for a specific amount or 'no_price' for open-ended), price object (amount and currency for fixed_price), and optional metadata (your order ID, user ID, etc. — sent back in webhooks). Coinbase Commerce supports pricing in major fiat currencies (USD, EUR, GBP, etc.) and stablecoins (USDC). For a fixed price item, set pricing_type='fixed_price' and price={amount: '29.99', currency: 'USD'}. Coinbase converts this to the equivalent crypto amount at the current exchange rate. After creating the charge, your Edge Function returns the charge ID and hosted_url. Store the charge ID in your database immediately so you can match incoming webhook events to the correct order. Redirect the user to hosted_url for the payment experience.

Lovable Prompt

Create a Supabase Edge Function at supabase/functions/coinbase-commerce/index.ts. Support: action='create-charge' with name, description, amount_usd, user_id, order_id — POST to Coinbase Commerce /charges with API key, create a fixed_price charge; store charge_id, order_id, user_id, status='NEW', created_at in a crypto_orders Supabase table; return {charge_id, hosted_url, expires_at}. Add CORS headers.

Paste this in Lovable chat

supabase/functions/coinbase-commerce/index.ts
1// supabase/functions/coinbase-commerce/index.ts
2import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
3import { createClient } from "https://esm.sh/@supabase/supabase-js@2";
4
5const API_KEY = Deno.env.get("COINBASE_COMMERCE_API_KEY") ?? "";
6const API_BASE = Deno.env.get("COINBASE_COMMERCE_API_BASE") ?? "https://api.commerce.coinbase.com";
7const corsHeaders = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "POST, OPTIONS", "Access-Control-Allow-Headers": "Content-Type, Authorization" };
8
9serve(async (req) => {
10 if (req.method === "OPTIONS") return new Response(null, { headers: corsHeaders });
11 const supabase = createClient(Deno.env.get("SUPABASE_URL") ?? "", Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "");
12
13 try {
14 const body = await req.json();
15 const { action } = body;
16
17 if (action === "create-charge") {
18 const { name, description, amount_usd, user_id, order_id } = body;
19 const res = await fetch(`${API_BASE}/charges`, {
20 method: "POST",
21 headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json", "X-CC-Version": "2018-03-22" },
22 body: JSON.stringify({
23 name,
24 description,
25 pricing_type: "fixed_price",
26 local_price: { amount: amount_usd.toString(), currency: "USD" },
27 metadata: { user_id, order_id },
28 }),
29 });
30 const data = await res.json();
31 if (!data.data?.code) throw new Error(data.error?.message ?? "Charge creation failed");
32 const charge = data.data;
33
34 await supabase.from("crypto_orders").insert({
35 charge_id: charge.code,
36 order_id,
37 user_id,
38 amount_usd,
39 status: "NEW",
40 hosted_url: charge.hosted_url,
41 created_at: new Date().toISOString(),
42 });
43
44 return new Response(JSON.stringify({ charge_id: charge.code, hosted_url: charge.hosted_url, expires_at: charge.expires_at }), {
45 headers: { ...corsHeaders, "Content-Type": "application/json" },
46 });
47 }
48
49 return new Response(JSON.stringify({ error: "Unknown action" }), { status: 400, headers: corsHeaders });
50 } catch (err) {
51 return new Response(JSON.stringify({ error: err.message }), { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } });
52 }
53});

Pro tip: Coinbase Commerce charges expire after 1 hour if unpaid. After the expiry, the hosted_url still works but new payment addresses are generated. Store the expiry time in your database and show a 'Payment link expired' message in your UI if the user returns after an hour without completing payment.

Expected result: The coinbase-commerce Edge Function creates payment charges. Calling action='create-charge' returns a hosted_url that opens Coinbase's checkout showing the price in multiple cryptocurrencies.

4

Create the webhook receiver Edge Function

Create a separate Edge Function that receives and processes Coinbase Commerce webhooks. The webhook receiver must be at the URL you registered with Coinbase, and it must verify the signature on every incoming request before processing payment events. Coinbase Commerce signs webhooks using HMAC-SHA256 with your webhook secret as the key and the raw request body as the message. The signature is included in the X-CC-Webhook-Signature header. Compute the expected signature and compare it to the header value before trusting the event data. Key Coinbase Commerce webhook events: charge:created (charge was created — usually from your app), charge:pending (partial payment received — user sent some but not full amount), charge:confirmed (full payment received and confirmed on blockchain — trigger fulfillment), charge:failed (charge expired without payment), charge:delayed (payment received but delayed blockchain confirmation), charge:resolved (charge resolved — could be paid or cancelled). For most use cases, you need to handle charge:confirmed (update order status to paid, trigger fulfillment) and charge:failed (update order status to expired). Store all webhook events in a Supabase webhook_events table for audit purposes before processing — this lets you replay events if your processing logic has a bug.

Lovable Prompt

Create a Supabase Edge Function at supabase/functions/coinbase-webhooks/index.ts. Verify the X-CC-Webhook-Signature header using HMAC-SHA256 with COINBASE_COMMERCE_WEBHOOK_SECRET. Parse the event body and handle: event type 'charge:confirmed' — update the crypto_orders table status to 'CONFIRMED' where charge_id matches, trigger order fulfillment logic (e.g., set order_fulfilled=true); event type 'charge:failed' — update status to 'FAILED'. Log all events to a webhook_events table regardless of type. Return 200 OK.

Paste this in Lovable chat

supabase/functions/coinbase-webhooks/index.ts
1// supabase/functions/coinbase-webhooks/index.ts
2import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
3import { createClient } from "https://esm.sh/@supabase/supabase-js@2";
4
5const WEBHOOK_SECRET = Deno.env.get("COINBASE_COMMERCE_WEBHOOK_SECRET") ?? "";
6
7serve(async (req) => {
8 const supabase = createClient(Deno.env.get("SUPABASE_URL") ?? "", Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "");
9 const rawBody = await req.text();
10 const signature = req.headers.get("X-CC-Webhook-Signature") ?? "";
11
12 // Verify signature
13 const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(WEBHOOK_SECRET), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
14 const expectedSig = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(rawBody));
15 const expectedHex = Array.from(new Uint8Array(expectedSig)).map(b => b.toString(16).padStart(2, "0")).join("");
16
17 if (expectedHex !== signature) {
18 console.error("Webhook signature mismatch");
19 return new Response("Unauthorized", { status: 401 });
20 }
21
22 const event = JSON.parse(rawBody);
23 const chargeCode = event.data?.code;
24 const eventType = event.type;
25
26 // Log the event
27 await supabase.from("webhook_events").insert({ event_type: eventType, charge_id: chargeCode, payload: event, received_at: new Date().toISOString() });
28
29 if (eventType === "charge:confirmed" && chargeCode) {
30 await supabase.from("crypto_orders").update({ status: "CONFIRMED", confirmed_at: new Date().toISOString() }).eq("charge_id", chargeCode);
31 } else if (eventType === "charge:failed" && chargeCode) {
32 await supabase.from("crypto_orders").update({ status: "FAILED" }).eq("charge_id", chargeCode);
33 }
34
35 return new Response("OK", { status: 200 });
36});

Pro tip: Crypto transactions typically need 1-3 blockchain confirmations before Coinbase Commerce fires a charge:confirmed event. For Bitcoin, this takes 10-30 minutes. For Ethereum and ERC-20 tokens (USDC, DAI), it takes 1-5 minutes. Don't fulfill orders based on charge:pending — wait for charge:confirmed which indicates sufficient blockchain confirmations.

Expected result: The coinbase-webhooks Edge Function verifies signatures and processes payment events. When a test payment is confirmed, the crypto_orders table status updates to CONFIRMED.

Common use cases

Digital product purchase with crypto checkout

An online store for digital downloads (ebooks, templates, software licenses) offers crypto payment as an alternative to Stripe. When a buyer selects a product and clicks 'Pay with Crypto', an Edge Function creates a Coinbase Commerce charge and redirects the buyer to the hosted checkout where they can pay with their preferred cryptocurrency. After payment confirmation via webhook, the buyer receives their download link.

Lovable Prompt

Add a 'Pay with Crypto' button to the product purchase page. When clicked, call an Edge Function that creates a Coinbase Commerce charge with the product name, price in USD, and a metadata field containing the user's order ID. Return the hosted_url from the charge and redirect the user to it. When payment is confirmed via Coinbase webhook, update the order status to 'paid' in Supabase and send the buyer their download link via email.

Copy this prompt to try it in Lovable

Crypto tip jar for creators

A creator portfolio site lets fans send crypto tips in any amount they choose. The Edge Function creates a charge without a fixed price (letting the buyer set the amount on Coinbase's page), and Coinbase detects whatever amount is sent. Tips are recorded in Supabase with the sender's crypto currency and amount for display on a public contribution list.

Lovable Prompt

Add a crypto tip feature to the creator page. A 'Send a Tip' button opens a form where visitors enter their name and optional message. Clicking Send calls an Edge Function to create a Coinbase Commerce charge with no fixed price and a description showing the creator's name and the visitor's message. Redirect to the Coinbase hosted checkout. When payment confirmed via webhook, save the tip to a Supabase tips table with amount, currency, and optional message. Display recent tips publicly on the creator page.

Copy this prompt to try it in Lovable

Subscription payment in USDC

A membership platform accepts USDC (a stablecoin pegged to USD) for monthly subscriptions, avoiding credit card fees. Each month, the system creates a new charge for active subscribers and sends them a payment link. The webhook confirms payment and extends their membership. USDC eliminates price volatility compared to paying in Bitcoin or Ethereum.

Lovable Prompt

Build a subscription billing system using Coinbase Commerce USDC payments. Create an Edge Function that generates monthly payment charges in USDC for each active subscriber (stored in Supabase). Send each subscriber a payment email with their Coinbase charge hosted_url. When the payment webhook fires with status 'CONFIRMED' for USDC, update the subscriber's renewal_date in Supabase by 30 days. Add a membership status indicator on the user dashboard showing days remaining and a 'Renew' link.

Copy this prompt to try it in Lovable

Troubleshooting

Webhook signature verification fails for all incoming events

Cause: The webhook secret in Cloud Secrets doesn't match the secret associated with the registered endpoint in Coinbase Commerce, or the raw body is being parsed before signature verification (destroying the exact byte representation needed for HMAC).

Solution: Verify that COINBASE_COMMERCE_WEBHOOK_SECRET exactly matches the webhook signing secret shown for your endpoint in Commerce → Settings → Security → Webhook subscriptions. Ensure you call await req.text() to get the raw body BEFORE any JSON parsing — the signature is computed over the raw bytes, and parsing JSON then re-stringifying changes the byte representation.

typescript
1// CORRECT: read raw body first, parse after signature verification
2const rawBody = await req.text();
3// ... verify signature ...
4const event = JSON.parse(rawBody); // parse after verification

Charges expire before users complete payment

Cause: Coinbase Commerce charges expire after 1 hour by default. If users click 'Pay with Crypto' and then delay paying (common with crypto where users need time to find their wallet), the charge expires and the hosted_url stops accepting new payments.

Solution: Implement charge status checking in your app: when a user returns to complete payment, check the charge status via the Commerce API. If expired, create a new charge automatically. You can also increase the charge expiry time in Commerce settings. Show a countdown timer on your payment page so users know they need to complete payment within the hour.

charge:confirmed event received but order not found in database

Cause: The charge_id in the webhook doesn't match what's stored in your crypto_orders table. Coinbase Commerce charges have a 'code' field (a short alphanumeric string like 'ABC123XY') as the identifier — if you stored the full charge object ID instead of the code field, lookups will fail.

Solution: Use event.data.code (the short charge code, e.g., 'ABC123XY') as the identifier in your database, not the full UUID-format id. The X-CC-Webhook-Signature event payload uses the code consistently. Verify which field you stored at charge creation time and ensure the webhook handler matches.

typescript
1// Store and look up by charge CODE, not charge ID
2const chargeCode = event.data?.code; // 'ABC123XY' format
3await supabase.from('crypto_orders').update({...}).eq('charge_id', chargeCode);

Best practices

  • Always verify the X-CC-Webhook-Signature header before processing any payment events — without verification, fraudulent webhook calls could trigger order fulfillment without actual payment.
  • Store all incoming webhook events in a raw log table before processing — this gives you an audit trail and allows replaying events if your processing logic has a bug.
  • Don't fulfill orders on charge:pending events — only fulfill on charge:confirmed, which indicates sufficient blockchain confirmations. Pending payments can still fail if the crypto network rejects the transaction.
  • Use USDC for price-sensitive applications where payment amount volatility is unacceptable — Bitcoin and Ethereum prices fluctuate between charge creation and payment, while USDC is pegged to USD.
  • Implement a payment polling endpoint that checks charge status from the Commerce API — users who complete payment but whose browser doesn't redirect back to your site need a way to check their payment status.
  • Set expiry time prominently in the checkout UI — showing a countdown timer creates urgency and helps users understand they need to complete payment within the hour window.
  • Cache the current crypto exchange rates shown to users and update them every 30 seconds — outdated rates can cause confusion when the displayed crypto amount doesn't match the actual charge amount.

Alternatives

Frequently asked questions

Does Coinbase Commerce require buyers to have a Coinbase account?

No — buyers can pay with any cryptocurrency wallet, not just Coinbase. Coinbase Commerce generates a payment address for each charge, and buyers can send crypto from any wallet (Metamask, Trust Wallet, hardware wallets, etc.) to that address. The Coinbase hosted checkout shows a QR code and wallet address that works with any compatible wallet. Some buyers will have Coinbase accounts and can pay directly, but it's not required.

How do I receive the money after a crypto payment is confirmed?

Coinbase Commerce holds confirmed crypto payments in your Commerce account. You can either keep funds as crypto or convert and withdraw to your bank account in fiat currency through Coinbase. For USDC payments, the value is stable and can be withdrawn as USD. For Bitcoin and Ethereum, you choose when to convert based on your currency risk preference. Payouts to your bank typically take 1-3 business days after initiating a withdrawal.

What cryptocurrencies does Coinbase Commerce accept?

Coinbase Commerce currently supports Bitcoin (BTC), Ethereum (ETH), Litecoin (LTC), Bitcoin Cash (BCH), USD Coin (USDC), Dai (DAI), and a growing list of other tokens. The specific coins available for a charge depend on your Commerce account settings. USDC and Dai are stablecoins pegged to USD, making them the best choice for avoiding exchange rate risk on fixed-price products.

Is there a transaction fee for Coinbase Commerce?

Coinbase Commerce has no transaction fees for receiving crypto payments — it's free to use. You receive 100% of the crypto sent (minus the blockchain network gas fees paid by the buyer). When you withdraw to fiat currency through Coinbase, standard exchange fees apply (typically 0-2% depending on your Coinbase tier). This makes Coinbase Commerce significantly cheaper than traditional card processors for large transaction amounts.

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.