Lightning (Bitcoin) Payments for Agents
Set up a self-custodial Lightning Address (like alice@yourdomain.com) backed by your own wallet. Your agent handles the LNURL proxy, wallet API, and public exposure — you get a human-readable payment endpoint where every sat goes directly to your keys.
Core dependency: github.com/ACINQ/phoenixd — self-custodial Lightning node, single binary, zero config. Docs · Releases
Download
⬇ Download lightning-address.skill
Install with OpenClaw:
openclaw skill install lightning-address.skill
Or drop the file into your ~/.openclaw/skills/ directory.
What This Skill Does
A Lightning Address is a human-readable payment endpoint. When someone pays alice@example.com, their wallet resolves it via LNURL-pay (LUD-16) to create a fresh invoice from the recipient's wallet. No intermediary holds funds.
This skill walks your agent through the full setup:
- Wallet selection — phoenixd (recommended), Alby Hub, LND, or LNbits, with honest trade-offs
- LNURL proxy — bundled Python script that bridges Lightning Address requests to your wallet's invoice API
- Public exposure — Tailscale Funnel, Cloudflare Tunnel, or VPS reverse proxy
- DNS configuration — static well-known file on the domain
- End-to-end testing — curl verification + real wallet test
- Persistence — launchd (macOS) and systemd (Linux) service configs
How It Works
Sender wallet → GET example.com/.well-known/lnurlp/alice
↓
Static JSON (returns callback URL)
↓
Sender wallet → GET callback?amount=<msats>
↓
LNURL proxy → wallet createinvoice API
↓
Returns Lightning invoice (bolt11)
↓
Sender wallet pays → sats arrive in your wallet
Two components: a static file on the domain (the pointer) and a live LNURL proxy on your machine (the invoice generator). The domain owner and wallet owner can be different people.
Wallet Options
| Wallet | Self-Custody | Setup | Best For |
|---|---|---|---|
| Phoenixd ✅ | Yes (BIP39) | ~5 min | Agents, servers, automation |
| Alby Hub | Yes (LDK) | ~15 min | GUI users, Nostr/NWC |
| LND | Yes | Hours | Full control, routing |
| LNbits | Depends | ~20 min | Multi-user, hackathons |
Phoenixd trade-off: ACINQ is your sole channel partner — they see payment amounts and timing. Acceptable for a spending wallet; not for serious privacy. The only mitigation is running a full LND node with multiple channel partners.
When Someone Else Owns the Domain
You don't need to own the domain. You run the wallet and proxy on your machine; the domain owner adds one static file. That's it.
What You Do
- Install phoenixd and fund it
- Run the LNURL proxy
- Expose it publicly (Tailscale Funnel, etc.)
- Send the domain owner your callback URL
What to Send the Domain Owner
Add one file to your website at
.well-known/lnurlp/yournamewith this content:{ "callback": "https://YOUR-CALLBACK-URL/lnurlp/yourname/callback", "metadata": "[[\"text/identifier\",\"yourname@theirdomain.com\"],[\"text/plain\",\"Pay yourname\"]]", "tag": "payRequest", "minSendable": 1000, "maxSendable": 100000000 }Serve it over HTTPS as JSON. If on GitHub Pages, just commit the file.
The domain owner does not need to run any software, receive any credentials, or have access to your wallet. They can revoke the address by deleting the file — same trust model as email routing.
Step 1: Install Phoenixd
Download the latest release for your platform from github.com/ACINQ/phoenixd/releases.
# macOS arm64
wget https://github.com/ACINQ/phoenixd/releases/download/v0.7.3/phoenixd-0.7.3-macos-arm64.zip
unzip phoenixd-0.7.3-macos-arm64.zip
mv phoenixd phoenix-cli ~/.local/bin/
# Linux x86_64
wget https://github.com/ACINQ/phoenixd/releases/download/v0.7.3/phoenixd-0.7.3-linux-x64.zip
unzip phoenixd-0.7.3-linux-x64.zip
mv phoenixd phoenix-cli ~/.local/bin/
# First run — generates seed, creates config
phoenixd
# Type "I understand" when prompted about fee credit
⚠️ Critical: Back up ~/.phoenix/seed.dat immediately. This 12-word BIP39 phrase is your only recovery path. Store it encrypted, offline, separate from the machine running phoenixd.
Who Built Phoenixd
ACINQ — founded 2014, France. One of the three original Lightning Network implementations (alongside Lightning Labs and Blockstream). $10M funded. Their Lightning node (Eclair) has been running since 2017. Phoenix Wallet is one of the most respected self-custodial Lightning wallets on mobile. They co-authored the Lightning Protocol 1.0 specification.
Step 2: Understand the Costs
Phoenixd uses ACINQ as a Lightning Service Provider (LSP). When you receive your first payment large enough to cover fees, ACINQ opens a channel:
| Setting | Channel Capacity | Fee (1% + mining) | Approx USD |
|---|---|---|---|
| 2M sats (default) | ~$1,414 | ~20,137 sats | ~$14 |
| 5M sats | ~$3,535 | ~50,137 sats | ~$35 |
| 10M sats | ~$7,070 | ~100,137 sats | ~$71 |
Important details:
- The 1% fee is on the channel capacity, not your payment amount
- Payments smaller than the total fee go to fee credit (non-refundable, used toward future channel fees)
- After the channel is open, incoming payments have zero additional fee until capacity is consumed
- Sending fees are normal Lightning routing (1-10 sats typically)
- Configure with
--auto-liquidity=(off|2m|5m|10m)(requires restart)
Step 3: Phoenixd API Reference
All API calls use HTTP Basic Auth (empty username, password from ~/.phoenix/phoenix.conf).
# Check balance
curl -s http://localhost:9740/getbalance -u :$PASSWORD
# Get node info
curl -s http://localhost:9740/getinfo -u :$PASSWORD
# Create invoice (receive payment)
curl -s -X POST http://localhost:9740/createinvoice \
-u :$PASSWORD \
-d description='Coffee fund' \
-d amountSat=5000
# Pay invoice (send payment)
curl -s -X POST http://localhost:9740/payinvoice \
-u :$PASSWORD \
-d invoice=lnbc...
# List incoming payments
curl -s http://localhost:9740/payments/incoming -u :$PASSWORD
# List outgoing payments
curl -s http://localhost:9740/payments/outgoing -u :$PASSWORD
The API is fully documented at phoenix.acinq.co/server/api.
Step 4: LNURL Proxy (Full Implementation)
The LNURL proxy is a lightweight Python HTTP server that translates LNURL-pay callback requests into phoenixd invoice creation calls. Zero dependencies — stdlib only.
#!/usr/bin/env python3
"""LNURL-pay proxy for phoenixd. Zero dependencies."""
import http.server, json, urllib.request, urllib.parse, base64, os
PHOENIXD_URL = os.environ.get("PHOENIXD_URL", "http://localhost:9740")
PHOENIXD_PASS = os.environ.get("PHOENIXD_PASS", "") # limited API password
LN_ADDRESS = os.environ.get("LN_ADDRESS", "agent@yourdomain.com")
PORT = int(os.environ.get("PORT", "8089"))
class LNURLHandler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
path = self.path.split("?")[0]
params = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)
# Callback endpoint: wallet sends amount, we create invoice
if path.endswith("/callback") and "amount" in params:
amount_msat = int(params["amount"][0])
description = json.dumps([
["text/identifier", LN_ADDRESS],
["text/plain", f"Pay {LN_ADDRESS}"]
])
# Create invoice via phoenixd
auth = base64.b64encode(f":{PHOENIXD_PASS}".encode()).decode()
data = urllib.parse.urlencode({
"description": description,
"amountSat": amount_msat // 1000
}).encode()
req = urllib.request.Request(
f"{PHOENIXD_URL}/createinvoice",
data=data, method="POST",
headers={"Authorization": f"Basic {auth}"}
)
resp = json.loads(urllib.request.urlopen(req).read())
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Access-Control-Allow-Origin", "*")
self.end_headers()
self.wfile.write(json.dumps({
"pr": resp["serialized"],
"routes": []
}).encode())
else:
self.send_response(404)
self.end_headers()
def log_message(self, fmt, *args): pass # silence logs
if __name__ == "__main__":
server = http.server.HTTPServer(("0.0.0.0", PORT), LNURLHandler)
print(f"LNURL proxy on :{PORT} → {PHOENIXD_URL}")
server.serve_forever()
Run it:
PHOENIXD_PASS="your-limited-password" \
LN_ADDRESS="alice@yourdomain.com" \
python3 lnurl-proxy.py
Step 5: Expose Your Proxy Publicly
Your LNURL proxy needs a public HTTPS endpoint so sender wallets can reach it. Three options:
Option A: Tailscale Funnel (Recommended)
Free, stable URL that survives reboots. No account besides Tailscale.
# One-time setup
tailscale funnel --bg --set-path /ln http://127.0.0.1:8089
# Verify
tailscale serve status
# Your URL: https://your-machine.tail12345.ts.net/ln
Option B: Cloudflare Tunnel
Free tier available. Requires Cloudflare account and domain on Cloudflare DNS.
cloudflared tunnel --url http://localhost:8089
⚠️ Quick tunnels generate random domains that break on restart. Use named tunnels for persistence.
Option C: VPS Reverse Proxy
Run nginx/caddy on a VPS pointing to your home machine via WireGuard/Tailscale. Most control, most setup.
Step 6: DNS / Static File Configuration
Create the well-known file on your domain. For alice@example.com, the file goes at:
https://example.com/.well-known/lnurlp/alice
Contents:
{
"callback": "https://your-public-endpoint/lnurlp/alice/callback",
"metadata": "[[\"text/identifier\",\"alice@example.com\"],[\"text/plain\",\"Pay alice\"]]",
"tag": "payRequest",
"minSendable": 1000,
"maxSendable": 100000000
}
GitHub Pages: Commit the file to your repo at .well-known/lnurlp/alice (no extension). Add an empty .nojekyll file so GitHub serves dotfiles. Ensure the response Content-Type is application/json.
Verify:
curl -s https://example.com/.well-known/lnurlp/alice | python3 -m json.tool
Step 7: End-to-End Testing
# 1. Verify static file resolves
curl -s https://yourdomain.com/.well-known/lnurlp/alice
# 2. Test callback directly (1000 msats = 1 sat)
curl -s "https://your-public-endpoint/lnurlp/alice/callback?amount=1000"
# Should return: {"pr": "lnbc...", "routes": []}
# 3. Test with a real wallet
# Open Phoenix, Muun, Breez, or any LNURL-compatible wallet
# Enter: alice@yourdomain.com
# Send a small amount (100 sats)
# 4. Verify receipt
curl -s http://localhost:9740/payments/incoming -u :$PASSWORD | python3 -m json.tool
Deep Dive: All Wallet Options Compared
We evaluated every option in real-world testing. Here's what we found from primary source docs and hands-on experience:
Phoenixd (ACINQ) — Recommended for Agents
- Type: Self-custodial, single binary, zero config
- Cost to start: ~$14 one-time channel fee (1% of 2M sat channel + mining)
- Minimum viable payment: Need a single payment ≥ total channel fee to trigger channel creation. Smaller payments accumulate as non-refundable "fee credit"
- API: Simple HTTP REST (curl-friendly)
- Pros: Simplest self-custodial option, fully automated liquidity, battle-tested
- Cons: ACINQ is sole channel partner (privacy tradeoff), minimum channel 2M sats, no on-chain deposit path
- Gotcha: ACINQ's server can have transient "channel funding errors" (TxAbort during dual funding). We hit one that lasted ~12 hours and resolved on its own. GitHub issue #228
Alby Hub (LDK) — Best for Humans, Decent for Agents
- Type: Self-custodial, web UI + HTTP API + NWC (Nostr Wallet Connect)
- Cost to start: Depends on LSP:
- Megalith (Lightning): 1M sat minimum, ~$13 fee
- Megalith (on-chain): 150K sat minimum (~$106), ~$0.11 mining fee
- Olympus/Zeus (on-chain): 250K sat minimum (~$177)
- Pros: Multiple LSP choices, on-chain deposit option, nice web UI, Nostr-native
- Cons: Heavier than phoenixd, higher minimums for on-chain
- Useful as fallback when phoenixd's sole LSP has issues
Alby Account (Custodial) — Cheapest Quick-Start
- Type: Custodial (Alby holds the keys)
- Cost: Free. Zero minimum.
- Pros: Instant, no channel needed, works immediately via NWC
- Cons: Not self-custodial — you're trusting Alby with your funds
- Good for: Testing, tiny amounts, getting started before committing to self-custody
Zeus Wallet (Olympus LSP) — Mobile-First
- Type: Self-custodial, mobile app with embedded node
- Cost: 10,000 sat flat fee for channels up to 1M sats, 1% above
- Pros: 0-conf channels (instant), good mobile UX
- Cons: Mobile app — not designed for server/agent automation, no headless API
LND (Lightning Labs) — Full Sovereignty
- Type: Self-custodial, full routing node
- Cost: On-chain transaction fee to open channels (you choose partners)
- Pros: Maximum control, multiple channel partners (better privacy), can earn routing fees
- Cons: Complex setup, manual channel management, requires significant capital for useful liquidity
Our Decision Path (Real-World)
- Started with phoenixd (simplest self-custodial) → hit ACINQ server bug
- Explored Alby Hub as alternative → minimum on-chain deposits too expensive for testing ($106+)
- Set up Alby Account (custodial) as cheap stopgap → worked instantly, free
- Phoenixd resolved after ~12 hours → now primary wallet
- Alby Account remains available as custodial fallback
Lesson: Have a backup plan. Self-custodial Lightning depends on your LSP being operational. If your sole channel partner goes down, you need either a second node with a different LSP, or a custodial fallback for continuity.
Security Model
| Component | Access Level | Purpose |
|---|---|---|
| Full API password | Can send payments | Agent uses for purchases |
| Limited API password | Read + create invoices only | Dashboard, LNURL proxy |
| Seed phrase | Full fund recovery | Offline backup only |
Spending limits: Keep the wallet balance small ($20-100). This is a spending wallet, not savings. Fund it periodically in small amounts.
Trust tradeoffs:
- Self-custodial: you hold the keys, can force-close the channel anytime
- ACINQ is the sole channel partner: they can see payment amounts/timing (privacy limitation)
- For serious privacy needs, run a full LND/CLN node with multiple channel partners
- The LNURL proxy uses the limited API password — it can create invoices but cannot send payments
Persistent Services (Survive Reboots)
Both phoenixd and the LNURL proxy must run as system services. Without this, the Lightning Address breaks on reboot.
macOS (launchd)
Create ~/Library/LaunchAgents/ai.openclaw.lnurl-proxy.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>ai.openclaw.lnurl-proxy</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/python3</string>
<string>/path/to/lnurl-proxy.py</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>PHOENIXD_PASS</key>
<string>your-limited-password</string>
<key>LN_ADDRESS</key>
<string>alice@yourdomain.com</string>
</dict>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
<key>ThrottleInterval</key><integer>10</integer>
</dict>
</plist>
launchctl load ~/Library/LaunchAgents/ai.openclaw.lnurl-proxy.plist
Linux (systemd)
Create /etc/systemd/system/lnurl-proxy.service:
[Unit]
Description=LNURL-pay proxy for phoenixd
After=network.target
[Service]
ExecStart=/usr/bin/python3 /path/to/lnurl-proxy.py
Environment=PHOENIXD_PASS=your-limited-password
Environment=LN_ADDRESS=alice@yourdomain.com
Restart=always
RestartSec=10
User=your-user
[Install]
WantedBy=multi-user.target
sudo systemctl enable --now lnurl-proxy
Key settings: KeepAlive / Restart=always ensures the proxy restarts on crash. ThrottleInterval / RestartSec prevents crash loops. Without persistence, the Lightning Address returns empty responses, causing lnurlError: EOF while parsing in sender wallets.
Agent Spending Workflows
Once your agent has a funded Lightning wallet, here's what it can do:
- Bitrefill purchases: Convert Lightning to gift cards (Amazon, Visa, etc.) for any online store
- L402 API access: Pay-per-request APIs gated by Lightning invoices
- Direct Lightning payments: Pay any Lightning invoice (freelancers, services, donations)
- Nostr zaps (NIP-57): Tip content creators on Nostr with Lightning
- Peddler (Nostr commerce): Accept payments for physical or digital goods
Approval gates: For agent spending, always implement a human approval step before paying any invoice. Screenshot the order summary, show it to the human, wait for explicit approval. Never let an agent pay invoices autonomously without a review gate — one wrong API call can send real money.
What's in the Skill Package
lightning-address/
├── SKILL.md # Core setup instructions
├── scripts/
│ └── lnurl-proxy.py # Parameterized LNURL proxy server
└── references/
├── wallet-options.md # Full wallet comparison
└── exposure-methods.md # Tailscale, Cloudflare, VPS options
Requirements
- OpenClaw — any recent version
- Python 3 — for the LNURL proxy (zero dependencies, stdlib only)
- Phoenixd — download from GitHub (or alternative wallet)
- Public HTTPS endpoint — Tailscale Funnel (free), Cloudflare Tunnel (free), or VPS
- Domain with static file hosting — GitHub Pages, Cloudflare Pages, or any web server
- ~$14 in Bitcoin — for the initial channel fee (or free if using custodial Alby to start)
Freedom Tech Perspective
Lightning Addresses are the bridge between human-readable identity and self-custodial payments. The key insight: the address format looks like email, but the payment flow is peer-to-peer.
- Self-custodial by design — your wallet, your keys. The domain only hosts a pointer.
- No KYC, no signup — phoenixd generates a BIP39 seed locally. No account creation anywhere.
- Runs locally — wallet + proxy on your machine. The only external dependency is the Lightning Network itself.
- Agent-native — HTTP API means your AI agent can create invoices, check balances, and manage the wallet programmatically.
- Composable — Lightning Address is one piece. Combine with Nostr (NIP-57 zaps), Peddler (commerce), or any LNURL-compatible service.
Every Lightning Address that runs on someone's own infrastructure is one fewer person relying on custodial services. Scale that and you have a payment network that governments can't easily shut down — not because it's hidden, but because it's everywhere.