---
title: Receiving
slug: receiving
docTags: 
createdAt: 2025-06-04T17:43:14.957Z
---

# 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.

::Image[]{src="https://api.archbee.com/api/optimize/WCn7j8shlcs6zTGZDBCrx-wLOpcfjrClW7i6xbJEu7R-20250613-083637.svg" size="70" width="664" height="969" position="center" showCaption="false"}

## 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.

[Lightning Decoder with decoded invoice](https://lightningdecoder.com/lnbc210n1p5yx9y9pp5uetqwpc4tn0zt58kpj7lzv49m0fr2r5qay004nakhhntjt2ljs5shp5k88pypm532r2zk76vr39llzv609x5680ljyyltmts7fyya95j6qqcqzzsxqyz5vqsp5g5a4pgs628f39a4874fvkq0sy839jg7yzz8svu3y9sc2hfeut3ys9qxpqysgqdjnkc09pc37u97kfjx6lu6uqv4hz0cz29qve2ds7226dxs4j74mjr23gk3mtudzcudtkmr02nvwjx6wrgd0m62mn8mf5m6cfmwtnv5gq5xkdq4)

:::CodeblockTabs
```javascript
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;
  }
};
```

```python
async def create_invoice(lnd_client, amount: int, memo: str):
    """
    Create a new Lightning invoice
    
    Args:
        lnd_client: The LND client instance
        amount: Invoice amount in satoshis
        memo: Invoice description/memo
    
    Returns:
        dict: Invoice data including payment_request and r_hash
    """
    try:
        invoice = await lnd_client.post("/v1/invoices", {
            "value": amount,
            "memo": memo,
            "expiry": 3600  # 1 hour expiry
        })
        return invoice
    except Exception as error:
        print(f"Invoice creation failed: {error}")
        raise error

# Synchronous version
def create_invoice_sync(lnd_client, amount: int, memo: str):
    try:
        invoice = lnd_client.post("/v1/invoices", {
            "value": amount,
            "memo": memo,
            "expiry": 3600  # 1 hour expiry
        })
        return invoice
    except Exception as error:
        print(f"Invoice creation failed: {error}")
        raise error
```

```php
function createInvoice($lndClient, $amount, $memo) {
    /**
     * Create a new Lightning invoice
     * 
     * @param LNDClient $lndClient The LND client instance
     * @param int $amount Invoice amount in satoshis
     * @param string $memo Invoice description/memo
     * @return array Invoice data including payment_request and r_hash
     */
    try {
        $invoice = $lndClient->post('/v1/invoices', [
            'value' => $amount,
            'memo' => $memo,
            'expiry' => 3600  // 1 hour expiry
        ]);
        return $invoice;
    } catch (Exception $error) {
        error_log("Invoice creation failed: " . $error->getMessage());
        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.

:::CodeblockTabs
```javascript
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;
  }
};
```

```python
async def check_invoice_status(lnd_client, r_hash: str):
    """
    Check the status of an invoice by its r_hash
    
    Args:
        lnd_client: The LND client instance
        r_hash: The invoice's r_hash (payment hash)
    
    Returns:
        dict: Invoice data including state and settlement info
    """
    try:
        invoice = await lnd_client.get(f"/v1/invoice/{r_hash}")
        return invoice
    except Exception as error:
        print(f"Invoice lookup failed: {error}")
        raise error

