Menu
Lightning Python Executable Jan 31, 2026

Check Lightning Wallet Balance

Query Lightning wallet balance and transaction history via LNbits API

#lnbits #balance #wallet #api

Overview

Query your Lightning wallet balance and recent transactions. This only requires an Invoice/Read key (no Admin key needed for read operations).

The Code

"""
Lightning Wallet Balance Checker
Query balance and history via LNbits API

Requirements:
- requests (pip install requests)
- LNbits instance with Invoice/Read key

Environment variables:
- LNBITS_URL: Your LNbits instance URL
- LNBITS_INVOICE_KEY: Invoice/Read API key (read-only access)
"""

import os
import requests
from datetime import datetime
from typing import List, Optional
from dataclasses import dataclass

# Configuration
LNBITS_URL = os.getenv("LNBITS_URL", "https://legend.lnbits.com")
LNBITS_INVOICE_KEY = os.getenv("LNBITS_INVOICE_KEY", "")


@dataclass
class WalletInfo:
    """Wallet information."""
    name: str
    balance_sats: int
    balance_msat: int


@dataclass
class Transaction:
    """Lightning transaction."""
    payment_hash: str
    amount_sats: int
    fee_msat: int
    memo: str
    time: datetime
    is_outgoing: bool
    pending: bool


def get_wallet_info() -> WalletInfo:
    """
    Get wallet name and balance.

    Returns:
        WalletInfo with balance details
    """
    if not LNBITS_INVOICE_KEY:
        raise ValueError("LNBITS_INVOICE_KEY not set")

    headers = {"X-Api-Key": LNBITS_INVOICE_KEY}

    response = requests.get(
        f"{LNBITS_URL}/api/v1/wallet",
        headers=headers,
        timeout=10
    )
    response.raise_for_status()

    data = response.json()
    balance_msat = data.get("balance", 0)

    return WalletInfo(
        name=data.get("name", "Unknown"),
        balance_sats=balance_msat // 1000,
        balance_msat=balance_msat
    )


def get_transactions(limit: int = 20) -> List[Transaction]:
    """
    Get recent transactions.

    Args:
        limit: Maximum number of transactions to return

    Returns:
        List of Transaction objects
    """
    if not LNBITS_INVOICE_KEY:
        raise ValueError("LNBITS_INVOICE_KEY not set")

    headers = {"X-Api-Key": LNBITS_INVOICE_KEY}

    response = requests.get(
        f"{LNBITS_URL}/api/v1/payments",
        headers=headers,
        params={"limit": limit},
        timeout=10
    )
    response.raise_for_status()

    transactions = []
    for tx in response.json():
        amount_msat = tx.get("amount", 0)
        is_outgoing = amount_msat < 0

        transactions.append(Transaction(
            payment_hash=tx.get("payment_hash", ""),
            amount_sats=abs(amount_msat) // 1000,
            fee_msat=tx.get("fee", 0),
            memo=tx.get("memo", ""),
            time=datetime.fromtimestamp(tx.get("time", 0)),
            is_outgoing=is_outgoing,
            pending=tx.get("pending", False)
        ))

    return transactions


def get_payment_stats(days: int = 30) -> dict:
    """
    Calculate payment statistics.

    Args:
        days: Number of days to analyze

    Returns:
        dict with payment statistics
    """
    from datetime import timedelta

    transactions = get_transactions(limit=1000)
    cutoff = datetime.now() - timedelta(days=days)

    recent = [tx for tx in transactions if tx.time > cutoff and not tx.pending]

    incoming = [tx for tx in recent if not tx.is_outgoing]
    outgoing = [tx for tx in recent if tx.is_outgoing]

    total_received = sum(tx.amount_sats for tx in incoming)
    total_sent = sum(tx.amount_sats for tx in outgoing)
    total_fees = sum(tx.fee_msat for tx in outgoing) // 1000

    return {
        "period_days": days,
        "total_transactions": len(recent),
        "incoming_count": len(incoming),
        "outgoing_count": len(outgoing),
        "total_received_sats": total_received,
        "total_sent_sats": total_sent,
        "total_fees_sats": total_fees,
        "net_flow_sats": total_received - total_sent,
        "avg_incoming_sats": total_received // len(incoming) if incoming else 0,
        "avg_outgoing_sats": total_sent // len(outgoing) if outgoing else 0
    }


