Skip to main content
RapidDev - Software Development Agency
bubble-integrationsBubble API Connector

Coinbase API

Coinbase offers two completely separate API products: the App API (api.coinbase.com) for spot prices and portfolio data, and Coinbase Commerce (api.commerce.coinbase.com) for accepting crypto payments. A simple crypto price ticker in Bubble needs zero authentication — spot price endpoints are public. Commerce payments require an API key plus a Backend Workflow webhook to confirm charges. Authenticated account data requires per-request HMAC-SHA256 signatures that Bubble cannot compute natively.

What you'll learn

  • The critical difference between Coinbase App API and Coinbase Commerce — two completely separate products with separate keys, separate base URLs, and different use cases
  • How to build a live crypto price ticker in Bubble using Coinbase's public spot price endpoint — no API key required
  • How to create Coinbase Commerce charges and redirect users to Coinbase's hosted checkout page from a Bubble workflow
  • How to set up a Bubble API Workflow (Backend Workflow) to receive Coinbase Commerce webhook events for payment confirmation
  • Why storing crypto amounts as Text (not Number) in Bubble's database prevents floating-point precision loss on BTC and ETH amounts
  • Why Commerce charges expire after 1 hour and how to handle charge recreation in Bubble
  • When authenticated App API endpoints (portfolio data) require HMAC-SHA256 signing that Bubble cannot compute natively
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate23 min read2–4 hoursFinance & AccountingLast updated July 2026RapidDev Engineering Team
TL;DR

Coinbase offers two completely separate API products: the App API (api.coinbase.com) for spot prices and portfolio data, and Coinbase Commerce (api.commerce.coinbase.com) for accepting crypto payments. A simple crypto price ticker in Bubble needs zero authentication — spot price endpoints are public. Commerce payments require an API key plus a Backend Workflow webhook to confirm charges. Authenticated account data requires per-request HMAC-SHA256 signatures that Bubble cannot compute natively.

Quick facts about this guide
FactValue
ToolCoinbase API
CategoryFinance & Accounting
MethodBubble API Connector
DifficultyIntermediate
Time required2–4 hours
Last updatedJuly 2026

Coinbase on Bubble: Two APIs, Three Use Cases

The most common mistake builders make when integrating Coinbase with Bubble is treating 'the Coinbase API' as a single product. There are two completely separate Coinbase APIs, and confusing them produces frustrating 401 errors that have nothing to do with your configuration being wrong.

Coinbase App API (api.coinbase.com): Access to cryptocurrency spot prices, exchange rates, and — with authentication — user account balances and transaction history. Public endpoints like GET /v2/prices/BTC-USD/spot require zero credentials. Authenticated endpoints require three computed headers per request including a per-request HMAC-SHA256 signature, which Bubble's API Connector cannot generate natively.

Coinbase Commerce (api.commerce.coinbase.com): A merchant payment tool. You create a 'charge' via API, receive a hosted checkout URL, redirect your customer there, and receive a webhook when payment is confirmed. Keys from commerce.coinbase.com work only with the Commerce API — they will not work on api.coinbase.com, and vice versa.

For Bubble builders, this creates three distinct use cases with very different implementation complexity:

1. Crypto price ticker — trivially easy, no auth, API Connector only, works on free Bubble plan 2. Merchant crypto payments (Commerce) — moderate complexity, API key in Private header, Backend Workflow for webhooks (paid Bubble plan), most common commercial use case 3. Portfolio data / account balances — advanced, requires HMAC-SHA256 signing, involves Backend Workflows calling external signing helpers

This tutorial covers all three use cases clearly, so you can build exactly what your project needs without being blocked by the wrong setup.

Integration method

Bubble API Connector

Bubble API Connector for spot prices (no auth required) and Commerce payments (CB-ACCESS-KEY header, Private); Bubble API Workflow (Backend Workflow) for Commerce webhook confirmation on paid Bubble plans.

Prerequisites

  • A Bubble account — the price ticker use case works on any plan including free; Commerce payments and webhook handling require a paid plan for Backend Workflows (API Workflows)
  • For Commerce payments: a Coinbase Commerce account at commerce.coinbase.com and an API key from Settings → API Keys
  • For App API price data: no account required — public endpoints are open
  • For authenticated portfolio data: a Coinbase developer account at www.coinbase.com/settings/api with an API key and secret that has the 'wallet:accounts:read' permission
  • Basic familiarity with Bubble's API Connector plugin and, for Commerce payments, how to create Backend Workflow endpoints
  • Understanding that Commerce charges expire after 1 hour — build your checkout flow with this constraint in mind

