12 KiB
12 KiB
LNbits WebSocket Implementation Guide
Overview
LNbits provides real-time WebSocket connections for monitoring wallet status, payment confirmations, and transaction updates. This guide covers how to implement and use these WebSocket connections in your applications.
WebSocket Endpoints
1. Payment Monitoring WebSocket
- URL:
ws://localhost:5006/api/v1/ws/{wallet_inkey} - HTTPS:
wss://your-domain.com/api/v1/ws/{wallet_inkey} - Purpose: Real-time payment notifications and wallet updates
2. Generic WebSocket Communication
- URL:
ws://localhost:5006/api/v1/ws/{item_id} - Purpose: Custom real-time communication channels
Client-Side Implementation
JavaScript/Browser Implementation
Basic WebSocket Connection
// Construct WebSocket URL
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
const websocketUrl = `${protocol}//${window.location.host}/api/v1/ws`
// Connect to payment monitoring
const ws = new WebSocket(`${websocketUrl}/${wallet.inkey}`)
// Handle incoming messages
ws.onmessage = (event) => {
const data = JSON.parse(event.data)
console.log('Received:', data)
if (data.payment) {
handlePaymentReceived(data.payment)
}
}
// Handle connection events
ws.onopen = () => {
console.log('WebSocket connected')
}
ws.onclose = () => {
console.log('WebSocket disconnected')
}
ws.onerror = (error) => {
console.error('WebSocket error:', error)
}
Using LNbits Built-in Event System
// Using the built-in LNbits event system
LNbits.events.onInvoicePaid(wallet, (data) => {
if (data.payment) {
console.log('Payment confirmed:', data.payment)
// Update UI
updateWalletBalance(data.payment.amount)
showPaymentNotification(data.payment)
}
})
Vue.js Implementation Example
// Vue component method
initWebSocket() {
const protocol = location.protocol === 'http:' ? 'ws://' : 'wss://'
const wsUrl = `${protocol}${document.domain}:${location.port}/api/v1/ws/${this.wallet.inkey}`
this.ws = new WebSocket(wsUrl)
this.ws.addEventListener('message', async ({ data }) => {
const response = JSON.parse(data.toString())
if (response.payment) {
// Handle payment update
await this.handlePaymentUpdate(response.payment)
}
})
this.ws.addEventListener('open', () => {
this.connectionStatus = 'connected'
})
this.ws.addEventListener('close', () => {
this.connectionStatus = 'disconnected'
// Implement reconnection logic
setTimeout(() => this.initWebSocket(), 5000)
})
}
Python Client Implementation
import asyncio
import websockets
import json
async def listen_to_wallet(wallet_inkey, base_url="ws://localhost:5006"):
uri = f"{base_url}/api/v1/ws/{wallet_inkey}"
try:
async with websockets.connect(uri) as websocket:
print(f"Connected to WebSocket: {uri}")
async for message in websocket:
data = json.loads(message)
if 'payment' in data:
payment = data['payment']
print(f"Payment received: {payment['amount']} sat")
print(f"Payment hash: {payment['payment_hash']}")
# Process payment
await handle_payment_received(payment)
except websockets.exceptions.ConnectionClosed:
print("WebSocket connection closed")
except Exception as e:
print(f"WebSocket error: {e}")
async def handle_payment_received(payment):
"""Process incoming payment"""
# Update database
# Send notifications
# Update application state
pass
# Run the WebSocket listener
if __name__ == "__main__":
wallet_inkey = "your_wallet_inkey_here"
asyncio.run(listen_to_wallet(wallet_inkey))
Node.js Client Implementation
const WebSocket = require('ws')
class LNbitsWebSocketClient {
constructor(walletInkey, baseUrl = 'ws://localhost:5006') {
this.walletInkey = walletInkey
this.baseUrl = baseUrl
this.ws = null
this.reconnectInterval = 5000
}
connect() {
const url = `${this.baseUrl}/api/v1/ws/${this.walletInkey}`
this.ws = new WebSocket(url)
this.ws.on('open', () => {
console.log(`Connected to LNbits WebSocket: ${url}`)
})
this.ws.on('message', (data) => {
try {
const message = JSON.parse(data.toString())
this.handleMessage(message)
} catch (error) {
console.error('Error parsing WebSocket message:', error)
}
})
this.ws.on('close', () => {
console.log('WebSocket connection closed. Reconnecting...')
setTimeout(() => this.connect(), this.reconnectInterval)
})
this.ws.on('error', (error) => {
console.error('WebSocket error:', error)
})
}
handleMessage(message) {
if (message.payment) {
console.log('Payment received:', message.payment)
this.onPaymentReceived(message.payment)
}
}
onPaymentReceived(payment) {
// Override this method to handle payments
console.log(`Received ${payment.amount} sat`)
}
disconnect() {
if (this.ws) {
this.ws.close()
}
}
}
// Usage
const client = new LNbitsWebSocketClient('your_wallet_inkey_here')
client.onPaymentReceived = (payment) => {
// Custom payment handling
console.log(`Processing payment: ${payment.payment_hash}`)
}
client.connect()
Server-Side Implementation (LNbits Extensions)
Sending WebSocket Updates
from lnbits.core.services import websocket_manager
async def notify_wallet_update(wallet_inkey: str, payment_data: dict):
"""Send payment update to connected WebSocket clients"""
message = {
"payment": payment_data,
"timestamp": int(time.time())
}
await websocket_manager.send(wallet_inkey, json.dumps(message))
# Example usage in payment processing
async def process_payment_confirmation(payment_hash: str):
payment = await get_payment(payment_hash)
if payment.wallet:
await notify_wallet_update(payment.wallet, {
"payment_hash": payment.payment_hash,
"amount": payment.amount,
"memo": payment.memo,
"status": "confirmed"
})
HTTP Endpoints for WebSocket Updates
# Send data via GET request
@router.get("/notify/{wallet_inkey}/{message}")
async def notify_wallet_get(wallet_inkey: str, message: str):
await websocket_manager.send(wallet_inkey, message)
return {"sent": True, "message": message}
# Send data via POST request
@router.post("/notify/{wallet_inkey}")
async def notify_wallet_post(wallet_inkey: str, data: str):
await websocket_manager.send(wallet_inkey, data)
return {"sent": True, "data": data}
Message Format
Payment Notification Message
{
"payment": {
"payment_hash": "abc123...",
"amount": 1000,
"memo": "Test payment",
"status": "confirmed",
"timestamp": 1640995200,
"fee": 1,
"wallet_id": "wallet_uuid"
}
}
Custom Message Format
{
"type": "balance_update",
"wallet_id": "wallet_uuid",
"balance": 50000,
"timestamp": 1640995200
}
Best Practices
1. Connection Management
- Implement automatic reconnection logic
- Handle connection timeouts gracefully
- Use exponential backoff for reconnection attempts
2. Error Handling
class WebSocketManager {
constructor(walletInkey) {
this.walletInkey = walletInkey
this.maxReconnectAttempts = 10
this.reconnectAttempts = 0
this.reconnectDelay = 1000
}
connect() {
try {
this.ws = new WebSocket(this.getWebSocketUrl())
this.setupEventHandlers()
} catch (error) {
this.handleConnectionError(error)
}
}
handleConnectionError(error) {
console.error('WebSocket connection error:', error)
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++
const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1)
setTimeout(() => {
console.log(`Reconnection attempt ${this.reconnectAttempts}`)
this.connect()
}, delay)
} else {
console.error('Max reconnection attempts reached')
}
}
}
3. Message Validation
function validatePaymentMessage(data) {
if (!data.payment) return false
const payment = data.payment
return (
typeof payment.payment_hash === 'string' &&
typeof payment.amount === 'number' &&
payment.amount > 0 &&
['pending', 'confirmed', 'failed'].includes(payment.status)
)
}
4. Security Considerations
- Use HTTPS/WSS in production
- Validate wallet permissions before connecting
- Implement rate limiting for WebSocket connections
- Never expose admin keys through WebSocket messages
Testing WebSocket Connections
Using wscat (Command Line Tool)
# Install wscat
npm install -g wscat
# Connect to WebSocket
wscat -c ws://localhost:5006/api/v1/ws/your_wallet_inkey
# Test with SSL
wscat -c wss://your-domain.com/api/v1/ws/your_wallet_inkey
Browser Console Testing
// Open browser console and run:
const ws = new WebSocket('ws://localhost:5006/api/v1/ws/your_wallet_inkey')
ws.onmessage = (e) => console.log('Received:', JSON.parse(e.data))
ws.onopen = () => console.log('Connected')
ws.onclose = () => console.log('Disconnected')
Sending Test Messages
# Using curl to trigger WebSocket message
curl "http://localhost:5006/api/v1/ws/your_wallet_inkey/test_message"
# Using POST
curl -X POST "http://localhost:5006/api/v1/ws/your_wallet_inkey" \
-H "Content-Type: application/json" \
-d '"test message data"'
Troubleshooting
Common Issues
-
Connection Refused
- Verify LNbits server is running on correct port
- Check firewall settings
- Ensure WebSocket endpoint is enabled
-
Authentication Errors
- Verify wallet inkey is correct
- Check wallet permissions
- Ensure wallet exists and is active
-
Message Not Received
- Check WebSocket connection status
- Verify message format
- Test with browser dev tools
-
Frequent Disconnections
- Implement proper reconnection logic
- Check network stability
- Monitor server logs for errors
Debug Logging
// Enable verbose WebSocket logging
const ws = new WebSocket(wsUrl)
ws.addEventListener('open', (event) => {
console.log('WebSocket opened:', event)
})
ws.addEventListener('close', (event) => {
console.log('WebSocket closed:', event.code, event.reason)
})
ws.addEventListener('error', (event) => {
console.error('WebSocket error:', event)
})
Production Deployment
Nginx Configuration
location /api/v1/ws/ {
proxy_pass http://localhost:5006;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400;
}
SSL/TLS Configuration
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location /api/v1/ws/ {
proxy_pass http://localhost:5006;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# ... other headers
}
}
Conclusion
LNbits WebSocket implementation provides a robust foundation for real-time wallet monitoring and payment processing. By following this guide, you can implement reliable WebSocket connections that enhance user experience with instant payment notifications and live wallet updates.
Remember to implement proper error handling, reconnection logic, and security measures when deploying to production environments.