checkout.js
checkout.js (v2.1.0) is a small browser helper that connects your payment buttons to Lightning Enable's hosted checkout page. It handles the redirect UX — loading states, error callbacks, and sending the customer to the checkout URL your backend creates.
- Prices are never passed from the client — that would let anyone edit the amount.
- Your API key never reaches the browser. Your backend creates the payment with
X-API-Key; the script only receives a checkout URL. - The script does not create invoices, render QR codes, or poll payment status — the hosted checkout page does that.
Architecture
Customer clicks button
→ checkout.js calls YOUR backend endpoint
→ your backend calls POST /api/payments (with your API key)
→ your backend returns { "checkoutUrl": "https://api.lightningenable.com/pay/1042" }
→ checkout.js redirects the customer to the hosted checkout page
Lightning Enable never holds funds — your payment provider (Strike or OpenNode) facilitates custody and settlement.
Quick Start
1. Include the script
<script src="https://api.lightningenable.com/checkout/v1/checkout.js"></script>
2. Create a checkout endpoint on your backend
Your endpoint creates the payment and returns the checkout URL. The hosted checkout page lives at https://api.lightningenable.com/pay/{invoiceId}.
// Node/Express example
app.post('/api/create-checkout', async (req, res) => {
const response = await fetch('https://api.lightningenable.com/api/payments', {
method: 'POST',
headers: {
'X-API-Key': process.env.LIGHTNING_ENABLE_API_KEY, // server-side only
'Content-Type': 'application/json'
},
body: JSON.stringify({
orderId: 'order-' + Date.now(),
amount: 25.00, // price from YOUR catalog — never from the client
currency: 'USD',
description: 'Premium Widget'
})
});
if (!response.ok) {
return res.status(502).json({ error: 'Could not create checkout' });
}
const payment = await response.json();
res.json({ checkoutUrl: 'https://api.lightningenable.com/pay/' + payment.invoiceId });
});
3. Add a payment button
Option A — dynamic session creation (SPAs / dynamic sites). The button calls your endpoint, then redirects:
<button data-checkout-endpoint="/api/create-checkout">Pay with Lightning</button>
Option B — pre-created checkout URL (static sites). Create the session ahead of time and link straight to it:
<button data-checkout-url="https://api.lightningenable.com/pay/1042">Pay with Lightning</button>
<!-- or skip the script entirely: -->
<a href="https://api.lightningenable.com/pay/1042">Pay with Lightning</a>
Buttons are wired up automatically when the DOM is ready — no initialization call required.
Configuration
LightningCheckout.init() is optional. Call it only to customize error handling or the redirect:
LightningCheckout.init({
onError: function (error) {
// error.message describes what failed (endpoint unreachable, missing checkoutUrl, ...)
showToast('Payment failed to start: ' + error.message);
},
onRedirect: function (url) {
// Default is window.location.href = url. Override to open in a new tab, log, etc.
window.open(url, '_blank');
}
});
| Option | Type | Default | Description |
|---|---|---|---|
onError | function(error) | console.error | Called when session creation fails or a button is misconfigured |
onRedirect | function(url) | window.location.href = url | Called with the checkout URL to navigate to |
Button attributes
| Attribute | Applies to | Description |
|---|---|---|
data-checkout-endpoint | Option A | Your backend endpoint that returns { "checkoutUrl": "..." } |
data-checkout-method | Option A | HTTP method for the endpoint call (default POST) |
data-checkout-url | Option B | Pre-created checkout URL to redirect to |
any other data-* | Option A | Sent to your endpoint as the JSON request body — e.g. data-product-id="42" posts { "productId": "42" } |
While a session is being created the button is disabled and gets the lightning-checkout-loading CSS class (dimmed, cursor: wait) — style it further if you like.
JavaScript API
LightningCheckout.init(options); // optional — configure callbacks
LightningCheckout.redirectToCheckout(checkoutUrl); // programmatic redirect
LightningCheckout.version; // "2.1.0"
Programmatic flow example:
async function buy(productId) {
const res = await fetch('/api/create-checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ productId })
});
const { checkoutUrl } = await res.json();
LightningCheckout.redirectToCheckout(checkoutUrl);
}
Confirming payment
The hosted checkout page shows the invoice and updates when payment lands. To fulfill the order, use one of the server-side paths:
- Webhooks (recommended): configure your callback URL and verify the
X-LightningEnable-Signatureheader — see Webhooks. - Polling from your backend:
GET /api/payments/{invoiceId}with your API key. - Browser-side UX only: the public
GET /api/payments/{invoiceId}/statusendpoint returns{ "status": "..." }without an API key.
Included in plans
checkout.js and the hosted checkout page are available on both Agentic Commerce plans — Individual ($99/mo) and Business ($299/mo). See pricing.
Next Steps
- Integration Guide — the full REST API flow
- Webhooks — payment notifications
- Refunds — handling returns