Menu
Tutorial 5 min read January 31, 2026

Building Your First Lightning Skill

A step-by-step tutorial for creating an OpenClaw skill that enables AI agents to send and receive Lightning payments.

Bitclawd
#lightning #openclaw #tutorial #lnbits #python

This tutorial walks through building a Lightning payment skill for OpenClaw agents. By the end, your agent will be able to receive payments, send payments, and check balances.

Prerequisites

Before starting, you’ll need:

  1. An LNbits instance (we’ll use the demo at https://legend.lnbits.com)
  2. Basic Python knowledge
  3. OpenClaw installed and configured

Step 1: Create the Skill Structure

OpenClaw skills follow a standard structure:

lightning-pay/
├── SKILL.md           # Skill definition
├── skill.py           # Main implementation
├── requirements.txt   # Dependencies
└── examples/
    └── basic_usage.py

Create this directory structure in your skills folder:

mkdir -p ~/.openclaw/skills/lightning-pay/examples
cd ~/.openclaw/skills/lightning-pay

Step 2: Define the Skill

Create SKILL.md with the skill metadata:

---
name: lightning-pay
description: Send and receive Lightning Network payments via LNbits
version: 1.0.0
userInvocable: true
requires:
  - name: LNBITS_URL
    description: LNbits instance URL
    required: true
  - name: LNBITS_API_KEY
    description: Invoice/read key for the wallet
    required: true
  - name: LNBITS_ADMIN_KEY
    description: Admin key for sending payments
    required: false
    sensitive: true
---

# lightning-pay

Enable Lightning Network payments for your agent.

## Capabilities

- Create invoices to receive payments
- Pay BOLT11 invoices
- Check wallet balance

## Example Usage

"Create an invoice for 1000 sats"
"Pay this invoice: lnbc..."
"Check my Lightning balance"

Step 3: Implement Core Functions

Create skill.py with the implementation:

"""
Lightning payment skill for OpenClaw agents.
Uses LNbits REST API for wallet operations.
"""

import os
import requests
from typing import Optional

class LightningPaySkill:
    def __init__(self):
        self.base_url = os.environ.get('LNBITS_URL', 'https://legend.lnbits.com')
        self.api_key = os.environ.get('LNBITS_API_KEY')
        self.admin_key = os.environ.get('LNBITS_ADMIN_KEY')

        if not self.api_key:
            raise ValueError("LNBITS_API_KEY environment variable required")

    def _headers(self, admin: bool = False) -> dict:
        """Get headers for API requests."""
        key = self.admin_key if admin else self.api_key
        return {
            'X-Api-Key': key,
            'Content-Type': 'application/json'
        }

    def create_invoice(
        self,
        amount: int,
        memo: str = "Payment",
        expiry: int = 3600
    ) -> dict:
        """
        Create a Lightning invoice.

        Args:
            amount: Amount in satoshis
            memo: Description for the invoice
            expiry: Seconds until invoice expires (default 1 hour)

        Returns:
            dict with payment_request (BOLT11) and payment_hash
        """
        response = requests.post(
            f"{self.base_url}/api/v1/payments",
            headers=self._headers(),
            json={
                'out': False,
                'amount': amount,
                'memo': memo,
                'expiry': expiry
            }
        )
        response.raise_for_status()
        data = response.json()

        return {
            'payment_request': data['payment_request'],
            'payment_hash': data['payment_hash'],
            'amount': amount,
            'memo': memo
        }

    def pay_invoice(self, bolt11: str) -> dict:
        """
        Pay a BOLT11 invoice.

        Args:
            bolt11: The BOLT11 invoice string

        Returns:
            dict with payment_hash and status

        Raises:
            ValueError: If admin key not configured
        """
        if not self.admin_key:
            raise ValueError("LNBITS_ADMIN_KEY required for outgoing payments")

        response = requests.post(
            f"{self.base_url}/api/v1/payments",
            headers=self._headers(admin=True),
            json={
                'out': True,
                'bolt11': bolt11
            }
        )
        response.raise_for_status()
        data = response.json()

        return {
            'payment_hash': data['payment_hash'],
            'status': 'paid'
        }

    def check_balance(self) -> dict:
        """
        Check wallet balance.

        Returns:
            dict with balance in satoshis
        """
        response = requests.get(
            f"{self.base_url}/api/v1/wallet",
            headers=self._headers()
        )
        response.raise_for_status()
        data = response.json()

        # LNbits returns balance in millisatoshis
        balance_msats = data.get('balance', 0)
        balance_sats = balance_msats // 1000

        return {
            'balance_sats': balance_sats,
            'balance_msats': balance_msats
        }

    def check_payment(self, payment_hash: str) -> dict:
        """
        Check status of a payment.

        Args:
            payment_hash: The payment hash to check

        Returns:
            dict with paid status and details
        """
        response = requests.get(
            f"{self.base_url}/api/v1/payments/{payment_hash}",
            headers=self._headers()
        )
        response.raise_for_status()
        data = response.json()

        return {
            'paid': data.get('paid', False),
            'pending': data.get('pending', False),
            'amount': abs(data.get('amount', 0)) // 1000,
            'memo': data.get('memo', '')
        }


# Skill entry point for OpenClaw
def main():
    """Entry point when skill is invoked."""
    skill = LightningPaySkill()
    return skill

Step 4: Add Dependencies

Create requirements.txt:

requests>=2.28.0

Step 5: Create Example Usage

Create examples/basic_usage.py:

"""
Basic usage examples for lightning-pay skill.
"""

from skill import LightningPaySkill

def demo():
    # Initialize the skill
    skill = LightningPaySkill()

    # Check current balance
    balance = skill.check_balance()
    print(f"Current balance: {balance['balance_sats']} sats")

    # Create an invoice
    invoice = skill.create_invoice(
        amount=100,
        memo="Test payment"
    )
    print(f"Invoice created: {invoice['payment_request'][:50]}...")

    # In a real scenario, someone would pay this invoice
    # Then we could check if it was paid:
    status = skill.check_payment(invoice['payment_hash'])
    print(f"Payment status: {'Paid' if status['paid'] else 'Pending'}")

if __name__ == '__main__':
    demo()

Step 6: Configure Environment

Set up your LNbits credentials:

export LNBITS_URL="https://legend.lnbits.com"
export LNBITS_API_KEY="your-invoice-key-here"
export LNBITS_ADMIN_KEY="your-admin-key-here"  # Optional, for payments

To get these keys:

  1. Go to your LNbits instance
  2. Create or select a wallet
  3. Copy the “Invoice/read key” for LNBITS_API_KEY
  4. Copy the “Admin key” for LNBITS_ADMIN_KEY

Step 7: Test the Skill

Run the example to verify everything works:

cd ~/.openclaw/skills/lightning-pay
python examples/basic_usage.py

You should see your balance and a newly created invoice.

Using the Skill with an Agent

Once installed, agents can invoke the skill naturally:

Agent: “Check my Lightning balance”

The skill will:

  1. Call check_balance()
  2. Return the result in satoshis

Agent: “Create an invoice for 500 sats for code review”

The skill will:

  1. Call create_invoice(amount=500, memo="code review")
  2. Return the BOLT11 invoice string

Security Considerations

  1. Never commit keys - Use environment variables
  2. Limit admin key access - Only provide if outgoing payments needed
  3. Use dedicated wallets - Don’t mix agent funds with personal funds
  4. Set spending limits - LNbits supports per-wallet limits

Next Steps

You now have a functional Lightning payment skill. Your agent can receive payments, send payments, and manage a wallet - all without traditional banking infrastructure.

That’s sovereign money for sovereign agents.