Step-by-step guide

1

Build a Crypto Price Ticker (No Auth Required)

Coinbase's spot price endpoints are completely public — you do not need an API key, an account, or any authentication to display live cryptocurrency prices. This makes the price ticker the simplest Coinbase integration in Bubble, and the one most builders should start with. Go to Plugins tab → Add plugins → search 'API Connector' (by Bubble) → Install. Click 'Add another API' and name it 'Coinbase Prices'. Set the base URL to https://api.coinbase.com Add a call named 'Spot Price': - Method: GET - Path: /v2/prices/BTC-USD/spot - No authentication headers needed - No body - Set 'Use as Data' (not Action) — this lets Bubble bind the response data directly to page elements Click 'Initialize call'. Because this is a public endpoint, the initialization completes immediately with real data. Bubble detects the response fields: data.amount (the price as a string like '45231.05') and data.currency (the currency like 'USD'). Add this Text element to a Bubble page: set the value to 'Get data from external API' → select your Coinbase Prices > Spot Price call → select data.amount. Add a currency symbol prefix ('$') to format the display. To display multiple currencies, create additional API calls: - /v2/prices/ETH-USD/spot (Ethereum) - /v2/prices/SOL-USD/spot (Solana) - /v2/prices/BTC-EUR/spot (Bitcoin in EUR) To refresh prices automatically, click on any element on the page, go to Workflows → Add workflow → 'Do every X seconds' → set interval to 30 seconds → add action 'Refresh an external API call' → select your Spot Price call. This triggers a fresh API call every 30 seconds without a page reload. Note: Coinbase returns the price as a string in data.amount, not a number. If you want to format it with commas or decimal places, use Bubble's 'formatted as number' expression on the value.

coinbase-spot-price-public.json
1// API Connector Configuration - No auth needed
2GET https://api.coinbase.com/v2/prices/BTC-USD/spot
3
4// Response:
5{
6 "data": {
7 "amount": "45231.05",
8 "base": "BTC",
9 "currency": "USD"
10 }
11}
12
13// Additional endpoints for other currencies:
14// GET /v2/prices/ETH-USD/spot
15// GET /v2/prices/SOL-USD/spot
16// GET /v2/prices/BTC-EUR/spot
17// GET /v2/exchange-rates?currency=USD (all rates in one call)

Pro tip: The exchange rates endpoint (/v2/exchange-rates?currency=USD) returns rates for hundreds of currencies in a single API call — much more WU-efficient than making separate calls for each coin. If you want to display 10+ cryptocurrencies, use the exchange rates endpoint and extract the specific rates you need from the response.

Expected result: A Text element on your Bubble page displays the live Bitcoin spot price in USD, updated every 30 seconds. No API key was needed. The Initialize Call completes immediately with a real price value.

2

Set Up Coinbase Commerce for Crypto Payments

Coinbase Commerce lets you accept Bitcoin, Ethereum, Litecoin, USDC, and other cryptocurrencies from customers without handling private keys or running your own blockchain node. The flow: your Bubble app creates a 'charge', Commerce returns a hosted checkout URL, you redirect the customer there, and Coinbase handles the rest. First, create your Commerce API key. Go to commerce.coinbase.com → log in or create an account → Settings → API Keys → Create an API Key. Copy the key — it will not be shown again. Install the API Connector plugin if you haven't already. Add a new API group named 'Coinbase Commerce'. Set base URL to https://api.commerce.coinbase.com Add a shared header: - Key: X-CC-Api-Key - Value: [your-commerce-api-key] - Enable the 'Private' checkbox — this keeps your key on Bubble's servers and out of the browser Add a second shared header: - Key: X-CC-Version - Value: 2018-03-22 (This pins the API version for stability) Add a call named 'Create Charge': - Method: POST - Path: /charges - Body type: JSON - Body: { "name": "[product_name]", "description": "[product_description]", "pricing_type": "fixed_price", "local_price": { "amount": "[price_amount]", "currency": "[currency_code]" }, "metadata": { "customer_id": "[bubble_user_id]", "order_id": "[bubble_order_id]" } } Make the parameters in square brackets into Bubble API call parameters. The metadata fields are important — they let you match the incoming webhook event back to the correct order in your database. Click 'Initialize call' with a real price (e.g., amount='25.00', currency='USD', product_name='Test Item'). The response includes a hosted_url field — this is the Coinbase Commerce checkout page URL you will redirect customers to. Critical: charges expire after 1 hour. If a customer starts checkout but delays more than an hour, the hosted_url is no longer valid. Store the charge_id and created_at timestamp in your Bubble Orders table so you can recreate an expired charge.

