How to Accept Crypto Payments in WooCommerce: Plugins, APIs, and Custom Gateways

Published On: March 16th, 2026|Categories: WordPress|10 min read|

Crypto payment support in WooCommerce is not a single toggle. The actual shape of your implementation depends on whether you want immediate fiat settlement, direct wallet custody, or something in between – and each choice carries different technical overhead, fee structures, and compliance surface area.

Plugin-Based Gateways: The Fast Path

The majority of stores reach for a plugin, and for good reason. Solutions like NOWPayments, CoinGate, and Coinbase Commerce register themselves as standard WooCommerce payment gateways via woocommerce_payment_gateways and handle the entire checkout flow inside an iframe or redirect. The merchant gets a dashboard, auto-conversion to fiat, and no need to touch a node.

NOWPayments processes over 300 coins and settles in fiat within minutes. CoinGate charges a 1% processing fee with no monthly cost. Coinbase Commerce deposits directly to a linked Coinbase account and supports Bitcoin, Ethereum, USDC, and Litecoin out of the box. All three generate a payment address per order and poll for confirmation via their own infrastructure, which means your server never talks to a blockchain node directly.

Installation is the same pattern for all of them.

// Example: registering a crypto gateway class
add_filter( 'woocommerce_payment_gateways', function( $gateways ) {
    $gateways[] = 'WC_My_Crypto_Gateway';
    return $gateways;
} );

The downside is custody. You are trusting the processor to hold funds until settlement, and their uptime is your uptime. If their webhook fails, your order status stays on “pending” until you reconcile manually.

Handling Webhooks Reliably

Every crypto processor fires a webhook when a payment confirms. The payload arrives at your /wc-api/ endpoint and updates the order status. The problem is that confirmation times vary – Bitcoin averages 10 minutes per block, but a single confirmation is often enough for low-value orders, while exchanges require 3-6 for higher amounts.

Building custom PHP webhook endpoints for WooCommerce gives you full control over how each confirmation event maps to an order status transition. The standard plugin approach works fine for most stores, but if you need conditional logic – hold orders above $500 until 3 confirmations, auto-complete orders under $50 on 1 confirmation – you need to intercept the webhook yourself.

add_action( 'woocommerce_api_my_crypto_gateway', function() {
    $payload = json_decode( file_get_contents( 'php://input' ), true );
    $sig     = $_SERVER['HTTP_X_CRYPTO_SIGNATURE'] ?? '';

    if ( ! hash_equals( hash_hmac( 'sha256', file_get_contents( 'php://input' ), MY_CRYPTO_SECRET ), $sig ) ) {
        http_response_code( 401 );
        exit;
    }

    $order_id      = absint( $payload['order_id'] );
    $confirmations = absint( $payload['confirmations'] );
    $order         = wc_get_order( $order_id );

    if ( $order && $confirmations >= 1 ) {
        $order->payment_complete( sanitize_text_field( $payload['txid'] ) );
    }

    http_response_code( 200 );
    exit;
} );

Always verify the HMAC signature before processing. A forged webhook can mark an order as paid without any actual transaction.

Self-Custody with Direct Wallet Integration

If keeping zero counterparty risk matters more than convenience, direct wallet integration is the route. BTCPay Server is the reference implementation here – it is open source, self-hosted, and connects to a full Bitcoin node or a lightweight Electrum server. The WooCommerce plugin for BTCPay Server registers a payment gateway that redirects to your own BTCPay instance.

For Ethereum and ERC-20 tokens, the pattern shifts. You generate a unique receiving address per order using HD wallet derivation (BIP-44), monitor that address for incoming transactions via an Ethereum node or a provider like Infura, then fire your own webhook internally when the balance changes. This is non-trivial to maintain but gives you full custody and zero processor fees beyond gas.

Stores processing high order volumes should pair this with database indexing strategies for WooCommerce – address generation and balance polling can create write-heavy patterns in wp_postmeta if order meta is not structured carefully.

Stablecoin Payments: Less Volatility, Same Infrastructure

Bitcoin and Ethereum prices move fast enough that a customer who initiates checkout and waits 3 minutes might face a meaningfully different USD equivalent by the time they submit. Stablecoins solve this. USDC, USDT, and DAI are pegged to the dollar and run on Ethereum, Polygon, Solana, and other chains.

Accepting USDC on Polygon via a plugin like CoinGate or NOWPayments requires no code change from the merchant side – you enable the token in the plugin settings. The transaction fee on Polygon is fractions of a cent, which makes it practical even for small purchases where Bitcoin’s variable fees would consume a meaningful percentage of the order value.

For stores already evaluating WooCommerce as their long-term platform, stablecoin support is a low-risk way to test crypto adoption without exposing the business to price volatility. Settlement in USDC can be converted to fiat on-demand via any exchange API.

Building a Custom Payment Gateway Class

When no plugin fits – different blockchain, proprietary processor contract, or specific UX requirements – the answer is a custom gateway. WooCommerce‘s WC_Payment_Gateway class is the extension point.

class WC_Custom_Crypto_Gateway extends WC_Payment_Gateway {

