Bitcoin Lightning Payment Gateway for WooCommerce (via CLINK)

August 9, 2026 · View on GitHub

Accept Bitcoin Lightning payments on your WooCommerce store via the CLINK protocol (clinkme.dev). Customers pay with ShockWallet.app, ZEUS, BXRD.app, Amethyst, or any other CLINK-compatible Lightning wallet. All transmitted privately and anonymously via relays of the Nostr protocol. Read the original public announcement to learn more.

Demo: woo-clink.wasmer.app Plugin: github.com/WoompaLoompa/woo-clink Wordpress: https://wordpress.org/plugins/clink-gateway-for-woocommerce/

How It Works

  1. Merchant generates a CLINK Offer string (noffer1...) from their CLINK-compatible Lightning node (ShockWallet, Lightning.Pub, etc.)
  2. Customer checks out and selects "Lightning (CLINK)" as payment method
  3. The plugin uses the noffer to request a BOLT 11 Lightning invoice from the merchant's node over Nostr
  4. Customer scans the QR code and pays with any Lightning wallet
  5. Payment is confirmed via CLINK protocol receipt — order is marked complete

No web server required for the Lightning node. All communication flows over Nostr relays.

Requirements

  • WordPress 5.8+
  • WooCommerce 6.0+
  • PHP 7.4+
  • A CLINK-compatible Lightning wallet/node (ShockWallet, Lightning.Pub, ZEUS, Amethyst)

Installation

From WordPress Admin

  1. Download the latest release .zip from the releases page
  2. Go to Plugins > Add New > Upload Plugin
  3. Upload the .zip and activate
  4. Go to WooCommerce > Settings > Payments > CLINK (Lightning) to configure

Manual

# Navigate to your WordPress plugins directory
cd wp-content/plugins/

# Clone the repository
git clone https://github.com/WoompaLoompa/woo-clink.git woocommerce-clink-gateway

# Install JS dependencies and build (optional — pre-built bundle included)
cd woocommerce-clink-gateway
npm install && npm run build

Then activate the plugin from the WordPress admin.

Configuration

Navigate to WooCommerce > Settings > Payments > CLINK (Lightning).

SettingDescription
Enable/DisableTurn the gateway on/off
TitlePayment method title shown at checkout
DescriptionPayment method description shown at checkout
CLINK Offer StringYour noffer1... string from ShockWallet / Lightning.Pub
Bitcoin NetworkThe network your CLINK offer operates on: Mainnet, Testnet, or Regtest. Invoices from a different network are rejected.
Fixed BTC RateOptional — set a fixed BTC price in your currency instead of live CoinGecko rate
Display Amount AsChoose how prices appear on product pages, cart, and checkout: sats, BTC, or ₿ (bip-0177). Overrides WooCommerce frontend prices.
Invoice TimeoutSeconds before the Lightning invoice expires (default: 600)
Poll IntervalMilliseconds between payment status checks (default: 5000)

Product Support

Product TypeSupported
SimpleYes
VariableYes
Digital / VirtualYes
Subscription (initial)Yes
Subscription (auto-renewal)Yes — via CLINK ndebit authorization
Bookings / AppointmentsYes (via WooCommerce core)

Auto-Renewal (Subscriptions)

After the first subscription payment, customers are prompted to Setup Auto-Renewal on the order-received page:

  1. Open their CLINK wallet (ShockWallet, ZEUS, Amethyst)
  2. Visit Get your nDebit string link pointing to my.shockwallet.app/lapps
  3. Copy the ndebit1... string and paste it into the auto-renewal field
  4. Future payments are processed automatically — no QR scanning required

The My Account > View Subscription page reflects the ndebit status in the "Payment" row:

  • No ndebit saved: Shows "Activate Auto-Renewal" as a link back to the parent order's order-received page for setup
  • Ndebit saved: Shows "Auto-Renewal" (plain text)

Customers can disable auto-renewal from My Account > Subscriptions at any time. Subscriptions without ndebit show a "Get nDebit String" action link to enable auto-renewal later.

Generating a noffer

ShockWallet (mobile)

  1. Open ShockWallet
  2. Go to Receive > CLINK Offer
  3. Copy the noffer1... string
  4. Paste into the plugin settings

Lightning.Pub (self-hosted)

  1. Log into your Lightning.Pub dashboard
  2. Navigate to Offers
  3. Copy the generated noffer1... string

Development

# Install dependencies
npm install

# Build JS bundle
npm run build

# Watch for changes
npm run watch

Three JavaScript bundles are built with esbuild:

  • assets/js/clink-checkout.js — uses @shocknet/clink-sdk to request Lightning invoices via the CLINK protocol on the order-received page. QR codes are generated client-side with qrcode-generator (no remote API). Built to clink-checkout.min.js.
  • assets/js/clink-blocks.js — registers the gateway with WooCommerce Cart/Checkout Blocks via registerPaymentMethod(). Built to clink-blocks.min.js.
  • assets/js/clink-price-converter.js — client-side price conversion fallback that converts .woocommerce-Price-amount elements to sats/BTC/₿ on all frontend pages. Ensures compatibility with price-display plugins like Custom Price for WooCommerce Pro. Built to clink-price-converter.min.js.

