Coinbase Commerce
Coinbase Commerce is a crypto payment gateway that lets your store accept payment in major cryptocurrencies directly to a self-custody wallet. Customers pay in Bitcoin (BTC), Ethereum (ETH), USD Coin (USDC), Dogecoin (DOGE), Litecoin (LTC), DAI, or Bitcoin Cash (BCH) — the plugin surfaces all supported currencies at checkout. Because payments settle on the blockchain rather than through a bank, there are no chargebacks, and funds arrive in your Coinbase Commerce wallet without a traditional payment processor sitting in the middle.
This plugin is a separate add-on available from the J2Commerce Extensions Store. It is not included with the core J2Commerce component.
Important Notice — Coinbase Commerce Sunset (November 2024)
Coinbase announced in late 2024 that the hosted Commerce checkout is no longer available to new merchants. If you created a Coinbase Commerce account before the sunset date, your account and API access remain fully functional — this plugin continues to work for you without any changes required.
If you are setting up a new store, Coinbase Commerce is not an option for you. Consider these alternatives that are still open for new sign-ups:
- NOWPayments — multi-coin processor with hosted and API modes
- BTCPay Server — self-hosted, open-source, no fees
- OpenNode — Lightning Network–focused Bitcoin processor
Prerequisites
Before configuring the plugin, make sure you have:
- A Coinbase Commerce account created before the November 2024 sunset
- Your API Key — found at commerce.coinbase.com/dashboard/settings under the API keys tab
- Your Webhook Shared Secret — displayed when you create a webhook endpoint in the same settings page (the secret is shown only once, so copy it immediately)
- J2Commerce installed and configured with at least one product and a working checkout
Installation
This plugin is a separate add-on available from the J2Commerce Extensions Store.
- Purchase and download the
plg_j2commerce_payment_coinbase.zippackage from the J2Commerce website. - Go to System -> Install -> Extensions.
- Upload the
plg_j2commerce_payment_coinbase.zipfile using the Upload Package File tab. - The plugin installs automatically.
Enabling the Plugin
After installation the plugin is disabled by default.
- Go to System -> Manage -> Plugins.
- Search for Coinbase in the filter bar.
- Click the red circle next to J2Commerce - Payment - Coinbase Commerce to enable it (turns green).
Configuration
Click the Toggle Inline Help button in the toolbar and the app will show a description below each field as you configure it.
Once enabled, open the plugin to configure it.
- Go to J2Commerce -> Payments -> Payment Methods.
- Find Coinbase Commerce and click its name to open the settings.
Work through each field in order.
Display Settings
| Field | What it does | Recommended value |
|---|---|---|
| Display Name | The payment option label shown at checkout | Coinbase Commerce (BTC, ETH, USDC, DOGE, LTC, etc.) or your preferred shorter label |
| Display Image | Optional logo shown next to the payment name at checkout | Upload from media/plg_j2commerce_payment_coinbase/images/payment_coinbase.webp, or leave blank |
Coinbase Payment Mode
| Field | Description | Options |
|---|---|---|
| Coinbase Payment Mode | Controls how the customer pays | Redirect (hosted on Coinbase) or Modal (on your site) |
See Choosing Redirect vs Modal below for guidance on which to choose.
API Credentials
| Field | What to enter | Required |
|---|---|---|
| Coinbase Commerce API Key | The API key from your Coinbase Commerce dashboard settings | Yes |
| Coinbase Webhook Shared Secret | The shared secret shown when you add a webhook endpoint in Coinbase Commerce | Yes — without it, webhooks are silently rejected and orders will not update |
| Your Webhook Endpoints | Read-only field. Displays the two URLs to paste into Coinbase Commerce | — |
Order Status
These three fields control what J2Commerce order status is assigned when Coinbase reports each payment event.
| Field | Default | When it triggers |
|---|---|---|
| Confirmed Status | Confirmed (1) | Coinbase reports charge:confirmed or charge:resolved |
| Pending Status | Pending (4) | Coinbase reports charge:pending (awaiting blockchain confirmation) |
| Failed Status | Failed (3) | Coinbase reports charge:failed |
The defaults match the standard J2Commerce order status IDs and work for most stores. Change them if you use custom order statuses.
Note on charge:resolved: Coinbase uses this event when a charge was overpaid or underpaid and a Coinbase support agent has manually resolved it. The plugin treats charge:resolved the same as charge:confirmed — both move the order to your Confirmed Status. This is the correct behavior for almost all cases.
NOTE: If the status you want isn't listed in the dropdown menu, you can create a new one by going to J2Commerce -> Setup -> Order Statuses

