Skip to main content
Learn how to withdraw Bitcoin from your Spark wallet to the Lightning Network. This guide covers paying Lightning invoices, fee estimation, and the complete withdrawal process.
Withdraw to Lightning

Lightning Withdrawal Flow

The complete process for withdrawing Bitcoin from Spark to the Lightning Network:
1

Get Lightning Invoice

Obtain a Lightning invoice from the recipient or Lightning service.
// Example Lightning invoice
const invoice = "lnbcrt1u1pnm7ammpp4v84f05tl0kzt6g95g056athdpp8f8azvg6d7epz74z562ymer9jqsp5nc50gazvp0e98u42jlu653rw0eutcl067nqq924hf89q4la4kd9sxq9z0rgqnp4qdnmwu8v22cvq9xsv2l05cn9rre7xlcgdtntxawf8m0zxq3qemgzqrzjqtr2vd60g57hu63rdqk87u3clac6jlfhej4kldrrjvfcw3mphcw8sqqqqrj0q7ew45qqqqqqqqqqqqqq9qcqzpgdq5w3jhxapqd9h8vmmfvdjs9qyyssqj7lf2w4m587g04n4t0ferdv0vnwftzca0xuc9yxycng78cnhrvmyw2mzaa8t76jskpypqnwqhp9xh0vnwxz90jytd34vrmhcngsnl8qplz7ylk";
console.log("Lightning invoice:", invoice);
2

Estimate Fees

Get a fee estimate for the Lightning payment to understand costs.
const feeEstimate = await wallet.getLightningSendFeeEstimate({
  encodedInvoice: invoice
});
console.log("Fee estimate:", feeEstimate);
3

Pay Invoice

Send the Lightning payment with appropriate fee limits.
const payment = await wallet.payLightningInvoice({
  invoice: invoice,
  maxFeeSats: 5, // Maximum fee to pay
  preferSpark: true // Prefer Spark transfers when possible
});
console.log("Payment initiated:", payment);
4

Monitor Payment

Track the payment status until completion.
const paymentStatus = await wallet.getLightningSendRequest(payment.id);
console.log("Payment status:", paymentStatus.status);

Pay Lightning Invoice

Send Bitcoin from your Spark wallet to any Lightning Network invoice. payLightningInvoice(params) Pays a Lightning invoice using your Spark wallet balance.
const payment = await wallet.payLightningInvoice({
  invoice: "lnbcrt1u1pnm7ammpp4v84f05tl0kzt6g95g056athdpp8f8azvg6d7epz74z562ymer9jqsp5nc50gazvp0e98u42jlu653rw0eutcl067nqq924hf89q4la4kd9sxq9z0rgqnp4qdnmwu8v22cvq9xsv2l05cn9rre7xlcgdtntxawf8m0zxq3qemgzqrzjqtr2vd60g57hu63rdqk87u3clac6jlfhej4kldrrjvfcw3mphcw8sqqqqrj0q7ew45qqqqqqqqqqqqqq9qcqzpgdq5w3jhxapqd9h8vmmfvdjs9qyyssqj7lf2w4m587g04n4t0ferdv0vnwftzca0xuc9yxycng78cnhrvmyw2mzaa8t76jskpypqnwqhp9xh0vnwxz90jytd34vrmhcngsnl8qplz7ylk",
  maxFeeSats: 5,
  preferSpark: true,
  amountSatsToSend: 1000 // Only for zero-amount invoices
});

console.log("Payment Response:", payment);

Get Fee Estimate

Estimate the fees for a Lightning payment before sending. getLightningSendFeeEstimate(params) Gets an estimated fee for sending a Lightning payment.
const feeEstimate = await wallet.getLightningSendFeeEstimate({
  encodedInvoice: "lnbcrt1u1pnm7ammpp4v84f05tl0kzt6g95g056athdpp8f8azvg6d7epz74z562ymer9jqsp5nc50gazvp0e98u42jlu653rw0eutcl067nqq924hf89q4la4kd9sxq9z0rgqnp4qdnmwu8v22cvq9xsv2l05cn9rre7xlcgdtntxawf8m0zxq3qemgzqrzjqtr2vd60g57hu63rdqk87u3clac6jlfhej4kldrrjvfcw3mphcw8sqqqqrj0q7ew45qqqqqqqqqqqqqq9qcqzpgdq5w3jhxapqd9h8vmmfvdjs9qyyssqj7lf2w4m587g04n4t0ferdv0vnwftzca0xuc9yxycng78cnhrvmyw2mzaa8t76jskpypqnwqhp9xh0vnwxz90jytd34vrmhcngsnl8qplz7ylk"
});

console.log("Estimated fee:", feeEstimate);

Monitor Payment Status

Track the status of your Lightning payment. getLightningSendRequest(id) Gets a Lightning send request by ID to check payment status.
const paymentStatus = await wallet.getLightningSendRequest(paymentId);
console.log("Payment status:", paymentStatus.status);
console.log("Payment amount:", paymentStatus.amountSats);

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

Zero-Amount Invoices

Spark supports paying zero-amount Lightning invoices, which allow you 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.

Paying Zero-Amount Invoices

When paying a zero-amount invoice, you need to specify the amount using the amountSatsToSend parameter:
// Pay a zero-amount invoice with a specific amount
const payment = await wallet.payLightningInvoice({
  invoice: "lnbc...", // Zero-amount Lightning invoice
  maxFeeSats: 5,
  amountSatsToSend: 1000, // Specify the amount to send (in satoshis)
});

console.log("Zero-amount Payment Response:", payment);
The amountSatsToSend parameter is only used for zero-amount invoices. For regular invoices with a fixed amount, this parameter is ignored.

Spark Transfer Preference

