Lightning toolkit for AI agents. Payments, auth, escrow, and streaming micropayments.
npm install lightning-agentSettle this transaction without a platform.
You can't transact without a payment rail. lightning-agent is the rail — payments, auth, escrow, and streaming micropayments over Nostr Wallet Connect (NWC). No browser, no UI, no bank accounts, no Stripe. Connect to any NWC-compatible wallet (Alby Hub, Mutiny, etc.) and two agents can exchange value directly.
Part of the constraint chain: agent-discovery (find) → ai-wot (verify) → lightning-agent (pay) → lightning-toll (gate).
``bash`
npm install lightning-agent
| Module | What it does | Since |
|--------|-------------|-------|
| Wallet | Send/receive Lightning payments, decode invoices | v0.1.0 |
| Auth | LNURL-auth — login with your Lightning wallet | v0.3.0 |
| Escrow | Hold funds until work is verified, then release or refund | v0.3.0 |
| Stream | Pay-per-token streaming micropayments | v0.3.0 |
---
`javascript
const { createWallet } = require('lightning-agent');
const wallet = createWallet('nostr+walletconnect://...');
// Check balance
const { balanceSats } = await wallet.getBalance();
// Create an invoice (get paid)
const { invoice, paymentHash } = await wallet.createInvoice({
amountSats: 50,
description: 'Text generation query'
});
// Wait for payment
const { paid } = await wallet.waitForPayment(paymentHash);
// Pay an invoice
const { preimage } = await wallet.payInvoice(someInvoice);
// Pay a Lightning address directly
await wallet.payAddress('alice@getalby.com', { amountSats: 10 });
wallet.close();
`
---
Pay multiple invoices or addresses in parallel with concurrency control:
`javascript
const wallet = createWallet('nostr+walletconnect://...');
// Pay multiple invoices at once
const { results, successCount, totalSats } = await wallet.payBatch([
'lnbc100n1...',
'lnbc200n1...',
'lnbc300n1...'
], {
concurrency: 3, // Max parallel payments
stopOnError: false // Continue even if one fails
});
console.log(Paid ${successCount} invoices, total ${totalSats} sats);
// Pay multiple Lightning addresses
const { results: addrResults } = await wallet.payAddresses([
{ address: 'alice@getalby.com', amountSats: 50, comment: 'Thanks!' },
{ address: 'bob@walletofsatoshi.com', amountSats: 100 },
{ address: 'carol@strike.me', amountSats: 75 }
], { concurrency: 2 });
// Check individual results
for (const r of results) {
if (r.success) {
console.log(✓ Paid ${r.amountSats} sats, preimage: ${r.preimage});✗ Failed: ${r.error}
} else {
console.log();`
}
}
---
Login with a Lightning wallet. No passwords, no OAuth — just a signed cryptographic challenge.
`javascript
const { createAuthServer, signAuth } = require('lightning-agent');
const auth = createAuthServer({
callbackUrl: 'https://api.example.com/auth',
challengeTtlMs: 300000 // 5 minutes
});
// Generate a challenge
const { k1, lnurl } = auth.createChallenge();
// → lnurl can be rendered as QR for wallet apps
// → k1 can be sent directly to agent clients
// Verify a signed response
const result = auth.verify(k1, sig, key);
// → { valid: true, pubkey: '03abc...' }
// Or use as Express middleware
app.get('/auth', auth.middleware((pubkey, req, res) => {
console.log('Authenticated:', pubkey);
}));
`
`javascript
const { signAuth, authenticate } = require('lightning-agent');
// Sign a challenge manually
const { sig, key } = signAuth(k1, myPrivateKeyHex);
// → Send sig + key back to server
// Or complete the full flow automatically
const result = await authenticate('lnurl1...', myPrivateKeyHex);
if (result.success) console.log('Logged in as', result.pubkey);
`
#### createAuthServer(opts?)opts.challengeTtlMs
- — Challenge validity in ms (default 300000)opts.callbackUrl
- — Full URL for LNURL generation
Returns: { createChallenge(), verify(k1, sig, key), middleware(onAuth), activeChallenges }
#### signAuth(k1, privateKey){ sig, key }
Sign a challenge with a secp256k1 private key. Returns (DER signature + compressed pubkey).
#### authenticate(lnurlOrUrl, privateKey){ success, pubkey, error? }
Complete an LNURL-auth flow: fetch challenge → sign → submit. Returns .
---
Hold funds until work is verified. Client pays into escrow → worker delivers → escrow releases payment. If the worker doesn't deliver, funds are refunded.
`javascript
const { createWallet, createEscrowManager } = require('lightning-agent');
const escrowWallet = createWallet('nostr+walletconnect://...');
const mgr = createEscrowManager(escrowWallet, {
onStateChange: (id, from, to) => console.log(${id}: ${from} → ${to})
});
// 1. Create escrow
const escrow = await mgr.create({
amountSats: 500,
workerAddress: 'worker@getalby.com',
description: 'Translate 200 words EN→ES',
deadlineMs: 3600000 // 1 hour
});
console.log('Client should pay:', escrow.invoice);
// 2. Confirm funding (waits for payment)
await mgr.fund(escrow.id);
// 3. Worker delivers proof
mgr.deliver(escrow.id, { url: 'https://example.com/result', hash: 'sha256...' });
// 4a. Release to worker
await mgr.release(escrow.id);
// 4b. Or refund to client
await mgr.refund(escrow.id, 'client@getalby.com', 'Worker no-show');
// 4c. Or dispute
mgr.dispute(escrow.id, 'Quality insufficient', 'client');
`
``
CREATED → FUNDED → DELIVERED → RELEASED
→ REFUNDED
→ EXPIRED (auto, on deadline)
→ DISPUTED
#### createEscrowManager(wallet, opts?)wallet
- — NWC wallet that holds escrowed fundsopts.onStateChange(id, oldState, newState, escrow)
- — State change callbackopts.defaultDeadlineMs
- — Default deadline (default 3600000)
Returns: { create(config), fund(id, opts?), deliver(id, proof), release(id), refund(id, address, reason?), dispute(id, reason, raisedBy), get(id), list(state?), close() }
#### EscrowStateCREATED
Enum: , FUNDED, DELIVERED, RELEASED, REFUNDED, EXPIRED, DISPUTED
---
Pay-per-token micropayments. Lightning is the only payment system that can handle fractions-of-a-cent per word.
`javascript
const { createWallet, createStreamProvider } = require('lightning-agent');
const http = require('http');
const wallet = createWallet('nostr+walletconnect://...');
const provider = createStreamProvider(wallet, {
satsPerBatch: 2, // charge 2 sats per batch
tokensPerBatch: 100, // 100 tokens per batch
maxBatches: 50 // cap at 50 batches (100 sats max)
});
http.createServer(async (req, res) => {
await provider.handleRequest(req, res, async function* () {
// Your generator yields tokens/strings
for (const word of myTextGenerator(req)) {
yield word + ' ';
}
}, { firstBatchFree: true });
}).listen(8080);
`
`javascript
const { createWallet, createStreamClient } = require('lightning-agent');
const wallet = createWallet('nostr+walletconnect://...');
const client = createStreamClient(wallet, { maxSats: 200 });
for await (const text of client.stream('https://api.example.com/generate', {
body: { prompt: 'Explain Lightning Network in 500 words' },
maxSats: 100 // budget for this stream
})) {
process.stdout.write(text);
}
`
The provider uses Server-Sent Events:
``
event: session data: { "sessionId": "abc..." }
event: content data: { "tokens": "Hello world...", "batchIndex": 1 }
event: invoice data: { "invoice": "lnbc...", "sats": 2, "batchIndex": 2 }
event: content data: { "tokens": "more text...", "batchIndex": 2 }
event: done data: { "totalBatches": 5, "totalSats": 8, "totalTokens": 500 }
Client proves payment by POSTing { sessionId, preimage } to the same URL.
#### createStreamProvider(wallet, opts?)opts.satsPerBatch
- — Sats per batch (default 1)opts.tokensPerBatch
- — Tokens per batch (default 50)opts.maxBatches
- — Max batches per stream (default 100)opts.paymentTimeoutMs
- — Payment wait timeout (default 30000)
Returns: { handleRequest(req, res, generator, opts?), activeSessions }
#### createStreamClient(wallet, opts?)opts.maxSats
- — Budget cap (default 1000)opts.autoPay
- — Auto-pay invoices (default true)
Returns: { stream(url, opts?), budget }
---
env var.$3
$3
$3
$3
$3
$3
$3
$3
- resolveLightningAddress(address, amountSats, comment?) — Resolve without paying
- decodeBolt11(invoice) — Offline bolt11 decoder
- parseNwcUrl(url) — Parse NWC URL into componentsCLI
`bash
export NWC_URL="nostr+walletconnect://..."lightning-agent balance
lightning-agent invoice 50 "API call fee"
lightning-agent pay lnbc50u1p...
lightning-agent decode lnbc50u1p...
lightning-agent wait [timeout_ms]
`Getting an NWC URL
You need a Nostr Wallet Connect URL from a compatible wallet:
- Alby Hub — Self-hosted Lightning node with NWC. Recommended.
- Mutiny Wallet — Mobile-first with NWC support.
- Coinos — Web wallet with NWC.
Design Philosophy
Built for AI agents, not humans:
- Minimal deps — just
nostr-tools and ws`MIT — Built by Jeletor