Surcharge (Optional)
You can add an optional processing fee when customers choose Coinbase as their payment method. Leave both fields empty if you do not want a surcharge.
| Field | Description | Example |
|---|---|---|
| Surcharge Name | Label shown on the order for the fee | Crypto processing fee |
| Surcharge Percent | Percentage of the order total (before the fixed fee) | 1.5 |
| Surcharge Fixed | Flat fee added in addition to the percentage | 0.50 |
| Surcharge Tax Class | Tax profile to apply to the surcharge amount | Leave blank if the surcharge is not taxable |
Availability Restrictions (Optional)
Use these to limit when Coinbase Commerce appears as a payment option.
| Field | Description | Example |
|---|---|---|
| Minimum Subtotal | Hide this payment method if the cart subtotal is below this amount | 10.00 |
| Maximum Subtotal | Hide this payment method if the cart subtotal exceeds this amount | 5000.00 |
| Geozone Restriction | Limit availability to customers in a specific geozone | Select a geozone, or leave blank for all countries |
Custom Messages
These fields accept plain text or HTML and appear at specific points in the checkout flow.
| Field | When it appears |
|---|---|
| On Selection | When the customer selects Coinbase as their payment method |
| On Before Payment | Just before the payment form is shown |
| On After Payment | After the customer returns from Coinbase (success page) |
| On Error Payment | If a payment error occurs |
| On Cancel Payment | If the customer cancels and returns without paying |
Thank You Article
You can select a Joomla article to display on the post-payment success page. Leave blank to use the default confirmation message.
Button Text
The Button Text field customises the label on the "Place Order" button. The default value is Place Order.
Debug Logging
| Field | Description | Default |
|---|---|---|
| Debug Logging | Writes detailed request and response data to administrator/logs/plg_j2commerce_payment_coinbase.php | No |
Enable this only when diagnosing a problem. Disable it again in production — log files can grow large and may contain transaction data.
Choosing Redirect vs Modal
The Coinbase Payment Mode field gives you two checkout experiences.
Redirect (recommended)
The customer is sent to a Coinbase-hosted payment page and returns to your store after paying.
Pros:
- Coinbase maintains the payment UI — no CSS work required on your end
- Works reliably across all browsers and devices
- Handles the countdown timer and multi-currency display natively
Cons:
- The customer briefly leaves your site
- You have no control over the visual design of the payment page
Use this if you want the simplest setup, or if you are not confident testing modal overlays across browsers. It is the default, and the right choice for most stores.
Modal (on your site)
A payment overlay appears inline on your checkout page. The customer can see the crypto address, copy it, pick a different coin, and confirm payment without navigating away.
Pros:
- The customer never leaves your store
- Crypto addresses are copyable directly from your checkout page
- Better for customers who prefer to copy addresses manually into their wallet app
Cons:
- Requires more cross-browser testing
- CSS may need adjustments depending on your template
- If JavaScript fails to load, the customer sees a fallback form instead of the modal
Use this if your customer base is technically comfortable with crypto, or if keeping the customer on-site is a priority for your conversion rate.
Webhook Configuration
Webhooks are how Coinbase Commerce tells your store that a payment has been confirmed, is pending, or has failed. Without a working webhook, orders stay in their initial state regardless of what happens on the blockchain.
Step 1: Copy Your Webhook URL
In the plugin settings, the Your Webhook Endpoints field displays two URLs.
- Primary endpoint — matches the checkout confirmation URL pattern used by J2Commerce
- Alternate endpoint (com_ajax) — routes through Joomla's
com_ajaxhandler; use this if URL rewriting causes problems
Copy the Primary endpoint URL first. It looks like:
https://yoursite.com/index.php?option=com_j2commerce&view=checkout&task=confirmPayment&orderpayment_type=payment_coinbase&paction=process&tmpl=component
Step 2: Add the Endpoint in Coinbase Commerce
- Log in to commerce.coinbase.com/dashboard/settings.
- Scroll to Webhook subscriptions.
- Click Add an endpoint.
- Paste the Primary endpoint URL from the plugin settings.
- Click Save.
Coinbase will display a Shared Secret — copy it immediately, as it is shown only once.
Step 3: Save the Shared Secret
- Return to the Coinbase plugin settings in your Joomla admin.
- Paste the shared secret into the Coinbase Webhook Shared Secret field.
- Click Save (or Save & Close).
Step 4: Test the Webhook
Back in your Coinbase Commerce settings, use the Send test webhook button to send a test event to your endpoint. The plugin should return one of these responses:
| Response | Meaning |
|---|---|
Ok, Processed | Webhook arrived, signature verified, order updated |
IPN Ok (ignored event type) | Webhook arrived but the event type is informational only (e.g., charge:created) — no action needed |
IPN Misconfigured | The webhook secret field in the plugin is empty |
IPN Rejected | Signature verification failed |
A test webhook from Coinbase uses a synthetic event type that the plugin receives but does not act on — you will see IPN Ok (ignored event type). That is correct.
If the Primary Endpoint Does Not Work
Some URL rewriting plugins (sh404SEF, JoomSEF, Route66) and web application firewalls (Cloudflare, mod_security) intercept requests at the primary URL and strip the X-CC-Webhook-Signature header that Coinbase includes.
If you see IPN Rejected and your shared secret is definitely correct:
- Switch to the Alternate endpoint (com_ajax) URL instead.
- Update the endpoint URL in your Coinbase Commerce dashboard.
- Test again.
The com_ajax URL bypasses template and SEF routing, making it more compatible with aggressive URL rewriting.
Order Status
NOTE: If the status you want isn't listed in the dropdown menu, you can create a new one by going to J2Commerce -> Setup -> Order Statuses
When Coinbase sends a webhook to your store, the plugin maps the event type to an order status.
| Coinbase Event | What it means | Default Order Status |
|---|---|---|
charge:pending | Payment broadcast to the network; waiting for blockchain confirmations | Pending (4) |
charge:confirmed | Enough confirmations received; payment is trustworthy | Confirmed (1) |
charge:resolved | Charge was overpaid or underpaid; manually resolved by Coinbase | Confirmed (1) |
charge:failed | The charge window expired or payment did not arrive | Failed (3) |
Events like charge:created and charge:delayed are received and acknowledged but do not trigger a status change. The plugin responds IPN Ok for those events.
Surcharges and Subtotal Limits
Adding a Processing Fee
If you want to pass on a small handling fee to customers who pay with crypto:
- Enter a label in Surcharge Name (e.g.,
Crypto network fee). - Enter a percentage in Surcharge Percent (e.g.,
1for 1%) or a fixed amount in Surcharge Fixed (e.g.,0.50). - You can combine both — the percentage is calculated first, then the fixed amount is added.
- If the fee is taxable, select a tax class in Surcharge Tax Class.
Restricting to Certain Order Sizes
If you only want Coinbase Commerce available for orders above or below certain amounts:
- Set Minimum Subtotal to hide the payment option for small orders (e.g., set to
50.00to require at least $50). - Set Maximum Subtotal to hide it for very large orders (e.g.,
2000.00if you want to verify large transactions manually).
Leave both fields empty to allow all order sizes.
Testing the Payment Flow
Coinbase Commerce provides a sandbox environment through their dashboard. To test without real money:
-
In your Coinbase Commerce dashboard, switch to a test environment if available for your account type.
-
Place a test order on your store and select Coinbase Commerce as the payment method.
-
Depending on your mode setting:
- Redirect — you are taken to the Coinbase hosted checkout page
- Modal — the crypto address overlay appears on your checkout page
-
Complete the test payment.
-
Verify in J2Commerce -> Sales -> Orders that the order has:
- A Transaction ID (the Coinbase charge code, e.g.,
ABCD1234) - An updated Order Status matching your Confirmed Status setting
- A Transaction ID (the Coinbase charge code, e.g.,
-
Check the order history tab on the order to confirm the webhook arrived and recorded the event.
What's New in J2Commerce 6
This plugin was fully rewritten for J2Commerce 6. If you used the J2Store v4 version of this plugin, here is what changed:
- No jQuery — the modal checkout UI uses vanilla JavaScript. No jQuery dependency.
- HMAC signature verification uses PHP's constant-time
hash_equalsfunction, preventing timing-based attacks against the webhook secret comparison. - HTTP requests use Joomla's built-in
HttpFactoryinstead of raw cURL calls, making the plugin compatible with any HTTP transport adapter configured in Joomla. - Order status transitions go through J2Commerce's
OrderModel::updateOrderStatus()method. This means order history is logged correctly and status-change email notifications fire as expected — the same as any other payment plugin. - Surcharge, subtotal limits, and geozone restriction are fully implemented, matching the feature parity of the PayPal plugin.
- Assets are registered via Joomla's Web Asset Manager. No inline
<link>or<script>tags are injected into the page. - Backwards compatibility — in-flight charges created under the J2Store v4 plugin are still accepted by the webhook handler. The origin hash logic accepts both the old J2Store and new J2Commerce format.
Troubleshooting
"IPN Misconfigured" — orders never update after payment
Cause: The Coinbase Webhook Shared Secret field in the plugin settings is empty.
Solution:
- Log in to commerce.coinbase.com/dashboard/settings.
- Open your webhook endpoint.
- Copy the shared secret (you may need to regenerate it if you did not save it originally).
- Paste it into the Coinbase Webhook Shared Secret field in the plugin settings and save.
"IPN Rejected" — webhook arrives but is refused
Cause 1: The shared secret in the plugin does not match the one in your Coinbase Commerce dashboard.
Solution: Double-check both values. Even a single extra space will cause a mismatch.
Cause 2: A security plugin, CDN (such as Cloudflare), or mod_security rule is stripping the X-CC-Webhook-Signature HTTP header before it reaches PHP.
Solution: Switch to the Alternate endpoint (com_ajax) URL. Update the endpoint URL in your Coinbase Commerce dashboard and test again. If the problem persists, temporarily disable mod_security or add an exclusion rule for your webhook URL, then test.
"Order ID empty or did not match" — webhook arrives but order is not found
Cause: The metadata.order_id field in the Coinbase charge was not set correctly, or the order was deleted after the charge was created.
Solution:
- Enable Debug Logging in the plugin settings.
- Place a new test order and check
administrator/logs/plg_j2commerce_payment_coinbase.phpfor the raw webhook payload. - Confirm the
metadata.order_idvalue matches an existing order in J2Commerce. - If orders are being deleted and recreated (e.g., by a cron job or cleanup script), stop that process before payments can arrive.
Customer paid but order is stuck on "Pending" or initial status
Cause: The webhook did not arrive or was not processed. Common reasons:
- The webhook URL is misconfigured in Coinbase Commerce
- The shared secret is wrong
- Debug logging is off so there is no record of what happened
Solution:
- Enable Debug Logging and reproduce the issue.
- Open
administrator/logs/plg_j2commerce_payment_coinbase.phpand look for any error entries. - Check the Coinbase Commerce dashboard webhook delivery log to confirm your endpoint received the event and what HTTP response code it returned.
- If Coinbase shows a delivery failure (non-200 response), check your server logs for the specific PHP or firewall error.
Coinbase does not return a payment URL (Redirect mode)
Cause: The API key is invalid, the Coinbase Commerce account is suspended, or Coinbase returned an unexpected response.
Solution:
- Enable Debug Logging.
- Attempt a checkout and check the log file for the
createChargeentry and any error detail. - Verify the API key in Coinbase Commerce -> Settings -> API Keys is active and has not been revoked.