Skip to main content

Simple Python wrapper for Lexe Bitcoin Lightning Network wallet integration

Project description

Lexe Wrapper

A simple Python package for integrating Bitcoin Lightning Network payments using the Lexe wallet. Install with pip and start building Lightning apps in minutes, not hours.

pip install lexe-wrapper

What This Package Solves

The Lexe Sidecar API is already clean and simple, but there are several setup gotchas that slow down development:

  1. Binary Management: Downloading and extracting the correct Lexe sidecar binary
  2. Process Management: Starting and stopping the sidecar subprocess
  3. Credentials Handling: Properly encoding and validating base64 client credentials
  4. Connection Management: Ensuring the sidecar is healthy and ready to accept requests
  5. Port Configuration: Managing the correct port (5393) for communication

This package handles all of these automatically, so you can focus on building great Lightning applications.

Quick Start

1. Install the Package

git clone https://github.com/lexe-app/lexe-wrapper.git
cd lexe-wrapper
pip install -e .

2. Get Your Lexe Credentials

You need a Lexe wallet and client credentials. Follow the Lexe SDK documentation to:

  1. Download the Lexe mobile app
  2. Create a wallet
  3. Export client credentials (base64 encoded string)

3. Set Environment Variable

export LEXE_CLIENT_CREDENTIALS="your_base64_encoded_credentials_here"

4. Start Building

Simple Usage (Context Manager)

from lexe_wrapper import LexeManager
import requests

# Automatic setup and cleanup
with LexeManager() as lexe:
    lexe.start_sidecar()  # Downloads binary, starts process, health checks
    
    # Now use the standard Lexe Sidecar API directly at localhost:5393
    response = requests.post("http://localhost:5393/v1/node/create_invoice", json={
        "amount": "1000", 
        "description": "Test payment"
    })
    invoice = response.json()
    print(f"Created invoice: {invoice['invoice']}")
    
    # Sidecar automatically stops when exiting the context

Web App Integration

from lexe_wrapper import LexeManager

# Initialize once when your web app starts
lexe = LexeManager()
lexe.start_for_webapp()  # Robust startup with error handling

# Use throughout your app's lifetime
@app.route('/create-invoice', methods=['POST'])
def create_invoice():
    response = requests.post("http://localhost:5393/v1/node/create_invoice", 
                           json=request.json)
    return response.json()

# Stop when app shuts down
lexe.stop_sidecar()

Manual Management

from lexe_wrapper import LexeManager

lexe = LexeManager()

try:
    lexe.start_sidecar()
    
    if lexe.check_health():
        print("Lexe is ready!")
        
        # Get node info using the wrapper method
        node_info = lexe.get_node_info()
        print(f"Balance: {node_info['balance']} sats")
        
finally:
    lexe.stop_sidecar()

For Coding Agents

When using this package in automated coding environments:

Essential Setup Steps

  1. Install package: Clone repo and pip install -e .
  2. Set credentials: export LEXE_CLIENT_CREDENTIALS="your_credentials"
  3. Import and start: Use the context manager pattern for automatic cleanup

Example Implementation

from lexe_wrapper import LexeManager
import requests

def setup_lexe_integration():
    """Initialize Lexe for your application"""
    lexe = LexeManager()
    lexe.start_sidecar()  # Downloads binary, starts process, waits for health
    return "http://localhost:5393"  # Ready to use Lexe API

def create_lightning_invoice(amount_sats, description):
    """Create a Lightning invoice using Lexe API"""
    response = requests.post("http://localhost:5393/v1/node/create_invoice", json={
        "amount": str(amount_sats),
        "description": description
    })
    return response.json()

# The package handles all the complexity - just use the API directly!

Key Benefits for Automation

  • Standard pip installation - pip install lexe-wrapper
  • Clean imports - from lexe_wrapper import LexeManager
  • Zero configuration files needed - everything is handled programmatically
  • Automatic binary management - downloads and extracts the right version
  • Built-in health checks - ensures the connection is ready before returning
  • Error handling - clear error messages when credentials are invalid or missing
  • Process lifecycle management - clean startup and shutdown

Installation Methods

Install from Source

Since this package is not yet published to PyPI, install directly from source:

git clone https://github.com/lexe-app/lexe-wrapper.git
cd lexe-wrapper
pip install -e .

Note: PyPI publishing coming soon for simple pip install lexe-wrapper experience.

API Reference

LexeManager Class

Constructor

from lexe_wrapper import LexeManager

LexeManager(client_credentials=None, port=5393)
  • client_credentials: Base64 encoded credentials (uses LEXE_CLIENT_CREDENTIALS env var if None)
  • port: Port for sidecar to listen on (default: 5393)

Methods

start_sidecar(wait_for_health=True, health_timeout=30)

  • Downloads binary if needed, starts process, optionally waits for health check
  • Returns: bool - True if started successfully

