Route Lightning sat to any wallet. Interactive demo of the Thunder Bridge npm package.
Thunder Bridge is a thin wrapper on top of a Lightning node. A few lines of code and your app starts taking sat straight into your own LN wallet. Hook anything you want onto every donation.
You've got an idea and you know it'll need to take sound money. Now let's run through who the standard payment rails kick out on day one. Under 18? Stripe, PayPal and your bank send you home. Anything in a vertical the regulator doesn't currently like? Account terminated. Live in a country that happens to be on the wrong list this week? Cheers, take care. "Consumer protection," "destination principle," "level playing field," "fair taxation of the digital economy," "preventing market distortion," the regulators call it, but what they're mostly protecting you from is earning your own money. Cool, thanks.
Spinning up a Lightning node for the occasion, playing treasurer, babysitting channels and liquidity? Probably not either. First you want to find out if the thing has any pulse, and for that you need the simplest possible end-to-end path so it actually runs. Complications show up on their own, once they're really needed.
Thunder Bridge is that shortcut, but the goal goes further: cut the barrier to entry to zero and get it to a place where the gateway itself has no technical way to control or block anything. The goal is to have it by design, not by policy: sat in, sat out. No paperwork, no age gate, no "sorry, kid", no "not that country". Part of that vision is multiple independent hosts, so the payment does not stand or fall with one node or one person.
A technically savvy person can already pull this off today via Breez SDK, phoenixd, their own BTCPay Server, ... The point of this project is to open the same door to people who aren't quite that technical, who only need a one-off or stop-gap solution, or who simply prefer simplicity. Just bring an idea and a few lines of code (or an agent that writes them for you).
Routing
Sat from a Lightning address land straight in your wallet. No node required.
Triggers
Webhook and WebSocket event on every payment. Drive whatever.
Programmatic
A few lines of JS. Runs in browsers, Node, Bun, and edge runtimes.
Stream alerts
Live overlay on every donation for Twitch, YouTube, or OBS. Trigger plus streamTrigger over WebSocket deliver events in real time.
createTrigger + streamTriggerIoT triggers
Light a lamp, open a door, drive a vending machine. Your ESP or Pi connects over WebSocket and the hardware reacts to every payment.
createTrigger + streamTriggerPay-per-use API
Unlock an API key, an AI generation, or a file. Donation confirmed by webhook equals access granted.
createDonation + webhookTip jar widget
Drop a donate form on your blog. createDonation renders the QR, waitForFulfillment shows status live.
createDonation + waitForFulfillmentGame server triggers
Minecraft, Counter-Strike: send sats = kill a random player, drop loot, summon a mob, change the weather. Lightning-funded chaos for your server.
createTrigger + streamTriggerAnti-spam paywall
Send 1 sat to comment, submit a form, or hit an API. Bot economics collapse, humans barely notice, no captchas.
createDonation + waitForFulfillmentThis is alpha. The vision is clean programmatic access, no fluff. The gateway is automated, but you still have to trust the proxy will pay out. If it catches on and there is real demand, we might get to BOLT12 offers and blinded paths for trust-minimized routing, open the source, and prep it for self-hosting. 🧡
Eight short examples that walk you through the API. Each card shows real code on the left and a live preview on the right. Run them in order, or jump to the part you need.
`invoiceToSvg` returns a deterministic SVG string for BOLT11 invoices, BOLT12 offers, and LN addresses (LUD-17). Encoded with the `LIGHTNING:` URI scheme and uppercased for QR alphanumeric compression and wallet compatibility. Pure client-side. No canvas, no network call.
import { invoiceToSvg } from "thunder-bridge";
// Works for BOLT11, BOLT12, and LN addresses (LUD-17).
// Encodes with the LIGHTNING: URI scheme + uppercase
// for wallet compatibility and QR alphanumeric compression.
const svg = invoiceToSvg("alice@getalby.com", {
size: 220,
color: "#1a1a2e",
});
document.body.innerHTML = svg;Quick format check that tells Lightning addresses apart from BOLT12 offers. Just a regex over the input. No network call, no domain lookup, no signature check.
import { detectDestinationType } from "thunder-bridge";
detectDestinationType("alice@getalby.com");
// "lnAddress"Useful for client-side validation before you call createDonation. Always re-validate on the server.
Ask the gateway how many sat will reach the recipient before you create a donation.
import { ThunderBridge } from "thunder-bridge";
const tb = new ThunderBridge("https://thunder-bridge.agora.gripe");
const fees = await tb.estimateFees(1000);
console.log(fees);
// Press Run to fetch the live breakdown.Generate a BOLT11 invoice that pays out to a Lightning address. Scan it with any wallet.
import { ThunderBridge } from "thunder-bridge";
const tb = new ThunderBridge("https://thunder-bridge.agora.gripe");
const { id, bolt11, expiresAt } = await tb.createDonation({
destination: "alice@getalby.com",
amountSat: 21,
});
// Render the bolt11 invoice as a QR code
// (your wallet scans it and pays)The invoice is real. Scanning it triggers an actual Lightning payment.
Opens a WebSocket to the gateway and subscribes to status events for one donationId. `onStatusChange` fires on every transition through `invoice_created → payment_received → paying_out`. Resolves with the terminal state (`success | failed | expired`); rejects when `timeoutMs` runs out.
import { ThunderBridge } from "thunder-bridge";
const tb = new ThunderBridge("https://thunder-bridge.agora.gripe");
const finalStatus = await tb.waitForFulfillment(donationId, {
onStatusChange(status) {
console.log("status:", status);
// "invoice_created" -> "payment_received"
// -> "paying_out" -> "success"
},
timeoutMs: 600_000,
});
console.log(finalStatus); // "success" | "failed" | "expired"A trigger is a reusable Lightning address with a fixed price. Share the QR, donations stream into your app.
import { ThunderBridge } from "thunder-bridge";
const tb = new ThunderBridge("https://thunder-bridge.agora.gripe");
const trigger = await tb.createTrigger({
priceSat: 21,
});
console.log(trigger.ln_address);
// "ln-XXXXX@thunder-bridge.agora.gripe"
console.log(trigger.hash);
// share this hash with streamTriggerOpen a WebSocket and react to every donation as it lands. Replays history on connect, auto-reconnects. Raw URL is `wss://thunder-bridge.agora.gripe/ws/triggers/'<hash>'`, so you can verify it in any generic WS client (e.g. websocketking.com). From that stream you can drive whatever: a Slack or Discord alert, an LED blinking on an ESP32, a door opener, a donation overlay in your livestream, an in-game event, a push notification, a database write, basically anything that listens.
import { ThunderBridge } from "thunder-bridge";
const tb = new ThunderBridge("https://thunder-bridge.agora.gripe");
const stop = tb.streamTrigger(triggerHash, {
onDonation(d) {
console.log("+" + d.amount_sat + " sat");
// Drive your IoT device, alert, counter...
},
onConnect: () => console.log("WS open"),
onDisconnect: () => console.log("reconnecting"),
});
// Later: stop the stream
// stop();Receive POST notifications on your own server with HMAC-SHA256 signatures you can trust.
// app/api/webhook/route.ts (Next.js App Router)
import { parseWebhookRequest } from "thunder-bridge";
export async function POST(req: Request) {
const payload = await parseWebhookRequest(
req,
process.env.WEBHOOK_SECRET!,
);
// Returns null if X-Signature-256 is invalid
if (!payload) {
return new Response("Bad signature", { status: 401 });
}
console.log(payload.event); // "donation.success"
console.log(payload.donation.amount_received_sat);
return new Response("OK");
}{
"event": "donation.success",
"signal_only": false,
"donation": {
"id": "d_a1b2c3...",
"destination": "alice@getalby.com",
"amount_received_sat": 1000,
"amount_sent_sat": 995,
"network_fee_sat": 5,
"status": "success",
"error_message": null,
"created_at": "2026-04-25T14:32:01Z",
"updated_at": "2026-04-25T14:32:08Z"
}
}Install the Thunder Bridge npm package and start accepting Lightning donations in a few lines of code. Works in Node.js, Bun, Deno, browsers, and edge runtimes.
npm install thunder-bridge
If you build with Claude Code, the npm package ships a skill that teaches Claude the current API and integration patterns. Install it into your repo and Claude picks it up automatically when you write Thunder Bridge code.
# Per project (./.claude/skills/) npx thunder-bridge install-skill # Global for your user (~/.claude/skills/) npx thunder-bridge install-skill --global # Overwrite existing copy npx thunder-bridge install-skill --force