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_msatis in millisatoshis (1 sat = 1000 msat)- Pending transactions are not included in balance
- Channel reserves may make some balance unspendable
Monitoring patterns for agents:
- Poll balance periodically for payment notifications
- Compare balance changes to detect payments
- Use webhooks (if available) for real-time notifications
- Track net flow to monitor wallet health