```

```php
function checkInvoiceStatus($lndClient, $rHash) {
    /**
     * Check the status of an invoice by its r_hash
     * 
     * @param LNDClient $lndClient The LND client instance
     * @param string $rHash The invoice's r_hash (payment hash)
     * @return array Invoice data including state and settlement info
     */
    try {
        $invoice = $lndClient->get("/v1/invoice/{$rHash}");
        return $invoice;
    } catch (Exception $error) {
        error_log("Invoice lookup failed: " . $error->getMessage());
        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.

:::CodeblockTabs
```javascript
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);
    }
  };
};
```

```python
import websockets
import json

async def subscribe_to_invoice(host: str, macaroon: str, payment_hash: str):
    """
    Subscribe to invoice updates via WebSocket
    
    Args:
        host: LND node host
        macaroon: Authentication macaroon
        payment_hash: The invoice's payment hash to monitor
    """
    uri = f"wss://{host}:8080/v1/invoices/subscribe"
    headers = {
        "Grpc-Metadata-Macaroon": macaroon
    }
    
    async with websockets.connect(uri, extra_headers=headers, ssl=True) as websocket:
        async for message in websocket:
            invoice = json.loads(message)
            
            if invoice.get('r_hash') == payment_hash:
                # Handle invoice update
                await handle_invoice_update(invoice)
                
                # Exit if settled
                if invoice.get('state') == 'SETTLED':
                    break
```

```php
use WebSocket\Client;

function subscribeToInvoice($host, $macaroon, $paymentHash) {
    /**
     * Subscribe to invoice updates via WebSocket
     * 
     * @param string $host LND node host
     * @param string $macaroon Authentication macaroon
     * @param string $paymentHash The invoice's payment hash to monitor
     */
    $uri = "wss://{$host}:8080/v1/invoices/subscribe";
    
    try {
        $client = new Client($uri, [
            'timeout' => 60,
            'headers' => [
                'Grpc-Metadata-Macaroon' => $macaroon
            ],
            'context' => stream_context_create([
                'ssl' => [
                    'verify_peer' => false,  // Set to true in production
                    'verify_peer_name' => false  // Set to true in production
                ]
            ])
        ]);
        
        while (true) {
            $message = $client->receive();
            $invoice = json_decode($message, true);
            
            if (isset($invoice['r_hash']) && $invoice['r_hash'] === $paymentHash) {
                // Handle invoice update
                handleInvoiceUpdate($invoice);
                
                // Exit if settled
                if (isset($invoice['state']) && $invoice['state'] === 'SETTLED') {
                    break;
                }
            }
        }
        
        $client->close();
        
    } catch (Exception $e) {
        error_log("WebSocket error: " . $e->getMessage());
        throw $e;
    }
}
```
:::

### 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.

:::CodeblockTabs
```javascript
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);
  });
};
```

```python
import grpc
from lightning import lightning_pb2, lightning_pb2_grpc

def subscribe_to_invoices_grpc(host: str, port: int, macaroon: str, cert_path: str):
    """
    Subscribe to all invoice updates via gRPC
    
    Args:
        host: LND node host
        port: gRPC port (usually 10009)
        macaroon: Authentication macaroon (hex string)
        cert_path: Path to TLS certificate
    """
    # Create credentials
    with open(cert_path, 'rb') as f:
        cert = f.read()
    
    creds = grpc.ssl_channel_credentials(cert)
    
    # Create channel with macaroon metadata
    channel = grpc.secure_channel(f'{host}:{port}', creds)
    stub = lightning_pb2_grpc.LightningStub(channel)
    
    # Prepare macaroon metadata
    metadata = [('macaroon', macaroon)]
    
    # Subscribe to invoices
    request = lightning_pb2.InvoiceSubscription()
    
    try:
        # Stream invoice updates
        for invoice in stub.SubscribeInvoices(request, metadata=metadata):
            handle_invoice_update_grpc(invoice)
    except grpc.RpcError as e:
        print(f"gRPC subscription error: {e.code()} - {e.details()}")
        raise
```

```php
// GRPC implementation using grpc/grpc (requires protobuf compilation)
// First install: composer require grpc/grpc google/protobuf

function subscribeToInvoicesGrpc($host, $port, $macaroon, $certPath) {
    /**
     * Subscribe to all invoice updates via gRPC
     * 
     * @param string $host LND node host
     * @param int $port gRPC port (usually 10009)
     * @param string $macaroon Authentication macaroon (hex string)
     * @param string $certPath Path to TLS certificate
     */
    
    // Read certificate
    $cert = file_get_contents($certPath);
    
    // Create credentials
    $credentials = \Grpc\ChannelCredentials::createSsl($cert);
    
    // Create client
    $client = new Lightning\LightningClient(
        "{$host}:{$port}",
        [
            'credentials' => $credentials,
            'update_metadata' => function($metaData) use ($macaroon) {
                $metaData['macaroon'] = [$macaroon];
                return $metaData;
            }
        ]
    );
    
    // Create subscription request
    $request = new Lightning\InvoiceSubscription();
    
    // Subscribe to invoices
    $call = $client->SubscribeInvoices($request);
    
    // Process stream
    foreach ($call->responses() as $invoice) {
        handleInvoiceUpdateGrpc($invoice);
    }
}
```
:::

## 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.





