LSPS2: Get "Just-In-Time" Lightning Channels
If you want to get an inbound channel from Megalith LSP for your own node, please go directly to our online form.
This page is for developers. It describes our API which follows the Lightning Service Provider Standard Two (bLIP52 / LSPS2) for automated "just in time" channel-opening.
You're here because you want your users to use Bitcoin in your application.
You've learned that supporting Lightning payments isn't 100% straightforward.
Should I just use an API for Lightning?
If your app only needs to receive payments (a store, a subscription, a tip jar), you don't need to onboard your users to Lightning at all. OpenReceive, our free, MIT-licensed library, does that for WordPress + WooCommerce, Express, Fastify, Next.js, Rails, Django, FastAPI, Laravel, plain PHP, and BTCPay Server. It accepts Lightning (and optionally USDT, USDC, ETH, or SOL via a swap provider) straight into your own wallet with a receive-only NWC code -- no account, no API key, no custodian. LSPS1 and LSPS2, below, are for when your users need their own self-custodial Lightning node.
Enter the first standard: LSPS1
Luckily, there is an open source standard that is already battle tested, with tens of thousands of users. It's called Lightning Service Provider Standard One (bLIP51 / LSPS1), and it's been implemented by LSPs (Lightning Service Providers) like Olympus by ZEUS, Megalith, and Flashsats. Collectively, these LSPs, along with dozens of others, have opened tens of thousands of channels using LSPS1, and routed many millions of payments.
LSPS1 is battle-tested and known to work well. It's impossible for funds to be "stolen" by the LSP, and furthermore, if and when your user's channel closes, their funds settle onto the Bitcoin mainchain automatically, so there's no need for complicated protocols, centralized control, or customer support.
There is no company providing an API that could suddenly go out of business, and since the LSP standards are open-source, you are free to switch LSPs at any time.
So. LSPS1 works great if your users already have at least a little Bitcoin. They pay a small invoice (usually around $20, depending on channel size and exchange rate), and then they get an "inbound" channel.
Especially if your users are somewhat savvy already with Lightning, and especially if your users are on desktop or using a desktop web browser, LSPS1 probably makes the most sense, and you can follow our guide to LSPS1 here.
Would somebody please think of the normies?
But here's the problem. What if your users don't yet have any Bitcoin? And furthermore, what if their potential attention span for getting onboarded onto Bitcoin is less than five seconds?
We've all seen the studies: When normies want to do something on the internet, it needs to be done in less than five seconds. If it takes longer than that, then they forget what they were trying to do, and they're already back on TikTok or Instagram.
LSPS1 is pretty elegant, but it involves a few user touch points...
- A user must know that he/she is running a Lightning node, and know that he/she needs a channel
- A user must pay an invoice (or you can pay it for them.)
- Here comes the confusing part: Once this invoice is paid, the channel can open quickly, but then the user has no Bitcoin in the channel! They then have to..
- Make a payment "to themselves" in order to get outbound capacity.
- So a user must (at least to some small degree) understand that they are getting a "lightning channel" -- and understand what this means.
And, remember -- Normies. They refuse to learn anything new, and you have less than five (5) seconds to get them what they want. Challenging, right?
LSPS2: From a user perspective, it's awesome
So the good people at the Lightning Layer Spec Group realized this issue, and have been chugging away for a couple years on a solution: bLIP52 / LSPS2.
LSPS2 allows for "just in time" channels. From the perspective of your user, this means they don't "pay for a channel" and "wait for it to open" and then "pay into their channel from an external wallet" -- instead, these three steps happen SIMULTANEOUSLY -- they instantly have a Lightning channel, and that channel instantly has both inbound liquidity AND outbound liquidity.
And all this can happen in LESS THAN TWO SECONDS, well before your user has lost interest and gone back to looking at gyrating bodies on TikTok, or similar.
LSPS2: For the developer of the client software, it's awesome
LSPS2 is ideal if you are using LDK Node, as there is an exceptionally simple and elegant API you can use to get your client a channel.
Even if looking at Rust gives you a headache, take a look here:
https://github.com/MegalithicBTC/ldk-node-liquidity-mutinynet/blob/master/src/lib.rs
You need a grand total of TWO (2) API calls to get your user a channel:
set_liquidity_source_lsps2(lsp_node_id, lsp_address, lsp_token);
and then....
let desc = Bolt11InvoiceDescription::Direct(Description::new("Payment".to_string()).unwrap());
let invoice = node.bolt11_payment().receive_via_jit_channel(25_000_000, &desc, 3_600, None).unwrap();
(Bolt11InvoiceDescription and Description come from ldk_node::lightning_invoice.)
So there you get an invoice, which your user can pay, or, to prevent confusion, your service can pay the invoice for your user (recommended). Now your user instantly has a Lightning channel with both inbound and outbound liquidity!
LSPS2: For the LSP, it's challenging
Now, I won't say that I personally cried when reading the LSPS2 spec, but it did give me some pause: From the perspective of an LSP, this specification is at least FIVE TIMES more complicated to implement than LSPS1, and requires lots of fiddling with HTLCs. There's also some risk that if the LSP makes a mistake in the implementation, the LSP could be attacked.
Furthermore, if you've looked at our LSPS1 implementation, you might have picked up that we cheated a bit, and used HTTP communication instead of BOLT8. HTTP makes things easier because it's easier to hook in a database and web server.
In the case of LSPS2, however, HTTP communication between client and LSP would be totally impossible, as the protocol cleverly uses the characteristics of HTLCs in order maximize convenience for the client, so LSPs need to get down-and-dirty with BOLT8 communication, as that's the only way to talk to the client.
In any case: after doing quite a bit of battle, we have now implemented the LSP-side behavior of LSPS2, and it is ready for production.
Please fire up your LDK Node(s) and give it a whirl
Our LSPS2 service is running on mainnet and is ready for production. You can use it here:
034066e29e402d9cf55af1ae1026cc5adf92eed1e0e421785442f53717ad1453b0@64.23.159.177:9735
Same two calls as above, with our node id, address, and token filled in. Any token works:
set_liquidity_source_lsps2(
"034066e29e402d9cf55af1ae1026cc5adf92eed1e0e421785442f53717ad1453b0".parse().unwrap(),
"64.23.159.177:9735".parse().unwrap(),
Some("use any token here".to_string()),
);
and then....
let desc = Bolt11InvoiceDescription::Direct(Description::new("Payment".to_string()).unwrap());
let invoice = node.bolt11_payment().receive_via_jit_channel(25_000_000, &desc, 3_600, None).unwrap();
One rule:
- Make sure your node is able to accept the payment within 60 seconds (ideally sooner). That should work fine if your LDK is hosted in the cloud. If your LDK is running on the user's device, think about this more carefully: the device has to be online and able to finish accepting the payment inside that window.
If you get stuck, or you want a hand wiring this into your app, please reach out. We are happy to help you get connected.