coinbase-commerce-create-charge.json
1// Create Charge
2POST https://api.commerce.coinbase.com/charges
3Headers:
4 X-CC-Api-Key: <private-commerce-api-key>
5 X-CC-Version: 2018-03-22
6 Content-Type: application/json
7
8Body:
9{
10 "name": "Premium Subscription",
11 "description": "1 month access to all features",
12 "pricing_type": "fixed_price",
13 "local_price": {
14 "amount": "29.00",
15 "currency": "USD"
16 },
17 "metadata": {
18 "customer_id": "bubble-user-id-here",
19 "order_id": "bubble-order-id-here"
20 }
21}
22
23// Response (partial):
24{
25 "data": {
26 "id": "charge-uuid-here",
27 "hosted_url": "https://commerce.coinbase.com/charges/ABCD1234",
28 "expires_at": "2026-01-09T15:30:00Z",
29 "timeline": [{ "status": "NEW", "time": "2026-01-09T14:30:00Z" }]
30 }
31}

Pro tip: Include meaningful metadata in every charge — at minimum the Bubble user ID and order ID. When the webhook arrives confirming payment, the metadata is how you link the Coinbase event back to the correct Bubble database record. Without metadata, you would have to query by amount and time, which is error-prone.

Expected result: Your 'Create Charge' API call initializes successfully and returns a real hosted_url pointing to a Coinbase Commerce checkout page. The charge appears in your Commerce dashboard at commerce.coinbase.com under 'Charges'.

3

Build the Checkout Workflow and Handle the Redirect

With the Commerce API call configured, build the complete checkout workflow in Bubble that takes a user from clicking 'Pay with Crypto' to landing on Coinbase's hosted checkout page. Create a 'Pay with Crypto' button on your product or cart page. In the button's workflow: Step 1: Create Order — if you haven't already, create an Order record in Bubble's database with status 'pending' and a generated order_id. This is what you will update when payment is confirmed. Step 2: Call API — 'Coinbase Commerce > Create Charge'. Map your parameters: - product_name: the product's name field - product_description: the product's description field - price_amount: the product's price formatted as text (e.g., '29.00', not 29) - currency_code: 'USD' (or your store's currency) - bubble_user_id: Current User's unique ID - bubble_order_id: the Order record's unique ID you created in Step 1 Step 3: Make changes to a thing — update your Order record to store 'coinbase_charge_id' (from the API response data.id) and 'coinbase_charge_created_at' (Current date/time). You will use the timestamp to detect expired charges. Step 4: Open an external URL — set the URL to the API response's data.hosted_url. Set it to open in the current tab (recommended) or a new tab. Opening in the same tab provides a cleaner UX because Coinbase will redirect back to your app when payment completes — set the 'Redirect URL' in your Commerce account settings to a thank-you page on your Bubble app. Important: store crypto transaction amounts as Text type in Bubble's database, not as Number. Bitcoin amounts have 8 decimal places (e.g., 0.00031427 BTC), and Bubble's Number type can lose precision on very small decimal values. Store the amount string exactly as returned by Coinbase and only convert to a display-formatted number when showing it in the UI. For expired charge detection: on any page where you show the charge or a 'resume checkout' link, add a condition checking if coinbase_charge_created_at is more than 50 minutes ago. If expired, run the 'Create Charge' API call again and update the stored charge_id and URL.