start_for_webapp(health_timeout=30)

  • Web app specific startup with robust error handling
  • Returns: bool - True if started successfully
  • Raises: RuntimeError if startup fails

stop_sidecar()

  • Gracefully stops the sidecar process
  • Returns: bool - True if stopped successfully

check_health()

  • Checks if sidecar is responding to health checks
  • Returns: bool - True if healthy

ensure_running()

  • Ensures sidecar is running and healthy (great for health check endpoints)
  • Returns: bool - True if running and healthy

restart_if_needed()

  • Restarts sidecar if not running or unhealthy
  • Returns: bool - True if now running and healthy

get_node_info()

  • Gets node information from Lexe API
  • Returns: dict - Node information including balance, channels, etc.

is_running()

  • Checks if the sidecar process is currently running
  • Returns: bool - True if running

CLI Reference

The package includes a command-line interface for testing and development:

# Using the installed package
python -m lexe_wrapper <command> [options]

# Or directly (if you cloned the repo)
python cli.py <command> [options]

Commands:
  start       Start the sidecar
  stop        Stop the sidecar  
  status      Show sidecar status
  health      Check sidecar health
  node-info   Get node information
  download    Download sidecar binary only

Options:
  --credentials TEXT    Override credentials from env var
  --port INTEGER       Port for sidecar (default: 5393)
  --timeout INTEGER    Health check timeout (default: 30)
  --no-wait           Don't wait for health check when starting
  --verbose           Enable verbose logging

Web App Integration (Long-Lived Connections)

The wrapper is specifically designed to support long-lived connections for web applications. Here's how to integrate it:

Flask Example

from flask import Flask, jsonify, request
from lexe_manager import LexeManager
import requests
import atexit

app = Flask(__name__)

# Global Lexe manager instance
lexe_manager = None

def init_lexe():
    """Initialize Lexe sidecar when app starts"""
    global lexe_manager
    lexe_manager = LexeManager()
    
    try:
        # Use the web app specific startup method
        lexe_manager.start_for_webapp(health_timeout=30)
        print("✅ Lexe sidecar started successfully")
        return True
    except RuntimeError as e:
        print(f"❌ Failed to start Lexe: {e}")
        return False

def cleanup_lexe():
    """Clean shutdown when app stops"""
    global lexe_manager
    if lexe_manager:
        lexe_manager.stop_sidecar()
        print("🛑 Lexe sidecar stopped")

# Initialize Lexe when app starts
with app.app_context():
    if not init_lexe():
        exit(1)

# Register cleanup function
atexit.register(cleanup_lexe)

@app.route('/health')
def health_check():
    """App health check - includes Lexe status"""
    if lexe_manager and lexe_manager.ensure_running():
        return jsonify({"status": "healthy", "lexe": "connected"})
    else:
        return jsonify({"status": "degraded", "lexe": "disconnected"}), 503

@app.route('/node-info')
def node_info():
    """Get Lexe node information"""
    try:
        # Use direct API call (the whole point of this wrapper!)
        response = requests.get("http://localhost:5393/v1/node/node_info", timeout=10)
        response.raise_for_status()
        return jsonify(response.json())
    except Exception as e:
        return jsonify({"error": str(e)}), 500

@app.route('/create-invoice', methods=['POST'])
def create_invoice():
    """Create a Lightning invoice"""
    try:
        amount = request.json.get('amount', '1000')
        description = request.json.get('description', 'Payment')
        
        # Direct Lexe API usage
        response = requests.post("http://localhost:5393/v1/node/create_invoice", 
                               json={
                                   "amount": str(amount),
                                   "description": description
                               }, timeout=15)
        response.raise_for_status()
        return jsonify(response.json())
    except Exception as e:
        return jsonify({"error": str(e)}), 500

@app.route('/restart-lexe', methods=['POST'])
def restart_lexe():
    """Restart Lexe if having issues"""
    if lexe_manager and lexe_manager.restart_if_needed():
        return jsonify({"status": "restarted"})
    else:
        return jsonify({"error": "restart failed"}), 500

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

FastAPI Example

from fastapi import FastAPI, HTTPException
from contextlib import asynccontextmanager
from lexe_manager import LexeManager
import requests

# Global Lexe manager
lexe_manager = None

@asynccontextmanager
async def lifespan(app: FastAPI):
    # Startup
    global lexe_manager
    lexe_manager = LexeManager()
    
    try:
        lexe_manager.start_for_webapp()
        print("✅ Lexe sidecar started")
        yield
    except RuntimeError as e:
        print(f"❌ Lexe startup failed: {e}")
        raise
    finally:
        # Shutdown
        if lexe_manager:
            lexe_manager.stop_sidecar()
            print("🛑 Lexe sidecar stopped")

app = FastAPI(lifespan=lifespan)

@app.get("/health")
def health_check():
    if lexe_manager and lexe_manager.ensure_running():
        return {"status": "healthy", "lexe": "connected"}
    raise HTTPException(503, "Lexe not available")