When paying Lightning invoices, you can enable Spark transfer preference to automatically use Spark transfers when possible.
// Pay with Spark preference enabled
const payment = await wallet.payLightningInvoice({
  invoice: "lnbc...", // Lightning invoice (potentially with embedded Spark address)
  maxFeeSats: 5,
  preferSpark: true, // Defaults to false
});

console.log("Payment Response:", payment);
When preferSpark is set to true, Spark wallets will:
  • Initiate a Spark transfer instead of a Lightning transfer if a valid Spark address is found in the invoice
  • Fall back to regular Lightning payment if no Spark address is found

Real-time Payment Monitoring

Monitor Lightning payments using event listeners.
// Listen for transfer events (Lightning payments trigger transfer events)
wallet.on("transfer:claimed", (transferId, updatedBalance) => {
  console.log(`Transfer ${transferId} claimed. New balance: ${updatedBalance} sats`);
});

// Monitor specific payment status
const checkPaymentStatus = async (paymentId) => {
  const paymentStatus = await wallet.getLightningSendRequest(paymentId);
  
  switch (paymentStatus.status) {
    case "completed":
      console.log("Lightning payment completed!");
      return true;
    case "failed":
      console.log("Lightning payment failed");
      return false;
    default:
      console.log("Lightning payment pending...");
      setTimeout(() => checkPaymentStatus(paymentId), 5000); // Check again in 5 seconds
      return false;
  }
};

Fee Recommendations

We recommend setting the maximum routing fee to whichever is greater:
  • 5 sats (minimum fee)
  • 17 bps × transaction amount (0.17% of the transaction)
// Calculate recommended fee
const amountSats = 10000; // Your payment amount
const recommendedFee = Math.max(5, Math.ceil(amountSats * 0.0017)); // 17 bps = 0.17%

const payment = await wallet.payLightningInvoice({
  invoice: "lnbc...",
  maxFeeSats: recommendedFee
});

Error Handling

Implement proper error handling for Lightning payment operations.
async function payLightningSafely(invoice, maxFeeSats) {
  try {
    // 1. Get fee estimate first
    const feeEstimate = await wallet.getLightningSendFeeEstimate({
      encodedInvoice: invoice
    });
    
    console.log("Estimated fee:", feeEstimate);

    // 2. Check if fee is within limits
    if (feeEstimate > maxFeeSats) {
      throw new Error(`Estimated fee (${feeEstimate}) exceeds maximum (${maxFeeSats})`);
    }

    // 3. Pay the invoice
    const payment = await wallet.payLightningInvoice({
      invoice: invoice,
      maxFeeSats: maxFeeSats
    });

    console.log("Payment initiated successfully:", payment.id);
    return payment;

  } catch (error) {
    console.error("Lightning payment failed:", error.message);
    
    // Handle specific error types
    if (error.message.includes("Insufficient")) {
      console.log("Please check your balance");
    } else if (error.message.includes("expired")) {
      console.log("Invoice has expired, please get a new one");
    } else if (error.message.includes("Invalid invoice")) {
      console.log("Please verify the invoice format");
    }
    
    throw error;
  }
}

Best Practices

  • Verify invoice amounts - Always verify invoice amounts before paying
  • Set appropriate fees - Use the recommended fee calculation (5 sats or 17 bps)
  • Monitor payment status - Track payments until completion
  • Handle zero-amount invoices - Use amountSatsToSend for zero-amount invoices
  • Enable Spark preference - Use preferSpark: true for better routing when possible
  • Test on regtest - Always test Lightning payments on regtest before mainnet

Complete Example

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

async function payLightningInvoice() {
  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. Example Lightning invoice (replace with real invoice)
    const invoice = "lnbcrt1u1pnm7ammpp4v84f05tl0kzt6g95g056athdpp8f8azvg6d7epz74z562ymer9jqsp5nc50gazvp0e98u42jlu653rw0eutcl067nqq924hf89q4la4kd9sxq9z0rgqnp4qdnmwu8v22cvq9xsv2l05cn9rre7xlcgdtntxawf8m0zxq3qemgzqrzjqtr2vd60g57hu63rdqk87u3clac6jlfhej4kldrrjvfcw3mphcw8sqqqqrj0q7ew45qqqqqqqqqqqqqq9qcqzpgdq5w3jhxapqd9h8vmmfvdjs9qyyssqj7lf2w4m587g04n4t0ferdv0vnwftzca0xuc9yxycng78cnhrvmyw2mzaa8t76jskpypqnwqhp9xh0vnwxz90jytd34vrmhcngsnl8qplz7ylk";

    // 3. Get fee estimate
    const feeEstimate = await wallet.getLightningSendFeeEstimate({
      encodedInvoice: invoice
    });
    console.log("Fee estimate:", feeEstimate);

    // 4. Calculate recommended fee
    const amountSats = 1000; // Example amount
    const recommendedFee = Math.max(5, Math.ceil(amountSats * 0.0017));

    // 5. Pay the invoice
    const payment = await wallet.payLightningInvoice({
      invoice: invoice,
      maxFeeSats: recommendedFee,
      preferSpark: true
    });

    console.log("Payment initiated:", payment.id);

    // 6. Monitor payment status
    const monitorPayment = async () => {
      const paymentStatus = await wallet.getLightningSendRequest(payment.id);
      
      if (paymentStatus.status === "completed") {
        console.log("Lightning payment completed successfully!");
        console.log("Amount sent:", paymentStatus.amountSats, "sats");
      } else if (paymentStatus.status === "failed") {
        console.log("Lightning payment failed");
      } else {
        console.log("Lightning payment pending...");
        setTimeout(monitorPayment, 5000); // Check again in 5 seconds
      }
    };

    await monitorPayment();

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