coinbase-checkout-workflow.json
1// Bubble workflow for 'Pay with Crypto' button:
2// Step 1: Create thing 'Order'
3// - status: 'pending'
4// - customer: Current User
5// - amount_display: '29.00 USD'
6
7// Step 2: Call API Coinbase Commerce > Create Charge
8// - product_name: Product's name
9// - price_amount: Product's price:formatted as text
10// - bubble_order_id: Result of Step 1's unique ID
11// - bubble_user_id: Current User's unique ID
12
13// Step 3: Make changes to Order (result of Step 1)
14// - coinbase_charge_id: Result of Step 2's body data id
15// - coinbase_charge_url: Result of Step 2's body data hosted_url
16// - coinbase_charge_created_at: Current date/time
17
18// Step 4: Open an external URL
19// - URL: Result of Step 2's body data hosted_url
20
21// Expired charge check (50 min threshold):
22// Condition: Order's coinbase_charge_created_at < Current date/time - 50 minutes
23// If true: re-run Create Charge, update Order record with new charge_id and hosted_url

Pro tip: Set your Commerce 'Redirect URL' in commerce.coinbase.com → Settings → Checkout to point to a Bubble thank-you page (e.g., https://your-app.bubbleapps.io/order-confirmation). When a customer completes payment, Coinbase redirects them back to this page — but do not use this redirect as your payment confirmation; use the webhook in the next step for that.

Expected result: Clicking 'Pay with Crypto' creates a pending order in Bubble's database, creates a Coinbase charge, and redirects the user to a Coinbase-hosted checkout page. The order record stores the charge ID and creation timestamp. The Commerce dashboard shows the new charge.

4

Set Up a Backend Workflow Webhook for Payment Confirmation

The checkout redirect does NOT confirm payment. A customer could close the browser after being redirected to Coinbase. Payment confirmation must come from Coinbase's webhook — an HTTP POST that Coinbase sends to your app when a charge is confirmed on the blockchain. Backend Workflows (API Workflows) are required for this step and need a paid Bubble plan. Enable API Workflows in Bubble: go to Settings → API → check 'This app exposes a Workflow API'. The Backend Workflows section will appear in your editor. Create a new Backend Workflow named 'coinbase_payment_webhook'. Set the method to POST. Click 'Detect request data' — Bubble shows you a URL like: https://your-app.bubbleapps.io/api/1.1/wf/coinbase_payment_webhook Copy this URL. Go to Coinbase Commerce → Settings → Webhook subscriptions → Add endpoint. Paste your Bubble Backend Workflow URL and subscribe to these events: - charge:confirmed (blockchain confirmation received) - charge:failed (charge expired or payment failed) Copy the webhook shared secret from Commerce Settings — you'll need it for verification. Send a test event from Commerce's webhook tester. In Bubble's Backend Workflow editor, you see the detected data structure from the test webhook — the key fields are: event.type (the event name like 'charge:confirmed'), event.data.id (the charge UUID), and event.data.metadata.order_id (your Bubble order ID from Step 2). Build the workflow logic: 1. Condition: only continue when event.type = 'charge:confirmed' (ignore other events) 2. Search for Order where coinbase_charge_id = event.data.id — finds the right Bubble order 3. Make changes to the Order: set status to 'paid', set paid_at to Current date/time 4. Optional: trigger a follow-up workflow (send confirmation email, provision access, etc.) Note on webhook verification: Coinbase Commerce signs webhooks with a X-CC-Webhook-Signature header (HMAC-SHA256 of the raw request body). Bubble's Backend Workflow cannot compute HMAC-SHA256 natively to verify the signature. For production, consider verifying by checking that the event metadata (order_id, amount) matches a real pending order in your database before marking it paid — this prevents forged webhook events from incorrectly marking orders as paid.

coinbase-commerce-webhook.json
1// Coinbase Commerce Webhook Payload
2// POST https://your-app.bubbleapps.io/api/1.1/wf/coinbase_payment_webhook
3
4{
5 "id": "webhook-event-uuid",
6 "type": "charge:confirmed",
7 "data": {
8 "id": "coinbase-charge-uuid",
9 "code": "ABCD1234",
10 "name": "Premium Subscription",
11 "timeline": [
12 { "status": "NEW", "time": "2026-01-09T14:30:00Z" },
13 { "status": "PENDING", "time": "2026-01-09T14:32:00Z" },
14 { "status": "COMPLETED", "time": "2026-01-09T14:38:00Z" }
15 ],
16 "metadata": {
17 "customer_id": "bubble-user-id",
18 "order_id": "bubble-order-id"
19 },
20 "pricing": {
21 "local": { "amount": "29.00", "currency": "USD" },
22 "bitcoin": { "amount": "0.00064153", "currency": "BTC" }
23 }
24 }
25}
26
27// Bubble Backend Workflow steps:
28// 1. Only when: Detected data event type = 'charge:confirmed'
29// 2. Search for Things: Order where coinbase_charge_id = Detected data event data id
30// 3. Make changes to Order: status = 'paid', paid_at = Current date/time

Pro tip: Bubble's webhook endpoint URL changes if you rename the Backend Workflow — update the URL in Commerce's webhook settings if you ever rename the workflow. Also note that Backend Workflow endpoints use a different URL format (/api/1.1/wf/) than Bubble's data API — do not confuse them when registering in Commerce.

Expected result: After a customer completes payment on Coinbase's checkout page, Coinbase sends a webhook POST to your Bubble Backend Workflow. The workflow finds the matching Order by coinbase_charge_id and updates its status to 'paid'. You can verify this by checking your Bubble database after a test payment using Commerce's test mode.

5

Display Real-Time Prices with the API Connector

Now that you have Commerce payments working, add a live price component to your checkout page showing the current cryptocurrency equivalent of the purchase price. This improves the experience by showing customers exactly how much crypto they will pay, updated in real time from Coinbase's public API. This step uses the public price endpoint — no auth required, no API key, no WU cost beyond the API Connector call itself. If you haven't already created a 'Coinbase Prices' API group in Step 1, do that now. Add a 'Convert Currency' call: - Method: GET - Path: /v2/prices/USD-BTC/spot - This returns how much BTC one USD buys — invert it to get BTC per dollar Alternatively, use the spot price endpoint with base and quote reversed: GET /v2/prices/BTC-USD/spot returns USD price of 1 BTC. To show the BTC cost of a $29 item, divide 29 by the returned amount. In your Bubble checkout page, add a Text element beneath the 'Pay with Crypto' button that reads: 'That's approximately [BTC amount] BTC at today's rate.' Use a 'Get data from external API' expression → Coinbase Prices > Spot Price call → data.amount, then apply the division math using Bubble's expression builder. For caching and WU efficiency: if your checkout page has many visitors, consider storing the latest Bitcoin price in an App Data record and refreshing it only once every 30 seconds via a recurring workflow, rather than having every page load trigger an API call. Display the stored price value and show 'Updated [X] seconds ago' using the stored refresh timestamp. RapidDev's team has helped many fintech Bubble apps build crypto payment flows like this — if you want to discuss architecture choices for your specific project, book a free scoping call at rapidevelopers.com/contact.

coinbase-price-display-and-caching.json
1// Display equivalent BTC amount for a $29.00 charge
2// In Bubble Text element:
3// Value: (29 / Coinbase Prices Spot Price's data amount):formatted as number (5 decimal places)
4// Display: 'approx. 0.00064 BTC'
5
6// Caching pattern for high-traffic apps:
7// Data type: AppSettings
8// Fields: btc_usd_price (Text), price_updated_at (Date)
9
10// Recurring workflow (every 30 seconds, on checkout pages):
11// Step 1: Call API > Coinbase Prices > Spot Price
12// Step 2: Make changes to AppSettings:
13// btc_usd_price = Result of Step 1's data amount
14// price_updated_at = Current date/time
15
16// Text element value: Search for AppSettings:first item's btc_usd_price

Pro tip: Commerce charges always show the fiat amount (USD, EUR, etc.) on Coinbase's hosted checkout page — customers see the crypto equivalent there too. Your Bubble UI price display is supplementary. The critical thing is that amounts stored in your Bubble database should always be the authoritative fiat amount (e.g., '29.00 USD'), not the crypto amount which fluctuates between charge creation and payment.

Expected result: The checkout page shows the current Bitcoin equivalent of the charge amount, updating every 30 seconds. Customers can see 'Pay $29.00 USD (approx. 0.00064 BTC at today's rate)' before clicking through to Coinbase Commerce.

