Bitcoin Lightning wallet for agents — balances, invoices, payments, BTC/USD swaps, QR codes, price conversion, and transaction history via the Blink API. All output is JSON.
Bitcoin Lightning wallet operations via the Blink API. Enables agents to check balances, receive payments via invoices, send payments over Lightning, swap between BTC and USD wallets, track transactions, and monitor prices.
Blink is a custodial Bitcoin Lightning wallet with a GraphQL API. Key concepts:
blink_...) with scoped permissions (Read, Receive, Write)lnbc...) used to receive paymentsuser@domain) for sending payments without an invoicebash and Node.js 18+.BLINK_API_KEY environment variable with appropriate scopes.--experimental-websocket.node:util, node:fs, node:path, node:child_process).Use this skill for concrete wallet operations, not generic Lightning theory.
export BLINK_API_KEY="blink_..."
API Key Scopes:
Tip: Start with Read + Receive only. Add Write when you need to send payments.
node {baseDir}/scripts/balance.js
If you see JSON with your wallet balances, you're ready.
To use the Blink staging environment (signet) instead of real money:
export BLINK_API_URL="https://api.staging.blink.sv/graphql"
Create a staging API key at dashboard.staging.blink.sv. The staging environment uses signet bitcoin (no real value) — perfect for testing payment flows safely.
If BLINK_API_URL is not set, production (https://api.blink.sv/graphql) is used by default.
Scripts automatically resolve BLINK_API_KEY using this order:
process.env.BLINK_API_KEY (checked first)~/.profile, ~/.bashrc, ~/.bash_profile, ~/.zshrc — scanned for an export BLINK_API_KEY=... line onlyNo source ~/.profile prefix is needed. The rc file scan uses a targeted regex that reads only the BLINK_API_KEY export line — no other data is extracted from these files.
These rules are mandatory for any AI agent using this skill:
pay_invoice.js, pay_lnaddress.js, pay_lnurl.js, or swap_execute.js without explicit user confirmation of the amount and recipient.--dry-run before executing for real unless the user explicitly says to skip it.balance.js before any payment or swap to verify sufficient funds.fee_probe.js before pay_invoice.js to show the user the fee cost.BLINK_API_KEY as a secret. Do not echo it, include it in messages, or write it to files.BLINK_API_URL to the staging endpoint.btcBalanceUsdFormatted, usdBalanceFormatted).node {baseDir}/scripts/price.js <sats> or the btcBalanceUsd field from balance output instead.--unit flag controls interpretation: sats for BTC, cents for USD.BLINK_API_KEY with the correct scopes for your operation.BLINK_API_URL for staging/testnet.balance.js.fee_probe.js.--wallet flag.--dry-run to preview without sending. Use --max-amount to cap outgoing amounts.swap_quote.js to preview the conversion.swap_execute.js (use --dry-run first).--dry-run on payment and swap commands to preview before executing.--max-amount <sats> to enforce a per-payment ceiling (pay_lnaddress, pay_lnurl).--force to override balance-check failures when you know the payment should proceed.# Check balances
node {baseDir}/scripts/balance.js
# Create BTC invoice (auto-subscribes to payment)
node {baseDir}/scripts/create_invoice.js 1000 "Payment for service"
# Pay a Lightning invoice
node {baseDir}/scripts/pay_invoice.js lnbc1000n1...
# Pay from USD wallet
node {baseDir}/scripts/pay_invoice.js lnbc1000n1... --wallet USD
# Get current BTC/USD price
node {baseDir}/scripts/price.js
# Quote BTC -> USD internal swap (dry-run)
node {baseDir}/scripts/swap_quote.js btc-to-usd 5000
# Execute USD -> BTC internal swap
node {baseDir}/scripts/swap_execute.js usd-to-btc 500 --unit cents
node {baseDir}/scripts/balance.js
Returns JSON with all wallet balances (BTC in sats, USD in cents), wallet IDs, pending incoming amounts, and a pre-computed USD estimate for the BTC wallet. Use btcBalanceUsd for the BTC wallet's USD value — do not calculate it yourself.
node {baseDir}/scripts/create_invoice.js <amount_sats> [--timeout <seconds>] [--no-subscribe] [memo...]
Generates a BOLT-11 Lightning invoice for the specified amount in satoshis. Returns the paymentRequest string that can be paid by any Lightning wallet. The BTC wallet ID is resolved automatically.
Auto-subscribe: After creating the invoice, the script automatically opens a WebSocket subscription and waits for payment. It outputs two JSON objects to stdout:
{"event": "invoice_created", ...} with paymentRequest, paymentHash, etc.{"event": "subscription_result", "status": "PAID"|"EXPIRED"|"TIMEOUT", ...}The agent should read the first JSON to share the invoice/QR with the user right away, then wait for the second JSON to confirm payment.
amount_sats — amount in satoshis (required)--timeout <seconds> — subscription timeout (default: 300). Use 0 for no timeout.--no-subscribe — skip WebSocket auto-subscribe, just create the invoice and exitmemo... — optional description attached to the invoice (remaining args joined)node {baseDir}/scripts/create_invoice_usd.js <amount_cents> [--timeout <seconds>] [--no-subscribe] [memo...]
Creates a Lightning invoice denominated in USD cents. The sender pays in BTC/Lightning, but the received amount is locked to a USD value at the current exchange rate. Credited to the USD wallet. Expires in ~5 minutes due to exchange rate lock.
Auto-subscribe: Same two-phase output as create_invoice.js — first JSON is the created invoice, second JSON is the payment resolution (PAID/EXPIRED/TIMEOUT).
amount_cents — amount in USD cents, e.g. 100 = $1.00 (required)--timeout <seconds> — subscription timeout (default: 300). Use 0 for no timeout.--no-subscribe — skip WebSocket auto-subscribe, just create the invoice and exitmemo... — optional description attached to the invoice (remaining args joined)node {baseDir}/scripts/check_invoice.js <payment_hash>
Checks the payment status of a Lightning invoice by its payment hash. Use after creating an invoice to detect when it has been paid. Returns status: PAID, PENDING, or EXPIRED.
payment_hash — the 64-char hex payment hash from create_invoice.js output (required)node {baseDir}/scripts/pay_invoice.js <bolt11_invoice> [--wallet BTC|USD] [--dry-run] [--force]
Pays a BOLT-11 Lightning invoice from the BTC or USD wallet. Returns payment status: SUCCESS, PENDING, FAILURE, or ALREADY_PAID. The wallet ID is resolved automatically.
bolt11_invoice — the BOLT-11 payment request string, e.g. lnbc... (required)--wallet BTC|USD — wallet to pay from (default: BTC). When USD is selected, the Blink API debits the USD equivalent from the USD wallet.--dry-run — preview the payment without sending (returns wallet info and invoice details)--force — attempt payment even when the wallet balance appears insufficientRequires Write scope on the API key.
AGENT: This command spends funds. Always run
balance.jsandfee_probe.jsfirst, then confirm amount and recipient with the user before executing.
node {baseDir}/scripts/pay_lnaddress.js <lightning_address> <amount_sats> [--wallet BTC|USD] [--dry-run] [--force] [--max-amount <sats>]
Sends satoshis to a Lightning Address (e.g. [email protected]). Returns payment status. The wallet ID is resolved automatically.
lightning_address — recipient in user@domain format (required)amount_sats — amount in satoshis (required)--wallet BTC|USD — wallet to pay from (default: BTC). When USD is selected, the amount is still specified in satoshis; the Blink API debits the USD equivalent from the USD wallet automatically.--dry-run — preview the payment without sending (returns wallet info and amount details)--force — attempt payment even when the wallet balance appears insufficient--max-amount <sats> — reject the payment if the amount exceeds this ceiling (in satoshis)Requires Write scope on the API key.
AGENT: This command spends funds. Always run
balance.jsfirst, confirm the Lightning Address and amount with the user, then execute.
node {baseDir}/scripts/pay_lnurl.js <lnurl> <amount_sats> [--wallet BTC|USD] [--dry-run] [--force] [--max-amount <sats>]
Sends satoshis to a raw LNURL payRequest string. For Lightning Addresses (user@domain), use pay_lnaddress.js instead.
lnurl — LNURL string, e.g. lnurl1... (required)amount_sats — amount in satoshis (required)--wallet BTC|USD — wallet to pay from (default: BTC). When USD is selected, the amount is still specified in satoshis; the Blink API debits the USD equivalent from the USD wallet automatically.--dry-run — preview the payment without sending (returns wallet info and amount details)--force — attempt payment even when the wallet balance appears insufficient--max-amount <sats> — reject the payment if the amount exceeds this ceiling (in satoshis)Requires Write scope on the API key.
AGENT: This command spends funds. Always run
balance.jsfirst, confirm the LNURL and amount with the user, then execute.
node {baseDir}/scripts/fee_probe.js <bolt11_invoice> [--wallet BTC|USD]
Estimates the fee for paying a Lightning invoice without actually sending. Use before pay_invoice.js to check costs. Payments to other Blink users and direct-channel nodes are free (0 sats).
bolt11_invoice — the BOLT-11 payment request string (required)--wallet BTC|USD — wallet to probe from (default: BTC). When USD is selected, uses lnUsdInvoiceFeeProbe to estimate fees from the USD wallet's perspective.node {baseDir}/scripts/qr_invoice.js <bolt11_invoice>
Renders a terminal QR code for a Lightning invoice (BOLT-11) to stderr and generates a PNG image file to /tmp. The stdout JSON includes a pngPath field with the absolute path to the PNG file.
Sending the QR image to a user: After running this script, use the pngPath from the JSON output to send the PNG as a media attachment to the user in the current chat. The agent should use its native message-send capability with the file path.
bolt11_invoice — the BOLT-11 payment request string (required)Output JSON includes:
invoice — uppercased invoice stringqrRendered — always trueqrSize — QR module counterrorCorrection — "L" (LOW)pngPath — absolute path to the generated PNG file (e.g. /tmp/blink_qr_1234567890.png)pngBytes — file size in bytesnode {baseDir}/scripts/transactions.js [--first N] [--after CURSOR] [--wallet BTC|USD]
Lists recent transactions (incoming and outgoing) with pagination. Returns direction, amount, status, type (lightning/onchain/intraledger), and metadata.
--first N — number of transactions to return (default: 20, max: 100)--after CURSOR — pagination cursor from previous response's endCursor--wallet BTC|USD — filter to a specific wallet currencynode {baseDir}/scripts/price.js [amount_sats]
node {baseDir}/scripts/price.js --usd <amount_usd>
node {baseDir}/scripts/price.js --history <range>
node {baseDir}/scripts/price.js --currencies
Multi-purpose exchange rate tool. All price queries are public (no API key required), though the key is sent if available.
Modes:
<amount_sats> — convert a satoshi amount to USD (e.g. price.js 1760 → $1.20)--usd <amount> — convert a USD amount to sats (e.g. price.js --usd 5.00 → 7350 sats)--history <range> — historical BTC price data with summary stats (high/low/change). Ranges: ONE_DAY, ONE_WEEK, ONE_MONTH, ONE_YEAR, FIVE_YEARS--currencies — list all supported display currencies (IDs, names, symbols, flags)node {baseDir}/scripts/account_info.js
Shows account level, spending limits (withdrawal, internal send, convert), default wallet, and wallet summary with pre-computed USD estimates for BTC balances. Limits are denominated in USD cents with a rolling 24-hour window.
node {baseDir}/scripts/swap_quote.js <direction> <amount> [--unit sats|cents] [--ttl-seconds N] [--immediate]
Builds a deterministic quote-like receipt for internal wallet conversion.
direction — btc-to-usd or usd-to-btcamount — positive integer amount (unit inferred by direction unless --unit is set)--unit sats|cents — optional override for input unit--ttl-seconds N — quote validity window in seconds (default: 60)--immediate — mark intent for immediate execution mode in quote receiptUses Blink's conversion estimation path for pricing and records:
intraLedgerPaymentSend or intraLedgerUsdPaymentSend)node {baseDir}/scripts/swap_execute.js <direction> <amount> [--unit sats|cents] [--ttl-seconds N] [--immediate] [--dry-run] [--memo "text"]
Executes a wallet-native internal conversion between your BTC and USD wallets.
--dry-run — returns an execution receipt without performing the mutation--memo "text" — optional memo attached to the internal transferExecution receipts include quote terms, pre/post balances, balance deltas, and final status.
Fee/settlement interpretation:
quote.feeSats, quote.feeBps, and quote.slippageBps are currently returned as zero in live runs.quote.amountOut versus balanceDelta instead of relying only on explicit fee fields.For deeper behavior details and formulas, see swap-operations.
AGENT: This command moves funds between wallets. Always run with
--dry-runfirst, show the quote to the user, and get explicit confirmation before executing without--dry-run.
Blink supports GraphQL subscriptions over WebSocket using the graphql-transport-ws protocol. Node 20 requires the --experimental-websocket flag.
node --experimental-websocket {baseDir}/scripts/subscribe_invoice.js <bolt11_invoice> [--timeout <seconds>]
Watches a single invoice and exits when it is PAID or EXPIRED. Status updates are printed to stderr. JSON result is printed to stdout.
node --experimental-websocket {baseDir}/scripts/subscribe_updates.js [--timeout <seconds>] [--max <count>]
Streams account updates in real time. Each event is output as a JSON line (NDJSON) to stdout. Use --max to stop after N events.
| Operation | GraphQL | Scope Required |
|---|---|---|
| Check balance | query me + currencyConversionEstimation | Read |
| Create BTC invoice | mutation lnInvoiceCreate | Receive |
| Create USD invoice | mutation lnUsdInvoiceCreate | Receive |
| Check invoice | query invoiceByPaymentHash | Read |
| Pay invoice | mutation lnInvoicePaymentSend | Write |
| Pay LN address | mutation lnAddressPaymentSend | Write |
| Pay LNURL | mutation lnurlPaymentSend | Write |
| Fee estimate (BTC) | mutation lnInvoiceFeeProbe | Read |
| Fee estimate (USD) | mutation lnUsdInvoiceFeeProbe | Read |
| Transactions | query transactions | Read |
| Price / convert | query currencyConversionEstimation | None (public) |
| Price history | query btcPriceList | None (public) |
| Currency list | query currencyList | None (public) |
| Realtime price | query realtimePrice | None (public) |
| Account info | query me + currencyConversionEstimation | Read |
| Swap quote (BTC <-> USD) | query currencyConversionEstimation | Read |
| Swap execute BTC -> USD | mutation intraLedgerPaymentSend | Write |
| Swap execute USD -> BTC | mutation intraLedgerUsdPaymentSend | Write |
| Subscribe invoice | subscription lnInvoicePaymentStatus | Read |
| Subscribe updates | subscription myUpdates | Read |
API Endpoint: https://api.blink.sv/graphql (production)
Authentication: X-API-KEY header
USD wallet notes: The lnInvoicePaymentSend, lnAddressPaymentSend, and lnurlPaymentSend mutations all accept either a BTC or USD wallet ID. When a USD wallet ID is provided, the API debits the USD equivalent automatically. Amounts for lnAddressPaymentSend and lnurlPaymentSend are always specified in satoshis regardless of wallet type.
All scripts output structured JSON to stdout. Status messages and errors go to stderr. Exit code 0 on success, 1 on failure.
{
"wallets": [
{ "id": "abc123", "currency": "BTC", "balance": 1760, "unit": "sats" },
{ "id": "def456", "currency": "USD", "balance": 1500, "unit": "cents" }
],
"btcWalletId": "abc123",
"btcBalance": 1760,
"btcBalanceSats": 1760,
"btcBalanceUsd": 1.2,
"btcBalanceUsdFormatted": "$1.20",
"usdWalletId": "def456",
"usdBalance": 1500,
"usdBalanceCents": 1500,
"usdBalanceFormatted": "$15.00"
}
First JSON (immediate):
{
"event": "invoice_created",
"paymentRequest": "lnbc500n1...",
"paymentHash": "abc123...",
"satoshis": 500,
"status": "PENDING",
"createdAt": "2026-02-23T00:00:00Z",
"walletId": "abc123"
}
Second JSON (when payment resolves):
{
"event": "subscription_result",
"paymentRequest": "lnbc500n1...",
"status": "PAID",
"isPaid": true,
"isExpired": false,
"isPending": false
}
{
"paymentHash": "abc123...",
"paymentStatus": "PAID",
"satoshis": 500,
"isPaid": true,
"isExpired": false,
"isPending": false
}
{
"status": "SUCCESS",
"walletId": "abc123",
"walletCurrency": "BTC",
"balanceBefore": 50000
}
{
"status": "SUCCESS",
"walletId": "def456",
"walletCurrency": "USD",
"balanceBefore": 1500,
"balanceBeforeFormatted": "$15.00"
}
{
"btcPriceUsd": 68036.95,
"satsPerDollar": 1470,
"conversion": {
"sats": 1760,
"usd": 1.2,
"usdFormatted": "$1.20"
}
}
{
"btcPriceUsd": 68036.95,
"satsPerDollar": 1470,
"conversion": {
"usd": 5.0,
"usdFormatted": "$5.00",
"sats": 7350
}
}
{
"range": "ONE_DAY",
"dataPoints": 24,
"summary": {
"current": 68036.95,
"oldest": 67500.00,
"high": 68500.00,
"low": 67200.00,
"changeUsd": 536.95,
"changePct": 0.8
},
"prices": [
{ "timestamp": 1740000000, "date": "2025-02-20T00:00:00.000Z", "btcPriceUsd": 67500.00 }
]
}
{
"transactions": [
{
"id": "tx_123",
"direction": "RECEIVE",
"status": "SUCCESS",
"amount": 1000,
"currency": "BTC",
"type": "lightning",
"paymentHash": "abc...",
"createdAt": 1740000000
}
],
"count": 1,
"pageInfo": {
"hasNextPage": false,
"endCursor": "cursor_abc"
}
}
{
"event": "swap_quote",
"dryRun": true,
"direction": "BTC_TO_USD",
"preBalance": {
"btcWalletId": "btc_wallet_id",
"usdWalletId": "usd_wallet_id",
"btcBalanceSats": 250000,
"usdBalanceCents": 150000
},
"quote": {
"quoteId": "blink-swap-1740000000-424242",
"amountIn": { "value": 5000, "unit": "sats" },
"amountOut": { "value": 340, "unit": "cents" },
"expiresAtEpochSeconds": 1740000060,
"immediateExecution": false,
"executionPath": "blink:intraLedgerPaymentSend"
}
}
{
"event": "swap_execution",
"dryRun": false,
"direction": "USD_TO_BTC",
"status": "SUCCESS",
"succeeded": true,
"preBalance": {
"btcBalanceSats": 250000,
"usdBalanceCents": 150000
},
"postBalance": {
"btcBalanceSats": 253650,
"usdBalanceCents": 149500
},
"balanceDelta": {
"btcDeltaSats": 3650,
"usdDeltaCents": -500
},
"quote": {
"quoteId": "blink-swap-1740000015-556677",
"executionPath": "blink:intraLedgerUsdPaymentSend"
},
"execution": {
"path": "blink:intraLedgerUsdPaymentSend",
"transactionId": "tx_abc123"
}
}
# 1. Create invoice — script auto-subscribes and outputs two JSON objects
node {baseDir}/scripts/create_invoice.js 1000 "Payment for service"
# → First JSON: {"event": "invoice_created", "paymentRequest": "lnbc...", ...}
# → Read paymentRequest from first JSON immediately
# 2. Generate QR code PNG
node {baseDir}/scripts/qr_invoice.js <paymentRequest>
# → JSON includes "pngPath": "/tmp/blink_qr_123456.png"
# → Send the PNG file to the user as a media attachment in the current chat
# 3. The create_invoice.js script is still running, waiting for payment
# → Second JSON: {"event": "subscription_result", "status": "PAID", ...}
# → When PAID: notify the user that payment has been received
# → When EXPIRED: notify the user the invoice expired
Important: The create_invoice.js script outputs two JSON objects separated by a newline. Parse them as separate JSON objects, not as a single JSON array. The first object arrives immediately; the second arrives when payment status resolves.
# 1. Create invoice without auto-subscribe
node {baseDir}/scripts/create_invoice.js 1000 --no-subscribe "Payment for service"
# 2. Give the paymentRequest to the payer
# 3. Poll for payment
node {baseDir}/scripts/check_invoice.js <payment_hash>
# 4. Verify balance
node {baseDir}/scripts/balance.js
# Same two-phase pattern as BTC, but using create_invoice_usd.js
# Note: USD invoices expire in ~5 minutes
node {baseDir}/scripts/create_invoice_usd.js 500 "Five dollars for service"
# → First JSON: {"event": "invoice_created", "amountCents": 500, "amountUsd": "$5.00", ...}
# Generate QR and send to user, then wait for second JSON
# 1. Check current balance
node {baseDir}/scripts/balance.js
# 2. Estimate fee
node {baseDir}/scripts/fee_probe.js lnbc1000n1...
# 3. Send payment
node {baseDir}/scripts/pay_invoice.js lnbc1000n1...
# 4. Verify in transaction history
node {baseDir}/scripts/transactions.js --first 1
# Pay an invoice from the USD wallet
node {baseDir}/scripts/fee_probe.js lnbc1000n1... --wallet USD
node {baseDir}/scripts/pay_invoice.js lnbc1000n1... --wallet USD
# Send to a Lightning Address from the USD wallet
node {baseDir}/scripts/pay_lnaddress.js [email protected] 1000 --wallet USD
# Send via LNURL from the USD wallet
node {baseDir}/scripts/pay_lnurl.js lnurl1... 1000 --wallet USD
# Note: for lnaddress and lnurl, the amount is always in satoshis.
# The Blink API debits the USD equivalent from the USD wallet automatically.
# Check how much 1760 sats is worth in USD
node {baseDir}/scripts/price.js 1760
# → $1.20
# How many sats is $5.00?
node {baseDir}/scripts/price.js --usd 5.00
# → 7350 sats
# 1. Build quote and inspect terms
node {baseDir}/scripts/swap_quote.js btc-to-usd 10000
# 2. Execute the swap
node {baseDir}/scripts/swap_execute.js btc-to-usd 10000
# 1. Dry-run execution receipt without moving funds
node {baseDir}/scripts/swap_execute.js usd-to-btc 500 --unit cents --dry-run
# 2. Real execution
node {baseDir}/scripts/swap_execute.js usd-to-btc 500 --unit cents
# Get BTC price over the last 24 hours
node {baseDir}/scripts/price.js --history ONE_DAY
# Get BTC price over the last month
node {baseDir}/scripts/price.js --history ONE_MONTH
BLINK_API_KEY in chat messages or files.api.blink.sv (or BLINK_API_URL override) for all GraphQL queries and mutations.ws.blink.sv (or BLINK_WS_URL override) for subscription WebSockets.BLINK_API_KEY is not found in process.env, the client scans ~/.profile, ~/.bashrc, ~/.bash_profile, and ~/.zshrc for a line matching export BLINK_API_KEY=.... Only the value of that specific export is extracted — no other data is read from these files. The environment variable is always checked first.qr command writes temporary PNG files to /tmp/blink_qr_*.png. These are standard image files with no embedded metadata beyond the QR content.This skill stores no data between runs. There are no databases, config files, session tokens, or caches. Each script invocation is independent — it reads the API key, makes API calls, outputs JSON, and exits.
BLINK_API_URL=https://api.staging.blink.sv/graphql to point at the signet staging environment with test funds.price.js works without an API key; only wallet operations require authentication.{baseDir}/scripts/balance.js — Check wallet balances{baseDir}/scripts/create_invoice.js — Create BTC Lightning invoices (auto-subscribes to payment status){baseDir}/scripts/create_invoice_usd.js — Create USD-denominated Lightning invoices (auto-subscribes to payment status){baseDir}/scripts/check_invoice.js — Check invoice payment status (polling){baseDir}/scripts/pay_invoice.js — Pay BOLT-11 invoices (BTC or USD wallet){baseDir}/scripts/pay_lnaddress.js — Pay to Lightning Addresses (BTC or USD wallet){baseDir}/scripts/pay_lnurl.js — Pay to LNURL strings (BTC or USD wallet){baseDir}/scripts/fee_probe.js — Estimate payment fees (BTC or USD wallet){baseDir}/scripts/qr_invoice.js — Render invoice QR code (terminal + PNG file){baseDir}/scripts/transactions.js — List transaction history{baseDir}/scripts/price.js — Get BTC/USD exchange rate{baseDir}/scripts/account_info.js — Show account info and limits{baseDir}/scripts/swap_quote.js — Build BTC<->USD swap quote receipts (dry-run){baseDir}/scripts/swap_execute.js — Execute BTC<->USD wallet-native swaps (or dry-run receipts){baseDir}/scripts/subscribe_invoice.js — Subscribe to invoice payment status (standalone){baseDir}/scripts/subscribe_updates.js — Subscribe to realtime account updates