Crypto Payments Integration in WooCommerce
WooCommerce doesn't have native crypto support, so integration is built via one of two approaches: ready-made payment processor plugin (CoinGate, NOWPayments, Coinbase Commerce) or custom WooCommerce payment gateway for working with your own wallet. The choice is determined by whether you need custodial or non-custodial scheme.
Option 1: Payment Processor (Fast, With Fees)
The most common options:
CoinGate WooCommerce Plugin — official plugin, supports 70+ coins, payouts in EUR/USD. Installation via wp-admin → Plugins. Setup takes 15 minutes if CoinGate account is already verified.
NOWPayments — similar service, focus on privacy coins (XMR, ZCash). Plugin on WordPress.org.
BTCPay Server — self-hosted processor, non-custodial (you control keys). More DevOps work, but 0% processor fees. Recommended for projects with serious transaction volume.
Option 2: Custom WooCommerce Gateway
If you need integration with your own infrastructure (own node, specific coin, special logic), we write a custom payment gateway.
WooCommerce Payment Gateway Structure
class WC_Crypto_Gateway extends WC_Payment_Gateway {
public function __construct() {
$this->id = 'crypto_gateway';
$this->method_title = 'Crypto Payment';
$this->method_description = 'Accept cryptocurrency payments';
$this->has_fields = false;
$this->supports = ['products'];
$this->init_form_fields();
$this->init_settings();
$this->title = $this->get_option('title');
$this->description = $this->get_option('description');
$this->api_key = $this->get_option('api_key');
add_action('woocommerce_update_options_payment_gateways_' . $this->id,
[$this, 'process_admin_options']
);
add_action('woocommerce_api_' . $this->id, [$this, 'handle_webhook']);
}
public function process_payment($order_id) {
$order = wc_get_order($order_id);
// Create payment request via our API
$payment = $this->create_crypto_payment([
'amount' => $order->get_total(),
'currency' => get_woocommerce_currency(),
'order_id' => $order_id,
'callback_url' => WC()->api_request_url($this->id),
'success_url' => $this->get_return_url($order),
]);
if (is_wp_error($payment)) {
wc_add_notice('Payment error: ' . $payment->get_error_message(), 'error');
return ['result' => 'fail'];
}
// Save external ID for reconciliation
$order->update_meta_data('_crypto_payment_id', $payment['id']);
$order->update_status('pending', 'Awaiting crypto payment');
$order->save();
return [
'result' => 'success',
'redirect' => $payment['payment_url'],
];
}
public function handle_webhook() {
$payload = file_get_contents('php://input');
$data = json_decode($payload, true);
if (!$this->verify_webhook_signature($payload, $_SERVER['HTTP_X_SIGNATURE'] ?? '')) {
status_header(400);
exit('Invalid signature');
}
$order = wc_get_order($data['order_id']);
if (!$order) {
status_header(404);
exit('Order not found');
}
switch ($data['status']) {
case 'paid':
$order->payment_complete($data['payment_id']);
$order->add_order_note(sprintf(
'Crypto payment confirmed. Received %s %s',
$data['amount_received'],
$data['currency']
));
break;
case 'expired':
$order->update_status('cancelled', 'Crypto payment expired');
break;
case 'underpaid':
$order->update_status('on-hold', sprintf(
'Underpayment: expected %s, received %s',
$data['amount_expected'],
$data['amount_received']
));
break;
}
status_header(200);
exit('OK');
}
}
// Register gateway
add_filter('woocommerce_payment_gateways', function($gateways) {
$gateways[] = 'WC_Crypto_Gateway';
return $gateways;
});
Plugin Registration
// crypto-payment-gateway.php (in wp-content/plugins/)
/**
* Plugin Name: Crypto Payment Gateway
* Description: Custom cryptocurrency payment gateway
* Version: 1.0.0
* Requires Plugins: woocommerce
*/
if (!defined('ABSPATH')) exit;
add_action('plugins_loaded', function() {
if (!class_exists('WC_Payment_Gateway')) return;
require_once plugin_dir_path(__FILE__) . 'includes/class-wc-crypto-gateway.php';
});
Edge Cases Handling
Exchange rate difference: 10–20 minutes pass between order creation and payment. Rate may change during this time. Solution: fix crypto amount at order creation, set order expiration (15–20 minutes), recalculate at current rate after expiration.
Partial payment: user sent less than required. Status on-hold, manual manager handling. Alternative — hold funds and offer to top up.
Duplicate webhook: webhook may arrive twice. Check _crypto_payment_id before status change — if order already completed, don't change.
Testing
Must test in sandbox mode with real scenarios:
- Successful full amount payment
- Order expiration
- Underpayment
- Duplicate webhook
WooCommerce has convenient tool — WC_Logger:
$logger = wc_get_logger()
$logger->debug('Webhook received', ['source' => 'crypto-gateway', 'data' => $data])
Logs accessible at WooCommerce → Status → Logs.
What's Included
- Selection and configuration of payment provider or custom gateway development
- WooCommerce payment gateway class implementation
- Webhook handler with signature verification
- Handling all order statuses and edge cases
- Testing in sandbox environment