6

Add Privacy Rules and Handle the 10,000 req/hr Limit

Before launching, apply Bubble Privacy Rules to protect sensitive financial data in your database, and set up WU-efficient patterns for the API calls. Privacy Rules for Commerce data: Go to Data tab → Privacy → click your 'Order' data type (or whatever you named it). Add a rule: 'This Order's customer = Current User' → check View for all fields. This ensures users can only see their own orders. Without this rule, a logged-in user who knows the order ID could potentially access another user's order details through Bubble's Data API. Privacy Rules for API keys: Coinbase Commerce API keys are stored as Private headers in the API Connector — they never reach the browser. However, if you ever store any Coinbase credentials in the Bubble database (e.g., for multi-account setups), restrict those fields using Privacy Rules. Rate limit management for App API: The authenticated Coinbase App API allows up to 10,000 requests per hour per API key. For price ticker use cases (public, unauthenticated), there is no documented rate limit but best practice is to avoid calling more frequently than every 10 seconds. For portfolio data calls (authenticated), 10,000/hr sounds large but a Bubble app with 1,000 active users each triggering 20 API calls per session = 20,000 calls per hour — exceeding the limit. Cache portfolio data in Bubble's database and refresh on user action (a 'Sync' button), not continuously. Workload Unit (WU) awareness: Each API Connector call consumes WU. For price tickers refreshing every 30 seconds on a busy page, this adds up. Use App Data caching (store the latest price and timestamp, serve from database to page, refresh via a single recurring Backend Workflow) rather than having each page load trigger an API call. Crypto amount storage: Reiterate the critical rule: always store cryptocurrency amounts (BTC, ETH, etc.) as Text type in your Bubble database, never as Number. Bubble's Number type is a JavaScript double-precision float — it cannot represent 0.00031427 BTC accurately. Store the exact string from Coinbase's response and only format for display.