    public function __construct() {
        $this->id                 = 'custom_crypto';
        $this->method_title       = 'Custom Crypto';
        $this->has_fields         = false;
        $this->init_form_fields();
        $this->init_settings();
        $this->title              = $this->get_option( 'title' );
        add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, [ $this, 'process_admin_options' ] );
    }

    public function process_payment( $order_id ) {
        $order   = wc_get_order( $order_id );
        $address = $this->generate_payment_address( $order_id );

        $order->update_meta_data( '_crypto_payment_address', $address );
        $order->update_meta_data( '_crypto_amount_due', $this->convert_to_crypto( $order->get_total() ) );
        $order->update_status( 'pending', __( 'Awaiting crypto payment.', 'your-plugin' ) );
        $order->save();

        return [
            'result'   => 'success',
            'redirect' => $this->get_return_url( $order ),
        ];
    }

    private function generate_payment_address( int $order_id ): string {
        // Call your processor API or HD wallet derivation here
        return apply_filters( 'my_crypto_generate_address', '', $order_id );
    }

    private function convert_to_crypto( float $fiat_amount ): float {
        // Fetch live rate from your preferred price API
        $rate = (float) get_transient( 'crypto_usd_rate' );
        return $rate > 0 ? round( $fiat_amount / $rate, 8 ) : 0.0;
    }
}

Cache your exchange rate in a transient with a 60-second TTL to avoid hammering the price API on every checkout page load. A stale rate is preferable to a gateway timeout that blocks the checkout flow entirely.

Security Considerations for Crypto Checkouts

Accepting cryptocurrency introduces attack surface that standard payment gateways do not have. A compromised webhook secret allows an attacker to mark orders as paid. A stolen private key means loss of all funds in that wallet with no chargeback mechanism.

Locking down the WordPress admin with 2FA and SSH-restricted access is the minimum baseline. Private keys and API secrets should never live in wp-config.php alongside database credentials – use environment variables loaded via the server configuration, outside the web root.

Order status transitions driven by webhook data should always be idempotent. If the same txid arrives twice, the second call should not duplicate the payment_complete() call or fire confirmation emails a second time. Store processed transaction IDs in order meta and check before acting.

$processed = $order->get_meta( '_processed_txids', true );
$txids     = $processed ? json_decode( $processed, true ) : [];

if ( in_array( $txid, $txids, true ) ) {
    http_response_code( 200 );
    exit; // Already handled
}

$txids[] = $txid;
$order->update_meta_data( '_processed_txids', wp_json_encode( $txids ) );
$order->payment_complete( $txid );
$order->save();

Order Management and HPOS Compatibility

WooCommerce High-Performance Order Storage changes how order meta is stored and queried. Any custom gateway that reads or writes order meta needs to use the CRUD methods (get_meta, update_meta_data, save) rather than raw get_post_meta / update_post_meta calls. A gateway that bypasses the order object and writes directly to wp_postmeta will break silently on stores with HPOS enabled.

Stores facing query slowdowns from crypto order meta lookups should review HPOS query optimization – querying _crypto_payment_address across thousands of orders without a custom index can push query time from 30ms to 400ms on a mid-traffic store.

Choosing the Right Approach

The decision tree is fairly direct. Low volume, multiple coins, no dev overhead: use NOWPayments or CoinGate. High volume with Bitcoin focus and full custody requirements: deploy BTCPay Server. Custom blockchain or bespoke processor: extend WC_Payment_Gateway directly. Stablecoin-only with near-zero fees: Polygon USDC via any major plugin.

You can explore the broader WooCommerce development category for more on payment gateway architecture, checkout customization, and performance patterns that apply regardless of which payment method you add. The crypto category covers wallet setup, token types, and exchange integrations that inform the processor selection decisions above.

None of these approaches requires a blockchain developer on staff. The custom gateway path does require solid PHP and familiarity with WooCommerce’s order lifecycle, but the extension points are well-documented and the HMAC verification pattern shown above covers the security-critical portion of any integration.

Често задавани въпроси

  1. What is the easiest way to accept Bitcoin in WooCommerce?

    Install a plugin like NOWPayments or CoinGate. Both register as standard WooCommerce gateways, handle address generation, and can auto-convert to fiat. Setup takes under 15 minutes with no custom code.

  2. Does accepting crypto in WooCommerce require a blockchain node?

    No – processor-based plugins (NOWPayments, CoinGate, Coinbase Commerce) handle all blockchain communication on their end. Only self-hosted solutions like BTCPay Server require running or connecting to a node.

  3. How do I prevent duplicate order completions from crypto webhooks?

    Store each processed transaction ID in order meta and check for it before calling payment_complete(). If the txid already exists in meta, return a 200 response and exit without re-processing.

  4. Are WooCommerce crypto plugins compatible with HPOS?

    Major plugins like CoinGate and NOWPayments have updated their WooCommerce integrations for HPOS compatibility. Custom gateways must use the WC_Order CRUD methods rather than direct postmeta functions to remain compatible.

  5. What are the transaction fees for crypto payments in WooCommerce?

    CoinGate charges 1% per transaction with no monthly fee. NOWPayments charges 0.5-1% depending on volume. BTCPay Server has no processing fee – you only pay the network transaction fee, which varies by blockchain and congestion.




Related Articles

If you enjoyed reading this, then please explore our other articles below:

More Articles

If you enjoyed reading this, then please explore our other articles below: