Интеграция LNURL-протокола
Попытка принять Lightning-платёж без LNURL — это пять шагов копирования и вставки, где каждый — потеря клиента. Пользователю нужно скопировать invoice из кошелька продавца, переключиться в свой кошелёк, вставить и оплатить. На практике это съедает до 30% конверсии. LNURL-интеграция устраняет эту боль: кошелёк автоматически запрашивает invoice через HTTP, достаточно одного сканирования QR. UX приближается к обычным платёжным системам.
Наша команда реализует LNURL-решения под ключ: от настройки ноды до внедрения Lightning Address. Накопленный опыт десятков проектов позволяет предвидеть типичные сложности — от проблем с ликвидностью до ошибок конфигурации TLS.
Почему стоит выбрать LNURL-интеграцию?
LNURL радикально улучшает пользовательский опыт. Сравните: обычный Lightning-платёж требует скопировать invoice (длинная строка), переключиться в кошелёк, вставить и оплатить. С LNURL — достаточно отсканировать один QR или нажать на ссылку. Это снижает количество отказов на 30–40% по нашим данным, а среднее время оплаты падает с 40 секунд до 5.
Кроме того, LNURL-pay даёт контроль над ценой: вы устанавливаете minSendable и maxSendable, можете уточнять сумму после сканирования. А с Lightning Address пользователь просто вводит [email protected] — никаких QR. По сравнению с ручным процессом LNURL-pay в 2.5 раза улучшает UX.
Какие протоколы входят в LNURL?
LNURL — не один протокол, а несколько спецификаций (LUD — Lightning URL Definitions). Каждый решает свою задачу:
| LUD | Протокол | Назначение |
|---|---|---|
| LUD-01 | LNURL-pay | Оплата: кошелёк запрашивает invoice у сервера продавца |
| LUD-03 | LNURL-withdraw | Вывод: кошелёк получает средства по ссылке |
| LUD-04 | LNURL-auth | Аутентификация через Lightning ключ (passwordless login) |
| LUD-06 | LNURL-channel | Открытие канала |
| LUD-12 | Lightning Address | Формат [email protected] для LNURL-pay |
Для приёма платежей важны прежде всего LNURL-pay и Lightning Address.
Как работает LNURL-pay?
Весь процесс — два HTTP запроса между кошельком и сервером:
- Пользователь сканирует QR. Кошелёк видит
lnurl1...(bech32 encoded HTTPS URL). Кошелёк декодирует и делает GET на этот URL. - Сервер возвращает metadata:
{ "tag": "payRequest", "callback": "https://merchant.com/lnurl/pay/invoice", "minSendable": 1000, "maxSendable": 100000000, "metadata": "[[\"text/plain\",\"Payment to My Shop\"]]" } - Пользователь вводит сумму. Кошелёк делает GET на callback с параметром
amount(в millisatoshi). - Сервер генерирует Lightning invoice через свою LN-ноду и возвращает:
{ "pr": "lnbc100n1pj...", "routes": [], "successAction": { "tag": "message", "message": "Payment confirmed! Order #12345" } } - Кошелёк оплачивает invoice. После успешной оплаты показывает
successAction.
Это всего пять шагов — втрое меньше по сравнению с ручным вводом invoice.
Как реализовать LNURL-pay сервер?
Нужна Lightning нода (LND или Core Lightning) для генерации invoice. Пример на Node.js с LND через gRPC:
import express from 'express'; import * as grpc from '@grpc/grpc-js'; import * as protoLoader from '@grpc/proto-loader'; import { bech32 } from 'bech32'; const app = express(); // LNURL-pay шаг 1: metadata app.get('/lnurl/pay/:paymentId', async (req, res) => { const { paymentId } = req.params; const callbackUrl = `https://${req.hostname}/lnurl/pay/${paymentId}/invoice`; // Кодируем URL в lnurl bech32 (для QR кода) const lnurlEncoded = encodeLnurl(callbackUrl); res.json({ tag: 'payRequest', callback: callbackUrl, minSendable: 1000, maxSendable: 100_000_000, metadata: JSON.stringify([ ['text/plain', `Payment for order ${paymentId}`], ]), }); }); // LNURL-pay шаг 2: генерация invoice app.get('/lnurl/pay/:paymentId/invoice', async (req, res) => { const { paymentId } = req.params; const amountMsat = parseInt(req.query.amount as string); if (!amountMsat || amountMsat < 1000) { return res.status(400).json({ status: 'ERROR', reason: 'Invalid amount' }); } try { const invoice = await lndClient.addInvoice({ value_msat: amountMsat, memo: `Order ${paymentId}`, expiry: 3600, }); await db.saveInvoice({ paymentHash: invoice.r_hash, paymentId, amountMsat, }); res.json({ pr: invoice.payment_request, routes: [], successAction: { tag: 'message', message: `Order ${paymentId} confirmed!`, }, }); } catch (err) { res.status(500).json({ status: 'ERROR', reason: 'Failed to generate invoice' }); } }); function encodeLnurl(url: string): string { const words = bech32.toWords(Buffer.from(url, 'utf8')); return bech32.encode('lnurl', words, 1023).toUpperCase(); } Этот код — основа. В продакшене добавляем валидацию, логирование, балансировку.
Lightning Address: [email protected]
Lightning Address (LUD-12) — самый удобный UX. Вместо QR-кода пользователь вводит адрес как email. Кошелёк автоматически делает запрос на https://domain.com/.well-known/lnurlp/username.
app.get('/.well-known/lnurlp/:username', async (req, res) => { const { username } = req.params; const user = await db.getUserByLnAddress(username); if (!user) { return res.status(404).json({ status: 'ERROR', reason: 'User not found' }); } res.json({ tag: 'payRequest', callback: `https://${req.hostname}/lnurl/lightning-address/${username}`, minSendable: 1000, maxSendable: 10_000_000_000, metadata: JSON.stringify([ ['text/identifier', `${username}@${req.hostname}`], ['text/plain', `Payment to ${username}`], ]), commentAllowed: 144, }); }); После этого [email protected] работает как Lightning Address в любом совместимом кошельке (Phoenix, Wallet of Satoshi, Zeus, Breez).
LNURL-auth: passwordless логин
LNURL-auth позволяет пользователям логиниться через Lightning кошелёк без пароля. Кошелёк подписывает challenge приватным ключом, производным от Lightning seed.
import crypto from 'crypto'; app.get('/auth/lnurl', (req, res) => { const k1 = crypto.randomBytes(32).toString('hex'); redis.setex(`lnurl_auth:${k1}`, 300, 'pending'); const lnurlAuthUrl = `https://${req.hostname}/auth/callback?tag=login&k1=${k1}`; const encoded = encodeLnurl(lnurlAuthUrl); res.json({ lnurl: encoded, k1 }); }); app.get('/auth/callback', async (req, res) => { const { k1, sig, key } = req.query as Record<string, string>; const status = await redis.get(`lnurl_auth:${k1}`); if (!status) { return res.json({ status: 'ERROR', reason: 'Unknown k1' }); } const isValid = verifyLnurlAuthSignature(k1, sig, key); if (!isValid) { return res.json({ status: 'ERROR', reason: 'Invalid signature' }); } await redis.setex(`lnurl_auth:${k1}`, 300, `authenticated:${key}`); res.json({ status: 'OK' }); }); Фронтенд polling-ом проверяет статус k1 — как только кошелёк подписал, пользователь залогинен.
Какие инфраструктурные требования для LNURL?
Lightning нода — обязательна. Варианты: LND (Go, gRPC API), Core Lightning (C, UNIX socket + REST), Eclair (Scala, используется Acinq/Phoenix). Для production: выделенный VPS с 4GB+ RAM, SSD, стабильным интернетом. Нода должна иметь входящую ликвидность для приёма платежей.
Hosted решения для быстрого старта: Voltage.cloud (managed LND), Alby Hub (self-custody), Strike API (custodial). Для боевого использования с серьёзными объёмами — только собственная нода.
TLS и домен обязательны: LNURL требует HTTPS. Самоподписанный сертификат не пройдёт — нужен Let's Encrypt или аналог.
Мониторинг: channel balance (оповещение при < 10% входящей ликвидности), invoice expiry, failed payment attempts. LND Metrics экспортирует Prometheus-совместимые метрики из коробки.
Что входит в работу по интеграции?
| Этап | Результат |
|---|---|
| Аналитика | Проект архитектуры, выбор ноды (LND/CLN), план миграции |
| Настройка ноды | Установка, настройка TLS, открытие каналов, backup |
| Разработка API | LNURL-pay, Lightning Address, LNURL-auth endpoints |
| Интеграция с сайтом | Подключение к корзине, настройка callback и successAction |
| Тестирование | Автотесты с regtest, проверка на testnet, нагрузочное |
| Документация и обучение | README с примерами, обучение вашей команды |
Мы также предоставляем поддержку на месяц после запуска.
Согласно спецификации LNURL, протокол поддерживает более 10 LUD-стандартов. Мы реализуем все необходимые.
Оценим ваш проект — напишите нам для консультации. Закажите разработку LNURL-интеграции с индивидуальным подходом. Получите консультацию инженера — свяжитесь с нами.