coinbase-privacy-and-wueconomy.json
1// Privacy Rules pattern for Orders data type:
2// Rule: 'This Order's customer is Current User'
3// Check: View (all fields)
4// Purpose: Each user sees only their own orders
5
6// WU-efficient price caching pattern:
7// Instead of: Text element calls Spot Price API on every page load
8// Do instead:
9// 1. AppSettings record stores: btc_price='45231.05', btc_price_updated=timestamp
10// 2. Recurring Backend Workflow (every 30 seconds): refreshes AppSettings price
11// 3. All page Text elements read from AppSettings (database = no API call per user)
12// Result: 2 API calls/minute regardless of how many users are on the page
13
14// Crypto amount field types in Bubble database:
15// CORRECT: coinbase_btc_amount (Text type) = '0.00064153'
16// WRONG: coinbase_btc_amount (Number type) = loses precision

Pro tip: Use Bubble's Logs tab to monitor your API call WU consumption. Filter by 'External API call' events to see which Coinbase calls are running most frequently and how much each costs. This is the fastest way to identify polling patterns that need caching optimization before they appear in your WU bill.

Expected result: Privacy Rules prevent users from viewing each other's order data. Crypto prices load from a cached App Data record rather than triggering a fresh API call per user per page load, keeping WU consumption predictable and the Coinbase rate limit comfortably unused.

Common use cases

Crypto Price Ticker Widget

Display live Bitcoin, Ethereum, and other cryptocurrency spot prices in a Bubble app — on a landing page, dashboard, or marketplace. Uses Coinbase's public price endpoints with no authentication, no API key, and no Bubble plan restrictions. Refresh automatically every 30 seconds using Bubble's element recurring workflow.

Bubble Prompt

Build a Bubble page that shows live BTC, ETH, and SOL prices in USD, updated every 30 seconds, using Coinbase's public spot price API endpoints — no login required for visitors to see prices.

Copy this prompt to try it in Bubble

Accept Crypto Payments via Coinbase Commerce

Let customers pay for products or subscriptions with cryptocurrency. Create a Coinbase Commerce charge from Bubble, redirect the customer to Coinbase's hosted checkout page, and confirm payment via a Bubble API Workflow webhook. Mark orders as paid in Bubble's database only after confirming the charge:confirmed event.

Bubble Prompt

Build a Bubble checkout flow where customers can pay with crypto via Coinbase Commerce: create a charge, redirect to hosted checkout, confirm payment via webhook, and update the order status to 'paid' in the database.

Copy this prompt to try it in Bubble

Crypto Portfolio Dashboard

Display a user's Coinbase account balances and recent transaction history in a Bubble dashboard. Uses authenticated App API endpoints (GET /v2/accounts) — requires building a Backend Workflow to compute per-request HMAC-SHA256 signatures and execute authenticated calls. Cache results in Bubble's database and refresh on user action.

Bubble Prompt

Build a Bubble portfolio tracker that shows a user's Coinbase wallet balances across BTC, ETH, and USDC, with a transaction history list, refreshing data when the user clicks a 'Sync' button.

Copy this prompt to try it in Bubble

Troubleshooting

Create Charge returns 401 'Unauthorized' even though the API key looks correct

Cause: You are likely mixing up the two Coinbase API products. Commerce API keys (from commerce.coinbase.com) only work with api.commerce.coinbase.com. App API keys (from coinbase.com/settings/api) only work with api.coinbase.com. Using a Commerce key with the App API base URL — or vice versa — produces 401 regardless of key validity.

Solution: Verify which base URL your API Connector group is configured with: https://api.commerce.coinbase.com for Commerce (payments), https://api.coinbase.com for App API (prices, portfolio). Match the key type to the base URL. If you are unsure which key you have, check where you generated it: commerce.coinbase.com → Settings → API Keys = Commerce key; coinbase.com/settings/api = App API key.

Commerce webhook is not firing or Bubble's Backend Workflow is not receiving events

Cause: Common causes: (1) Backend Workflow URL was copied before Bubble generated it (get a fresh URL from the workflow), (2) 'This app exposes a Workflow API' is not enabled in Bubble Settings → API, (3) the webhook endpoint was registered before you ran 'Detect request data', so Coinbase is POSTing to a non-initialized endpoint, or (4) the app is on Bubble's free plan which does not support Backend Workflows.

Solution: Go to Settings → API in Bubble and confirm 'This app exposes a Workflow API' is checked. Open your Backend Workflow editor and verify the workflow named 'coinbase_payment_webhook' exists. Click 'Detect request data' in the workflow, then use Coinbase Commerce's webhook tester to send a test event. Only after successful detection should you copy and register the final endpoint URL in Commerce. Ensure you are on a paid Bubble plan.

Spot price API call Initialization fails with 'There was an issue setting up your call'

Cause: Bubble's Initialize Call requires a successful HTTP response with real data. If the endpoint path is incorrect, or if you accidentally added an API key header to a public endpoint that expects no auth, the Initialize Call may fail. Also, adding a body to a GET request in the API Connector can cause issues.

Solution: For the public spot price endpoint, ensure the API call has: Method = GET, Path = /v2/prices/BTC-USD/spot, no body, no auth headers. If you placed the Spot Price call inside an API group that has shared auth headers (like X-CC-Api-Key), the header is sent with public calls too — Coinbase's public endpoints ignore extra headers, but verify the Initialize Call is pointing to the correct path. Remove any accidental body content from the GET call.

Commerce charge shows as 'Expired' on Coinbase's dashboard and the hosted_url no longer loads

Cause: Coinbase Commerce charges expire after 1 hour. If a customer did not complete payment within that window, or if your app created the charge but the customer navigated away, the charge expires. The hosted_url returns a 'Charge expired' page after expiry.

Solution: Store 'coinbase_charge_created_at' in your Bubble Orders table. Before opening the hosted_url (or when the user returns to checkout), check if created_at is more than 50 minutes ago. If so, run the 'Create Charge' API call again to create a fresh charge, update the Order record with the new charge_id and hosted_url, then redirect to the new URL. Show a message like 'Your payment link was refreshed — click to continue checkout.'

Bitcoin or Ethereum amounts display incorrectly with rounded or wrong decimal values

Cause: Bubble's Number data type stores values as JavaScript floating-point doubles, which cannot represent small decimal values like 0.00031427 BTC with full precision. If you stored the amount as a Number and then retrieved it, precision is lost.

Solution: Change the Bubble database field type for any cryptocurrency amount from Number to Text. Store the exact string from Coinbase's response (e.g., '0.00031427'). When displaying in the UI, use Bubble's ':formatted as number' expression only at display time — never convert to Number for storage. For math operations (like adding amounts), perform them in Bubble's expression builder as text-to-number conversions for display only.

