Receiving
Receiving Payments:
Lightning Network payments begin with invoice creation and require monitoring to confirm successful payment reception. LND provides multiple methods for creating invoices and tracking their payment status, from simple REST polling to real-time streaming interfaces.
1. Create Invoice
Lightning invoices are payment requests that contain all the information needed for a payer to send funds to your node. When you create an invoice, LND generates a unique payment hash and returns a BOLT11-encoded payment request string that can be shared via QR code, copied directly, or embedded in your application.
Each invoice includes essential details like the payment amount (in satoshis), an optional memo describing the payment purpose, and an expiration time. The invoice remains valid until either it's paid in full, manually canceled, or reaches its expiry time.
const createInvoice = async (amount, memo) => {
try {
const invoice = await lnd.post("/v1/invoices", {
value: amount,
memo: memo,
expiry: 3600 // 1 hour expiry
});
return invoice.data;
} catch (error) {
console.error("Invoice creation failed:", error);
throw error;
}
};2. Monitor Invoice Status Choose one of these methods based on your needs:
Once an invoice is created, you need to monitor its status to know when payment has been received. LND offers several approaches for tracking invoice payments, each suited to different application architectures and requirements.
Choose the monitoring method that best fits your needs:
REST polling:
Best for: Simple integrations, HTTP-only environments, or applications that don't require immediate payment notifications.
REST polling involves making periodic API calls to check if an invoice has been paid. While straightforward to implement, this method introduces some latency between payment completion and detection. It's ideal when you need basic payment tracking without the complexity of persistent connections.
const checkInvoiceStatus = async (rHash) => {
try {
const invoice = await lnd.get(/v1/invoice/${rHash});
return invoice.data;
} catch (error) {
console.error("Invoice lookup failed:", error);
throw error;
}
};Websocket subscription:
Best for: Real-time applications, browser-based implementations, or when you need immediate payment notifications with lower server overhead than REST polling.
WebSockets provide real-time, bidirectional communication that allows your application to receive instant notifications when invoice status changes. This eliminates polling delays and reduces server load, making it perfect for dashboards, point-of-sale systems, or any application where immediate payment confirmation enhances user experience.
const subscribeToInvoice = (paymentHash) => {
const ws = new WebSocket(wss://${HOST}:8080/v1/invoices/subscribe);
ws.onmessage = (event) => {
const invoice = JSON.parse(event.data);
if (invoice.r_hash === paymentHash) {
// Handle invoice update
handleInvoiceUpdate(invoice);
}
};
};GRPC:
Best for: Server-side applications requiring the most efficient real-time updates, high-throughput environments, or when you need the full feature set of LND's streaming capabilities.
gRPC provides the most efficient and feature-complete interface for monitoring invoice status. With strongly-typed responses and bidirectional streaming, it offers the lowest latency and highest reliability for payment tracking. This method is ideal for production applications that need robust, persistent connections to your Lightning node.
const subscribeToInvoices = (client) => {
const stream = client.subscribeInvoices({});
stream.on('data', (invoice) => {
// Handle invoice update
handleInvoiceUpdate(invoice);
});
stream.on('error', (error) => {
console.error("Invoice subscription error:", error);
});
};Implementation Considerations
Security: Use read-only or invoice-specific macaroons rather than admin macaroons when possible or in environments that do not need full admin access (for sending out funds onchain or over Lightning). Implement sensible rate limiting (e.g., max 100 invoices per minute per IP) to prevent abuse.
Error Handling: WebSocket connections drop frequently—implement exponential backoff reconnection starting at 1 second, maxing at 30 seconds. For gRPC streams, catch UNAVAILABLE and DEADLINE_EXCEEDED errors specifically and restart the subscription. REST polling should handle 5xx errors by increasing the poll interval temporarily (e.g., from 5 seconds to 30 seconds) before returning to normal frequency.
Scalability: For high-volume applications, gRPC streaming typically offers the best performance, while REST polling may be sufficient for lower-volume use cases.
User Experience: Real-time payment confirmation significantly improves user experience compared to polling-based approaches, particularly for interactive applications like point-of-sale systems.