Architecture

Checkout Flow:
  Customer                    WooCommerce                  Nostr Relay          Merchant Node
     │                           │                           │                     │
     │── Place Order ───────────▶│                           │                     │
     │                           │── Create Order (pending)  │                     │
     │                           │── Redirect to thank-you   │                     │
     │                           │                           │                     │
     │── Page Load ─────────────▶│                           │                     │
     │                           │── Localize noffer + sats  │                     │
     │                           │                           │                     │
     │── JS: Decode noffer ──────┤                           │                     │
     │── JS: Generate ephemeral  │                           │                     │
     │     Nostr key             │                           │                     │
     │── JS: Send kind:21001 ────┼──────────────────────────▶│── Request Invoice ─▶│
     │                           │                           │                     │
     │                           │◀── BOLT 11 Invoice ──────│◀─ Response ─────────│
     │── Display QR code ◀──────┤                           │                     │
     │── Customer pays ◀─────────┼──────────────────────────▶│                     │
     │                           │                           │── Receipt ─────────▶│
     │◀── Receipt callback ──────┤◀──────────────────────────│                     │
     │── AJAX: mark_paid ───────▶│                           │                     │
     │                           │── Order complete ────────▶│                     │

Files

woocommerce-clink-gateway/
├── woocommerce-clink-gateway.php        # Plugin bootstrap, AJAX handlers, scripts
├── includes/
│   ├── class-wc-gateway-clink.php       # WC_Payment_Gateway implementation
│   ├── class-wc-clink-subscriptions.php # WooCommerce Subscriptions integration
│   └── class-wc-clink-blocks-support.php# Cart/Checkout Blocks support
├── assets/
│   ├── js/
│   │   ├── clink-checkout.js            # Source — order-received page (ES module, @shocknet/clink-sdk)
│   │   ├── clink-checkout.min.js        # Built bundle
│   │   ├── clink-blocks.js             # Source — blocks checkout registration
│   │   ├── clink-blocks.min.js         # Built bundle
│   │   ├── clink-price-converter.js    # Source — client-side price conversion fallback
│   │   ├── clink-price-converter.min.js# Built bundle
│   │   └── clink-checkout.asset.php    # Asset metadata
│   ├── css/clink-checkout.css           # Checkout page styles
│   └── images/lightning-icon.svg        # Payment method icon
├── build.mjs                            # esbuild config
└── package.json                         # NPM dependencies

Security

  • Nonces: All AJAX endpoints use wp_create_nonce() / check_ajax_referer()
  • Escaping: All output uses WordPress escaping functions (esc_html, esc_url, esc_js, wp_kses_post)
  • Sanitization: All input uses sanitize_text_field() / absint()
  • No direct DB queries: All data access through WooCommerce APIs
  • Ephemeral keys: Each checkout generates a fresh Nostr key pair — never reuses keys

Third Party Services

This plugin communicates with the following third-party services:

  • Purpose: Request and receive Lightning invoices from the merchant's CLINK-compatible wallet.
  • When: At checkout, when a customer places an order using the CLINK payment method.
  • Data sent: Merchant's noffer offer data, payment amount in satoshis, order description, and ephemeral public keys.
  • Relay URL: Determined by the merchant's noffer string (configured in gateway settings).
  • Privacy note: No personal customer data (name, email, address) is transmitted to Nostr relays. Only payment amount and a short order description are shared. Customers choosing wallet-based auto-renewal (ndebit) authorize the merchant to pull future subscription payments; the ndebit string and subscription amount are known to the Nostr relay.

CoinGecko

  • Purpose: Fetch the current BTC-to-fiat exchange rate for price display.
  • When: On checkout page load, every 5 minutes (result cached in WordPress transients).
  • Data sent: The store's currency code (e.g., usd, eur).
  • Privacy policy: https://www.coingecko.com/en/privacy
  • Note: If configured, a fixed exchange rate in the plugin settings bypasses this service entirely.

ShockWallet.app

  • Purpose: Informational links for customers to generate CLINK noffer/ndebit strings.
  • When: When the customer clicks the link (no data sent by the plugin automatically).
  • Privacy policy:https://docs.shock.network/privacy

License

GPLv2 or later

Changelog

Recent versions. Full history: see the Changelog wiki page.

1.1.1

  • Orders are now placed directly into on-hold status at checkout instead of pending, preventing WooCommerce's automatic "unpaid order" cancellation from removing orders that were already paid via CLINK.

1.1.0

  • Fixed post-payment flow: after the CLINK receipt arrives, the order-received page now shows an immediate "Payment confirmed" screen and reliably redirects to the order summary.
  • mark_paid now retries transiently when the invoice record isn't ready yet (receipt arriving before invoice confirmation completes).

1.0.9

  • Security fix: strict BOLT11 invoice validation (checksum, network, amount, expiry) and order-key ownership enforcement on all AJAX handlers.
  • Added Network setting (mainnet / testnet / regtest).