Skip to main content
Learn how to receive Bitcoin deposits through the Lightning Network. This guide covers Lightning invoice creation, receiving payments, and integrating Lightning deposits into your Spark wallet.
Deposit from Lightning

Understanding Lightning Invoices

To send and receive Lightning payments, you can generate and pay Lightning invoices. A Lightning invoice (also called a payment request) is a specially formatted string that contains all the information needed to make a Lightning Network payment:
  • Amount: How many satoshis to send (can be omitted for zero-amount invoices)
  • Destination: The recipient’s node public key
  • Payment Hash: A unique identifier for the payment
  • Description: Optional memo describing the payment
  • Expiry: How long the invoice is valid for (default 24 hours)
Lightning invoices start with “ln” followed by the network identifier (bc for mainnet) and typically look like this: lnbc1... Mainnet invoice Example:
lnbcrt2500n1pj0ytfcpp5qqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqdx40shp5jqp3qymd6qgpy99ppk0jqjzylqg5t7fhqhpl6s4kxmqgmrn59w5k0z0cqqqqqqzqqqqq9qsqqqqqq9qqqqqqgq9qsqxl9l55y5cwa9s2h8nvdh4h7h43tcwjdcysf7v0fprz5uh6vshs4n0tvhgzz2xgcqpg8yqv7

Lightning Deposit Flow

The complete process for receiving Lightning payments into your Spark wallet:
1

Create Invoice

Generate a Lightning invoice with the desired amount and description.
const invoice = await wallet.createLightningInvoice({
amountSats: 50000,
memo: "Deposit to Spark wallet"
});
2

Share Invoice

Provide the invoice to the sender (via QR code, link, or text).
// Display invoice for user to share
console.log("Share this invoice:", invoice.invoice);
console.log("Or share this ID:", invoice.id);
3

Monitor Payment

Track the payment status until completion.
// Poll for payment status
const checkPayment = async (invoiceId) => {
  const request = await wallet.getLightningReceiveRequest(invoiceId);
  
  if (request.status === "completed") {
    console.log("Payment received:", request.amountReceived, "sats");
    return true;
  } else if (request.status === "expired") {
    console.log("Invoice expired");
    return false;
  } else {
    console.log("Payment pending...");
    return false;
  }
};

Create Lightning Invoice

Generate Lightning invoices to receive Bitcoin payments that will be deposited into your Spark wallet. createLightningInvoice(params) Creates a Lightning invoice for receiving Bitcoin payments.
const invoice = await wallet.createLightningInvoice({
  amountSats: 10000,        // Amount in satoshis
  memo: "Payment for services", // Optional description
  includeSparkAddress: true // Optional: embed Spark address
});

console.log("Lightning invoice:", invoice.invoice);
console.log("Invoice ID:", invoice.id);

Embedding Spark Addresses

By passing in true for includeSparkAddress, a 36-byte string consisting of a recognizable header and a receiver’s compressed identity public key SPK:identitypubkey will get embedded in the fallback address (f) field of a BOLT11 invoice:
const invoice = await wallet.createLightningInvoice({
  amountSats: 100,
  memo: "Invoice with Spark address",
  includeSparkAddress: true,
});
console.log("Invoice with Spark address:", invoice);

Fallback Address Format

The embedded Spark address in the fallback field will look something like this:
{
  version: 31,
  address_hash: "53504b0250949ec35b022e3895fd37750102f94fe813523fa220108328a81790bf67ade5"
}

Creating Invoices for Other Spark Users

To generate an invoice for another Spark user, pass in the 33-byte compressed identity pubkey as a string to receiverIdentityPubkey:
const invoice = await wallet.createLightningInvoice({
  amountSats: 100,
  memo: "Invoice for another user",
  receiverIdentityPubkey: "033b4f8cf891e45e2e3995e29b3c8b3d4d4e67f8a9b2c1d3e4f567890abcdef12",
});
console.log("Invoice for another user:", invoice);
If a wallet is generating an invoice for itself and wants to embed its own Spark identity in the invoice, it will not need to pass in a receiverIdentityPubkey to embed a Spark address. That will get taken care of on the backend. Passing it in shouldn’t change anything though.

Zero-Amount Invoices

Spark supports creating zero-amount Lightning invoices. Zero-amount invoices don’t have a fixed amount and allow the sender to specify the amount when making the payment.
Zero-amount invoices are not widely supported across the Lightning Network. Some exchanges, such as Binance, currently do not support them.

Creating Zero-Amount Invoices

To create a zero-amount invoice, pass 0 for the amountSats parameter:
// Create a zero-amount invoice
const zeroAmountInvoice = await wallet.createLightningInvoice({
  amountSats: 0, // Creates a zero-amount invoice
  memo: "Pay any amount you want",
});
console.log("Zero-amount Invoice:", zeroAmountInvoice);

Monitor Lightning Payments

Track incoming Lightning payments and their status using receive request monitoring. getLightningReceiveRequest(id) Gets the status of a Lightning receive request by ID.
// Monitor a specific invoice
const receiveRequest = await wallet.getLightningReceiveRequest(invoiceId);
console.log("Payment status:", receiveRequest.status);
console.log("Amount received:", receiveRequest.amountReceived);

// Check if payment is complete
if (receiveRequest.status === "completed") {
  console.log("Payment received successfully!");
}

Real-time Payment Monitoring

Use event listeners to monitor Lightning payments in real-time.
// Listen for transfer events (Lightning payments trigger transfer events)
wallet.on("transfer:claimed", (transferId, updatedBalance) => {
  console.log(`Transfer ${transferId} claimed. New balance: ${updatedBalance} sats`);
});

Error Handling

Implement proper error handling for Lightning invoice operations.
async function createInvoiceSafely(params) {
  try {
    // Validate amount
    if (params.amountSats <= 0) {
      throw new Error("Amount must be greater than 0");
    }

    // Validate expiry time
    if (params.expiryTime && params.expiryTime < 60) {
      throw new Error("Expiry time must be at least 60 seconds");
    }

    // Create invoice
    const invoice = await wallet.createLightningInvoice(params);
    console.log("Invoice created successfully:", invoice.id);
    return invoice;
    
  } catch (error) {
    console.error("Failed to create invoice:", error.message);
    
    // Handle specific error types
    if (error.message.includes("Amount")) {
      console.log("Please check the amount value");
    } else if (error.message.includes("Expiry")) {
      console.log("Please check the expiry time");
    } else if (error.message.includes("Network")) {
      console.log("Network error. Please try again.");
    }
    
    throw error;
  }
}

Checking Balance

You can use getBalance() to check a wallet balance after receiving payments. The getBalance() method returns a Promise resolving to an object containing:
  • balance: A bigint representing the total amount in satoshis
  • tokenBalances: A Map of token balances, where each entry contains:
    • balance: A bigint representing the token amount
    • tokenInfo: Information about the specific token the wallet is holding
const balanceInfo = await wallet.getBalance();
console.log("Balance:", balanceInfo.balance, "sats");
Additionally, you can listen for balance update events:
wallet.on("transfer:claimed", (transferId: string, balance: number) => {
  console.log(`Transfer ${transferId} claimed. New balance: ${balance}`);
});

Best Practices

  • Set appropriate expiry times - Balance between urgency and flexibility
  • Include clear descriptions - Help senders understand the payment purpose
  • Monitor payment status - Use polling or events to track payments
  • Handle expired invoices - Implement retry logic for expired invoices
  • Validate amounts - Ensure amounts are reasonable and valid
  • Use real-time monitoring - Implement event listeners for better UX
  • Analyze invoice data - Use the bolt11 library to decode and verify invoice data
  • Keep track of invoice IDs - Match balance changes to created invoices

Example: Complete Lightning Deposit Flow

import { SparkWallet } from "@buildonspark/spark-sdk";

async function completeLightningDeposit() {
  const { wallet } = await SparkWallet.initialize({
    options: { network: "REGTEST" }
  });

  try {
    // 1. Set up event listeners
    wallet.on("transfer:claimed", (transferId, updatedBalance) => {
      console.log(`Transfer ${transferId} claimed. New balance: ${updatedBalance} sats`);
    });

    // 2. Create Lightning invoice
    const invoice = await wallet.createLightningInvoice({
      amountSats: 10000,
      memo: "Lightning deposit to Spark wallet"
    });

    console.log("Invoice created:", invoice.invoice);
    console.log("Invoice ID:", invoice.id);

    // 3. Monitor payment status
    const monitorPayment = async () => {
      const request = await wallet.getLightningReceiveRequest(invoice.id);
      
      switch (request.status) {
        case "completed":
          console.log("Payment completed!");
          return true;
        case "expired":
          console.log("Invoice expired");
          return false;
        default:
          console.log("Payment pending...");
          setTimeout(monitorPayment, 5000); // Check again in 5 seconds
          return false;
      }
    };

    // Start monitoring
    await monitorPayment();

  } catch (error) {
    console.error("Lightning deposit failed:", error);
  }
}