How to make a Bitcoin Lightning App

A payment protocol like bitcoin can be used for more than just to pay people. It can be used to do fun things like interacting with a website by doing lightning transactions. Its fairly easy to make them but you should have some knowledge about programming.

In this article I’ll explain how I made this webapp where you can change the image or text on the webpage with a lightning transaction.

To handle lightning transactions you need a way to communicate with your lightning node.

I have found these options:

  1. BTCPay Server: (no third party)
  2. Opennode: (third party)

For this example I’ve used opennode so lets get started!

First, you need to sign up at but you should sign up at first. Opennode provides you with a development variant for testing which is great to develop our application!

Signing up for opennode (dev)

You can directly work with mainnet version if you wish to.

After signing in feel free to explore the interface. Opennode provides 10,000$ of free transaction processing which is a lot to begin with.

Some explaining: opennode is now your lighting node. Its a custodial system and all your transactions will go to your opennode wallet.

But how do you communicate with this wallet? For that opennode provides an API which is what we’ll be using. To use that API we first need the API key. To get that go to settings>Integrations and click on “+API key”. Now give your API a name and select “Invoices” in permissions.

Creating the API

Now click on Generate and it’ll generate the API key for you. Now copy down that API key somewhere because you won’t be able to get it after this (you can always create new ones though).

Now that we have our API key we can get to using it. To get started we’ll see how to use the API in a Node.js application.

Make a new node project for testing with npm and install opennode via npm:

This will install the opennode api for your project

Once that’s done, open up your index.js (create one in same folder and your project). You can use any code editor for this.

Now, we’ll import our opennode api and authenticate our API key:

API_KEY = "aaceb538-0b4e-4e86-950f-13e0beb48531" // you got it from the dashboard.
const opennode = require(‘opennode’);
opennode.setCredentials(API_KEY, ‘dev’); //if no parameter given, default environment is ‘live’

You can see the second parameter in setCredentials tells you in which mode this api should work in. ‘dev’ means in development mode, meaning all transactions would be testBitcoin and not real money. When you’re ready to deploy your application you can change it to ‘live’ and all transactions would be on bitcoin mainnet which is real money.

Note: If you don’t have testBitcoins for testing you can get them for free from faucets online.

Now that we have setup our API its time to create an invoice with the createCharge function.

async function getCharge(){
const charge = await opennode.createCharge({
amount: 1000,
description: “1 satoshi sindoor”,
auto_settle: false

invoice = charge["lightning_invoice"]["payreq"]
charge_id = charge["id"]

return charge;

You can also specify a fiat currency but in our case its not specified so the currency is satoshi. You can also use the promise method if your node version is older than 6.

Some explaination: So what did we do? By calling getCharge() we have created an invoice to our opennode lightning wallet. That invoice can now be used by the customer to pay you. Let’s try this.

runnig index.js

What you’re seeing is the “charge” the API returned in the form of a JSON. It has lot of information most of which are self-explanatory. In order for the customer to pay you, you need to give them the “payreq” which a big jumble of characters so it is mostly showed as a QR code. Also make sure you save the “id” because it is used to check if the transaction has happened.

You can take that “payreq” and do a lightning transaction from you testnet-lightning wallet and the transaction will happen and go to your opennode wallet.

To check if the transaction has happened programatically use chargeInfo function:

charge = await opennode.chargeInfo(charge_id);

And this is where the magic comes. You use this ability to know if an “action” should happen. Like, “If this transaction completes then change the image on the webpage to this”. This is where you can get all creative and build apps over bitcoin.

To check if an invoice is paid you can do this:

if(charge[“status”] == “paid”){
console.log("yo its paid lets do something now")
console.log("still waiting..")

And thats it.. everything else is normal web development and is technically not a part of this but if still want to learn keep reading.

Once you’re done developing, go to and make a mainnet acount and get a mainnet API key and change your setCredentials() to ‘live’ mode.

Now there’s a caveat, how do I know the user has done the transaction? There must be some service periodically checking if the transaction has happened. So you need to setup a server that does that, or you could just use an AWS lambda function which is what I used.

Note: You’ll probably need a server anyway to create invoices because the API is nodejs compatible and not Javascript compatible.

So my lambda code to check if the invoice is paid is this:

let invoice_key = “"
let invoice_key_dev = “”
const opennode = require(‘opennode’);
opennode.setCredentials(invoice_key, ‘live’); //if no parameter given, default environment is ‘live’
exports.handler = async (event, context) => {
// TODO implement

let charge, text;
let headers = {
“Access-Control-Allow-Origin”: “*”,
“Access-Control-Allow-Headers”: “application/json”,
“Access-Control-Allow-Methods”: “OPTIONS,POST,GET”
    charge = await opennode.chargeInfo(;

if(charge[“status”] == “unpaid”){
text = JSON.stringify({status: “unpaid”});
const response = {
statusCode: 200,
headers: headers,
body: text,
return response;
text = JSON.stringify({status: “paid”});
const response = {
statusCode: 200,
headers: headers,
body: text,
return response

Here I’ve also configured CORs which allows this lambda function to be called from different domain which in our case would be our website (you’ll also have to configure the API gateway of that lambda function).

What really happens is that the client (website) sends a request to this lambda function every 5 seconds using ajax.

function checkStatus(id){
url = “" + id
url: url,
xhrFields: {
withCredentials: false
method: ‘GET’,
success: function(data){
if(data[“status”] == “paid”){
    updateInDatabase()// This most likely send a request to update the database with what the user requested.
    document.getElementById(“isrecv”).textContent=”awaiting pay.. (valid for 5mins)”
    setTimeout(checkStatus, 5000, id) // re-checking after 5 seconds.

If the invoice is paid the client can then request the server to update the data (or the server will do it right when it knows the transaction has happened. I couldn’t do that because my database is firebase and aws can’t access it for some reason). This is definately not be the best and most secure way to do this. If your db is more accesible, do the update on the server side.

And thats pretty much there is. Now go make some amazing LApps.

PS — I dont’t earn anything from medium partner program so if you enjoyed and learned something please consider tipping me a little on . Thanks.