def format_sats(sats: int) -> str:
    """Format satoshis with thousands separator."""
    return f"{sats:,}"


def format_transaction(tx: Transaction) -> str:
    """Format a transaction for display."""
    direction = "←" if not tx.is_outgoing else "→"
    status = " (pending)" if tx.pending else ""
    amount = format_sats(tx.amount_sats)
    fee = f" (fee: {tx.fee_msat} msat)" if tx.fee_msat > 0 else ""

    return (
        f"{direction} {amount:>12} sats  "
        f"{tx.time.strftime('%Y-%m-%d %H:%M')}  "
        f"{tx.memo[:30]}{fee}{status}"
    )


# Example usage
if __name__ == "__main__":
    if not LNBITS_INVOICE_KEY:
        print("Set LNBITS_INVOICE_KEY environment variable")
        exit(1)

    try:
        # Get wallet info
        wallet = get_wallet_info()
        print("=" * 60)
        print(f"Wallet: {wallet.name}")
        print(f"Balance: {format_sats(wallet.balance_sats)} sats")
        print(f"         ({wallet.balance_msat:,} msat)")
        print("=" * 60)

        # Get recent transactions
        print("\n=== Recent Transactions ===")
        transactions = get_transactions(limit=10)

        if not transactions:
            print("No transactions found")
        else:
            for tx in transactions:
                print(format_transaction(tx))

        # Get statistics
        print("\n=== 30-Day Statistics ===")
        stats = get_payment_stats(days=30)
        print(f"Transactions:  {stats['total_transactions']}")
        print(f"  Incoming:    {stats['incoming_count']} ({format_sats(stats['total_received_sats'])} sats)")
        print(f"  Outgoing:    {stats['outgoing_count']} ({format_sats(stats['total_sent_sats'])} sats)")
        print(f"  Fees paid:   {format_sats(stats['total_fees_sats'])} sats")
        print(f"  Net flow:    {format_sats(stats['net_flow_sats'])} sats")

    except requests.RequestException as e:
        print(f"API error: {e}")
    except ValueError as e:
        print(f"Configuration error: {e}")

Usage

# Set environment variables
export LNBITS_URL="https://your-lnbits.com"
export LNBITS_INVOICE_KEY="your-invoice-read-key"

# Install and run
pip install requests
python check_balance.py

Example Output

============================================================
Wallet: Agent Wallet
Balance: 45,230 sats
         (45,230,000 msat)
============================================================

=== Recent Transactions ===
←       1,000 sats  2026-01-31 14:30  Payment from Bob
→       5,000 sats  2026-01-31 12:15  API service fee (fee: 1200 msat)
←      10,000 sats  2026-01-30 09:45  Zap from Nostr
→       2,500 sats  2026-01-29 18:20  Coffee payment

=== 30-Day Statistics ===
Transactions:  47
  Incoming:    32 (125,000 sats)
  Outgoing:    15 (79,770 sats)
  Fees paid:   23 sats
  Net flow:    45,230 sats

Agent Notes

Read-only access: Invoice/Read key cannot spend funds, making it safe to use for monitoring.

Balance considerations:

  • balance_msat is in millisatoshis (1 sat = 1000 msat)
  • Pending transactions are not included in balance
  • Channel reserves may make some balance unspendable

Monitoring patterns for agents:

  1. Poll balance periodically for payment notifications
  2. Compare balance changes to detect payments
  3. Use webhooks (if available) for real-time notifications
  4. Track net flow to monitor wallet health