@app.post("/invoices")
def create_invoice(amount: int, description: str = "Payment"):
    try:
        response = requests.post("http://localhost:5393/v1/node/create_invoice",
                               json={"amount": str(amount), "description": description})
        response.raise_for_status()
        return response.json()
    except Exception as e:
        raise HTTPException(500, str(e))

Web App Best Practices

  1. Startup Pattern: Use start_for_webapp() during app initialization
  2. Health Monitoring: Use ensure_running() in your health check endpoints
  3. Recovery: Use restart_if_needed() for automatic recovery
  4. Shutdown: Ensure stop_sidecar() is called when your app shuts down
  5. Direct API Usage: Once started, use standard HTTP requests to localhost:5393

Process Management for Production

import signal
import sys
from lexe_manager import LexeManager

# Global manager for signal handlers
lexe_manager = None

def signal_handler(signum, frame):
    """Handle shutdown signals gracefully"""
    global lexe_manager
    print("🔄 Received shutdown signal, stopping Lexe...")
    if lexe_manager:
        lexe_manager.stop_sidecar()
    sys.exit(0)

# Register signal handlers for graceful shutdown
signal.signal(signal.SIGINT, signal_handler)   # Ctrl+C
signal.signal(signal.SIGTERM, signal_handler)  # Docker/systemd stop

def main():
    global lexe_manager
    lexe_manager = LexeManager()
    
    # Start for long-lived operation
    lexe_manager.start_for_webapp()
    
    # Your web app code here
    # The sidecar stays running until explicitly stopped

After Starting the Sidecar

Once the wrapper starts the sidecar, you can use the standard Lexe Sidecar API directly:

  • Health: GET http://localhost:5393/v1/health
  • Node Info: GET http://localhost:5393/v1/node/node_info
  • Create Invoice: POST http://localhost:5393/v1/node/create_invoice
  • Pay Invoice: POST http://localhost:5393/v1/node/pay_invoice
  • Check Payment: GET http://localhost:5393/v1/node/payment?index=<index>

Error Handling

The wrapper provides clear error messages for common issues:

  • Missing credentials: Clear message about setting LEXE_CLIENT_CREDENTIALS
  • Invalid credentials: Validates base64 format and provides specific error
  • Download failures: Network issues when downloading the binary
  • Health check failures: When sidecar doesn't respond within timeout
  • Process management: Issues starting or stopping the sidecar process

Package Structure

lexe-wrapper/
├── lexe_wrapper/           # Main package
│   ├── __init__.py        # Package exports LexeManager
│   ├── manager.py         # Core LexeManager class
│   └── __main__.py        # CLI entry point
├── examples/              # Usage examples
│   └── simple_usage.py    # Simple integration examples
├── setup.py              # Package installation
├── pyproject.toml        # Modern Python packaging
└── README.md             # This documentation

Requirements

  • Python 3.7+
  • requests library (automatically installed as dependency)
  • x86_64 Linux environment (where Lexe sidecar runs)
  • Valid Lexe client credentials

Contributing

Contributions are welcome! This package follows standard Python packaging conventions:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests if applicable
  5. Submit a pull request

License

MIT License - see LICENSE file for details.

About

This package is designed to eliminate the friction in getting started with Lexe Bitcoin Lightning Network integration. The Lexe Sidecar API itself is excellent - this package just handles the setup complexity so you can focus on building great Lightning applications.

Key Design Principles:

  • Standard Python packaging - Install with pip, import normally
  • Minimal dependencies - Only requires requests
  • Clean API surface - Simple import, clear methods
  • Production ready - Proper error handling, logging, and lifecycle management
  • Direct API access - No unnecessary abstraction over the Lexe Sidecar API

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lexe_wrapper-1.0.0.tar.gz (17.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lexe_wrapper-1.0.0-py3-none-any.whl (11.7 kB view details)

Uploaded Python 3

File details

Details for the file lexe_wrapper-1.0.0.tar.gz.

File metadata

  • Download URL: lexe_wrapper-1.0.0.tar.gz
  • Upload date:
  • Size: 17.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for lexe_wrapper-1.0.0.tar.gz
Algorithm Hash digest
SHA256 407d5eb63ff0a25db6c5a82f6b03c663da312f4ebb35703085ce0f320f93adaf
MD5 55fde1e07f869f9e88c4ef5cdca5c046
BLAKE2b-256 e45a82007d5046ab86f74142048b5d16b75250659bbdf5b5df8d49f424e95ced

See more details on using hashes here.

File details

Details for the file lexe_wrapper-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: lexe_wrapper-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 11.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for lexe_wrapper-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b043068f715ef23d61e2a2868cca8ce4f4d5c88be135367d88d3682eef8663d7
MD5 4c593e68f1a401257d3ae3245c8107d2
BLAKE2b-256 21fe82332f600ec6f4148934add93cfbfa96c89640ff4510e26071b56f4dfaee

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page