Best practices

  • Always use the correct base URL for each Coinbase product: api.coinbase.com for App API (prices, portfolio) and api.commerce.coinbase.com for Commerce (payments) — using the wrong URL with the wrong key causes 401 errors that look like authentication failures.
  • Store all cryptocurrency amounts (BTC, ETH, SOL, etc.) as Text type in Bubble's database — never as Number — to prevent floating-point precision loss on small decimal values like 0.00031427 BTC.
  • Always store Commerce API keys in the API Connector's 'Private' header field — the X-CC-Api-Key header must have the Private checkbox enabled so the key stays on Bubble's servers and never appears in browser network traffic.
  • Cache cryptocurrency price data in Bubble's App Data rather than triggering a new API call on every page load — refresh the cached price via a single recurring Backend Workflow every 30 seconds and serve the cached value to all users.
  • Build expired-charge detection for Commerce payments by storing 'coinbase_charge_created_at' alongside the charge ID — check if the timestamp is more than 50 minutes old and recreate the charge automatically if needed.
  • Confirm Commerce payments only via webhook (Backend Workflow), never by trusting the redirect URL callback — customers can be redirected to your thank-you page without having paid if they manipulate the URL.
  • Apply Bubble Privacy Rules to Order data types so that each user can only see their own orders — without Privacy Rules, any logged-in user can query another user's orders through Bubble's Data API.
  • For authenticated App API endpoints (portfolio data), design a caching layer using Bubble's database — store account balances and refresh on user action (a 'Sync' button), not on a continuous poll, to avoid consuming all 10,000 req/hr on a busy app.

Alternatives

Frequently asked questions

Do I need a Coinbase account to display live crypto prices in Bubble?

No. Coinbase's spot price endpoints (GET /v2/prices/BTC-USD/spot) are completely public and require no API key, no authentication, and no Coinbase account. You can add them to Bubble's API Connector and display live prices immediately. This also means no rate limit concerns for basic price ticker use cases.

Can I accept crypto payments on Bubble's free plan?

You can display prices on the free plan. However, Commerce payment confirmation via webhook requires a Bubble Backend Workflow (API Workflow), which is only available on paid Bubble plans. Without the webhook, you cannot reliably confirm payments — you should not mark orders as paid based on the redirect URL alone. Upgrade to a paid plan before building a Commerce payment flow.

What is the difference between Coinbase App API and Coinbase Commerce?

Coinbase App API (api.coinbase.com) is for accessing cryptocurrency market data (spot prices, exchange rates) and — with authentication — a user's own Coinbase account balances and transaction history. Coinbase Commerce (api.commerce.coinbase.com) is a merchant payment tool for accepting crypto payments from customers, with hosted checkout pages and webhooks. They have completely separate API keys and base URLs. Mixing them up causes 401 errors.

Why do Commerce charges expire after 1 hour?

Coinbase Commerce charges display a specific cryptocurrency amount at creation time (e.g., '0.00064 BTC = $29'). Because crypto prices fluctuate, Coinbase sets a 1-hour expiry to limit the price risk. After 1 hour, the exchange rate may have moved significantly and Coinbase closes the charge to prevent under/overpayment. Build your Bubble app to detect expired charges and recreate them automatically when a customer returns to checkout after a delay.

How do I test Coinbase Commerce webhooks locally or in a Bubble development environment?

Coinbase Commerce's webhook tester (in Settings → Webhook subscriptions) sends real test events to any URL you register. In Bubble development (non-live version), your Backend Workflow endpoint URL includes '/version-test/' in the path. Register that test URL in Commerce's webhook settings during development. Switch to the live URL when you deploy. Bubble's Workflow Logs tab will show you every incoming webhook request and whether your workflow ran successfully.

Can I build a portfolio tracker that shows a user's Coinbase account balances?

Yes, but it requires authenticated App API endpoints that need per-request HMAC-SHA256 signatures. Bubble's API Connector cannot compute HMAC-SHA256 natively — the signature must be computed externally and passed to the Connector. You can build a Backend Workflow that calls a small external signing function (or use a tool like Make/Zapier as an intermediary) to compute the signature and then make the authenticated Coinbase API call. This is an advanced integration pattern beyond basic API Connector usage.

RapidDev

Talk to an Expert

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

Book a free consultation

Integrations are where projects stall

We wire Bubble integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

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.