checkout.js Widget
The checkout.js widget is an embeddable payment solution that allows merchants to accept Bitcoin Lightning payments on any website. It uses the BYOA (Bring Your Own API Key) model - funds flow directly to your OpenNode account.
Architecture
Your Website → checkout.js → OpenNode API → Your OpenNode Account
↓
Lightning Network
Key points:
- Lightning Enable never touches your funds
- OpenNode facilitates custody and settlement
- You provide your OpenNode API key
- Widget works on any website (static HTML, React, Vue, etc.)
Quick Start
1. Get Your OpenNode API Key
- Sign up at app.opennode.com/signup
- Complete KYB verification
- Navigate to Settings → API Keys
- Create a new API key with invoices permission
2. Include the Script
<script src="https://api.lightningenable.com/checkout/v1/checkout.js"></script>
3. Add a Payment Button
<button id="pay-with-lightning"
data-opennode-key="YOUR_OPENNODE_API_KEY"
data-amount="1000"
data-currency="USD"
data-description="Premium Content Access">
Pay $10 with Lightning ⚡
</button>
<script>
LightningCheckout.init({
onSuccess: function(payment) {
console.log('Payment complete!', payment.id);
// Unlock content, redirect, etc.
},
onCancel: function() {
console.log('Payment cancelled');
}
});
</script>
Configuration Options
Button Attributes
| Attribute | Required | Description |
|---|---|---|
data-opennode-key | Yes | Your OpenNode API key |
data-amount | Yes | Payment amount (in smallest unit, e.g., cents for USD) |
data-currency | No | Currency code (default: USD) |
data-description | No | Payment description shown to customer |
data-success-url | No | Redirect URL after successful payment |
data-cancel-url | No | Redirect URL if payment cancelled |
data-webhook-url | No | Your webhook endpoint for payment notifications |
JavaScript Options
LightningCheckout.init({
// Callbacks
onSuccess: function(payment) { }, // Called after successful payment
onCancel: function() { }, // Called if user cancels
onError: function(error) { }, // Called on error
// UI Options
theme: 'light', // 'light' or 'dark'
primaryColor: '#F7931A', // Bitcoin orange default
showQRCode: true, // Show QR code
showPaymentOptions: true, // Show wallet app buttons
// Behavior
autoClose: true, // Auto-close modal on success
closeDelay: 3000, // Delay before auto-close (ms)
});
Payment Flow
sequenceDiagram
participant User
participant checkout.js
participant OpenNode
participant Merchant
User->>checkout.js: Click "Pay with Lightning"
checkout.js->>OpenNode: Create invoice (using merchant's API key)
OpenNode-->>checkout.js: Invoice with Lightning address
checkout.js->>User: Display QR code + payment info
loop Poll for status
checkout.js->>OpenNode: Check invoice status
OpenNode-->>checkout.js: pending/paid
end
User->>OpenNode: Pay invoice via Lightning wallet
OpenNode-->>checkout.js: paid status
checkout.js->>Merchant: onSuccess callback
checkout.js->>User: Success confirmation
Supported Currencies
checkout.js supports all currencies that OpenNode supports:
- USD - US Dollar (default)
- EUR - Euro
- GBP - British Pound
- BTC - Bitcoin (satoshis)
- CAD - Canadian Dollar
- And many more...
Example: E-commerce Integration
<!DOCTYPE html>
<html>
<head>
<title>My Store - Checkout</title>
</head>
<body>
<h1>Premium Membership - $29/month</h1>
<button id="pay-lightning"
data-opennode-key="your-opennode-key"
data-amount="2900"
data-currency="USD"
data-description="Premium Membership - 1 Month"
data-webhook-url="https://yoursite.com/api/webhooks/opennode">
Pay with Bitcoin Lightning ⚡
</button>
<script src="https://api.lightningenable.com/checkout/v1/checkout.js"></script>
<script>
LightningCheckout.init({
onSuccess: function(payment) {
// Verify on your backend, then:
window.location.href = '/membership/success?payment=' + payment.id;
},
theme: 'dark',
primaryColor: '#10B981' // Custom green
});
</script>
</body>
</html>
Security Considerations
API Key Scope
Your OpenNode API key is exposed in the browser. Ensure it only has invoices permission:
- ✅ Create invoices
- ❌ Withdraw funds
- ❌ Access account settings
- ❌ View transaction history
Verify Payments Server-Side
Always verify payments on your backend before fulfilling orders:
// Frontend: onSuccess callback
onSuccess: function(payment) {
// Send payment ID to your backend
fetch('/api/verify-payment', {
method: 'POST',
body: JSON.stringify({ paymentId: payment.id })
}).then(response => {
if (response.ok) {
// Payment verified, fulfill order
}
});
}
// Backend: Verify with OpenNode
const response = await fetch(
`https://api.opennode.com/v1/charge/${paymentId}`,
{ headers: { 'Authorization': process.env.OPENNODE_SECRET_KEY } }
);
const charge = await response.json();
if (charge.data.status === 'paid') {
// Payment confirmed, fulfill order
}
Webhook Verification
If using webhooks, verify the signature:
// Your webhook endpoint
app.post('/api/webhooks/opennode', (req, res) => {
const signature = req.headers['x-opennode-signature'];
const payload = JSON.stringify(req.body);
const expectedSig = crypto
.createHmac('sha256', process.env.OPENNODE_WEBHOOK_SECRET)
.update(payload)
.digest('hex');
if (signature !== expectedSig) {
return res.status(401).send('Invalid signature');
}
// Process verified webhook
const { id, status } = req.body;
if (status === 'paid') {
// Fulfill order
}
});
Framework Examples
React
import { useEffect } from 'react';
function CheckoutButton({ amount, description }) {
useEffect(() => {
// Load checkout.js
const script = document.createElement('script');
script.src = 'https://api.lightningenable.com/checkout/v1/checkout.js';
script.onload = () => {
window.LightningCheckout.init({
onSuccess: (payment) => {
console.log('Paid!', payment.id);
}
});
};
document.body.appendChild(script);
return () => document.body.removeChild(script);
}, []);
return (
<button
data-opennode-key={process.env.REACT_APP_OPENNODE_KEY}
data-amount={amount}
data-currency="USD"
data-description={description}
>
Pay with Lightning ⚡
</button>
);
}
Vue
<template>
<button
:data-opennode-key="openNodeKey"
:data-amount="amount"
data-currency="USD"
:data-description="description"
>
Pay with Lightning ⚡
</button>
</template>
<script>
export default {
props: ['amount', 'description'],
data() {
return {
openNodeKey: process.env.VUE_APP_OPENNODE_KEY
};
},
mounted() {
const script = document.createElement('script');
script.src = 'https://api.lightningenable.com/checkout/v1/checkout.js';
script.onload = () => {
window.LightningCheckout.init({
onSuccess: (payment) => {
this.$emit('payment-success', payment);
}
});
};
document.body.appendChild(script);
}
};
</script>
Customization
CSS Variables
:root {
--le-primary: #F7931A; /* Primary button color */
--le-background: #ffffff; /* Modal background */
--le-text: #1a1a2e; /* Text color */
--le-border-radius: 12px; /* Border radius */
--le-font-family: system-ui; /* Font family */
}
Custom Styling
<style>
.lightning-checkout-modal {
/* Your custom modal styles */
}
.lightning-checkout-qr {
/* Custom QR code container */
}
.lightning-checkout-button {
/* Custom button styles */
}
</style>
Troubleshooting
"Invalid API Key"
- Verify your OpenNode API key is correct
- Ensure the key has invoices permission
- Check if key is for correct environment (dev vs production)
Invoice Not Creating
- Check browser console for errors
- Verify amount is a valid number
- Ensure currency is supported
Payment Not Detected
- OpenNode polls every 2 seconds by default
- Check OpenNode dashboard for payment status
- Verify webhook URL is accessible
Included in Plans
checkout.js is included in all Lightning Enable subscription plans:
| Plan | Price | checkout.js |
|---|---|---|
| Kentico Commerce | $249/month | ✅ Included |
| Agentic Commerce | $299/month | ✅ Included |
Next Steps
- OpenNode Setup Guide - Get your API key
- Webhook Integration - Server-side verification
- API Reference - Full API documentation