@zbdpay/agent-wallet
v1.3.0
Published
CLI wallet and command router for ZBD agent payments
Readme
@zbdpay/agent-wallet
zbdw CLI for wallet operations, registration, history, and L402-aware fetch flows.
Requirements
- Node.js
>=22 - npm
Install
npm install @zbdpay/agent-walletRun without installation:
npx @zbdpay/agent-wallet init --key <apiKey>Global install for frequent use:
npm install -g @zbdpay/agent-wallet
zbdw balanceLocal repo usage from /Users/andreneves/Code/zbd/agents:
npm --prefix agent-wallet run build
alias zbdw='node agent-wallet/dist/cli.js'Environment Variables
ZBD_API_KEY: API key used by wallet calls and paymentsZBD_API_BASE_URL: ZBD API base URL, defaulthttps://api.zbdpay.comZBD_AI_BASE_URL: registration service base URL, defaulthttps://zbd.aiZBD_WALLET_CONFIG: config path, default~/.zbd-wallet/config.jsonZBD_WALLET_PAYMENTS: payment history path, default~/.zbd-wallet/payments.jsonZBD_WALLET_TOKEN_CACHE: token cache path, default~/.zbd-wallet/token-cache.json
Commands
zbdw init [--key <apiKey>]
zbdw info
zbdw balance
zbdw receive <amount_sats>
zbdw receive --static
zbdw send <destination> <amount_sats>
zbdw payments
zbdw payment <id>
zbdw paylink create <amount_sats>
zbdw paylink get <id>
zbdw paylink list
zbdw paylink cancel <id>
zbdw withdraw create <amount_sats>
zbdw withdraw status <withdraw_id>
zbdw onchain quote <amount_sats> <destination>
zbdw onchain send <amount_sats> <destination> --accept-terms [--payout-id <id>]
zbdw onchain status <payout_id>
zbdw onchain retry-claim <payout_id>
zbdw fetch <url> [--method <method>] [--data <json>] [--max-sats <amount>]Destination Types (send)
lnbc...-> Bolt11 invoicelnurl...-> LNURL@name-> ZBD gamertag[email protected]-> Lightning address
Paylink Commands
Paylinks are hosted payment pages at zbd.ai/paylinks/<id>. Share the url with a payer; the link handles the invoice lifecycle.
# Create a paylink for 250 sats
zbdw paylink create 250
# {"id":"pl_001","url":"https://zbd.ai/paylinks/pl_001","status":"active","lifecycle":"active","amount_sats":250}
# Fetch current state (also syncs settlement to local payments.json)
zbdw paylink get pl_001
# {"id":"pl_001","url":"...","status":"active","lifecycle":"active","amount_sats":250,"created_at":"...","updated_at":"..."}
# List all paylinks
zbdw paylink list
# {"paylinks":[...]}
# Cancel a paylink (transitions lifecycle to dead)
zbdw paylink cancel pl_001
# {"id":"pl_001","url":"...","status":"dead","lifecycle":"dead"}Lifecycle values: created -> active -> paid | expired | dead
Terminal states (paid, expired, dead) are permanent. A paid link cannot be reused; an expired or cancelled link cannot be reactivated.
paylink get also polls the latest payment attempt and appends a settlement record to ~/.zbd-wallet/payments.json with paylink_id, paylink_lifecycle, and paylink_amount_sats metadata.
Onchain Payout Commands
Onchain payouts send bitcoin to a native BTC address via the zbd-ai payout service.
# Get a fee quote before sending
zbdw onchain quote 10000 bc1qexample...
# {"quote_id":"q_001","amount_sats":10000,"fee_sats":150,"total_sats":10150,"destination":"bc1q...","expires_at":"..."}
# Send onchain (--accept-terms is required)
zbdw onchain send 10000 bc1qexample... --accept-terms
# {"payout_id":"payout_123","status":"queued","amount_sats":10000,"destination":"bc1q...","request_id":"req_abc","kickoff":{"enqueued":true,"workflow":"payout.workflow.root","kickoff_id":"k_001"}}
# Check payout status
zbdw onchain status payout_123
# {"payout_id":"payout_123","status":"broadcasting","amount_sats":10000,"destination":"bc1q...","txid":null,"failure_code":null,"kickoff":{...}}
# Retry claim after a failed_invoice_expired payout
zbdw onchain retry-claim payout_123
# {"payout_id":"payout_123","status":"queued","kickoff":{"enqueued":true,"workflow":"payout.workflow.root","kickoff_id":"k_002"}}--accept-terms is required for onchain send. Omitting it exits immediately with accept_terms_required and makes no outbound request.
Payout status values: created -> queued -> broadcasting -> succeeded (terminal) or failed_invoice_expired | failed_lockup | refunded | manual_review (terminal)
Successful onchain send appends a record to ~/.zbd-wallet/payments.json with source: "onchain", onchain_network, onchain_address, and onchain_payout_id metadata.
JSON Output Contract
CLI writes JSON to stdout for both success and failure.
Failure shape:
{
"error": "error_code",
"message": "Human-readable message",
"details": {}
}Examples:
init:{ "lightningAddress": "[email protected]", "status": "ok" }info:{ "lightningAddress": "...", "apiKey": "***", "balance_sats": 123 }fetch:{ "status": 200, "body": {...}, "payment_id": "...|null", "amount_paid_sats": 21|null }paylink create:{ "id": "pl_001", "url": "https://zbd.ai/paylinks/pl_001", "status": "active", "lifecycle": "active", "amount_sats": 250 }paylink get: addscreated_atandupdated_atto the abovepaylink list:{ "paylinks": [...] }where each item matchespaylink getshapepaylink cancel:{ "id": "...", "url": "...", "status": "dead", "lifecycle": "dead" }onchain quote:{ "quote_id": "...", "amount_sats": N, "fee_sats": N, "total_sats": N, "destination": "...", "expires_at": "..." }onchain send:{ "payout_id": "...", "status": "queued", "amount_sats": N, "destination": "...", "request_id": "...", "kickoff": {...} }onchain status:{ "payout_id": "...", "status": "...", "amount_sats": N|null, "destination": "...", "txid": "...|null", "failure_code": "...|null", "kickoff": {...} }onchain retry-claim:{ "payout_id": "...", "status": "queued", "kickoff": {...} }
Storage Files
- Config:
~/.zbd-wallet/config.jsonapiKeylightningAddress
- Payment history:
~/.zbd-wallet/payments.json- paylink settlement records include
paylink_id,paylink_lifecycle,paylink_amount_sats - onchain payout records include
source: "onchain",onchain_network,onchain_address,onchain_payout_id
- paylink settlement records include
- Token cache:
~/.zbd-wallet/token-cache.json
L402 Fetch Flow
zbdw fetch is powered by @zbdpay/agent-fetch.
- parses
402challenge - pays invoice via wallet API
- retries with proof
- caches token
- enforces optional
--max-sats
Call twice against the same protected URL to verify cache reuse:
zbdw fetch "https://your-protected-endpoint" --max-sats 100
zbdw fetch "https://your-protected-endpoint" --max-sats 100On the second call, payment_id should be null when cached token is reused.
Companion Examples You Can Run Now
agent-wallet does not ship its own examples/ folder yet, but the fastest end-to-end examples are in companion repos:
../agent-pay/examples/http-server.mjs(serve a paid endpoint)../agent-fetch/examples/zbd-agent-fetch.mjs(pay and fetch that endpoint)
From /Users/andreneves/Code/zbd/agents:
npm --prefix agent-pay run build
ZBD_API_KEY=<your_api_key> npm --prefix agent-pay run example:http-serverThen in another terminal:
npm --prefix agent-wallet run build
node agent-wallet/dist/cli.js fetch "http://localhost:8787/protected" --max-sats 100Scripts
npm run build
npm run test
npm run lint
npm run typecheck
npm run release:dry-runTroubleshooting
zsh: command not found: zbdw- build first and add alias, or install package globally
register_failedduringinit- ensure
ZBD_AI_BASE_URLpoints to your runningzbd-aiinstance - confirm upstream
ZBD_API_BASE_URLand API key are valid for static charge creation
- ensure
wallet_response_invalidduringinfo/balance- verify wallet endpoint returns a valid balance shape and that
ZBD_API_BASE_URLis correct
- verify wallet endpoint returns a valid balance shape and that
accept_terms_requiredduringonchain send- add
--accept-termsflag to confirm consent; the flag is required and there is no interactive prompt
- add
onchain_payout_request_failedduringonchain send/status/retry-claim- verify
ZBD_AI_BASE_URLpoints to your runningzbd-aiinstance - inspect
details.statusanddetails.responsefor upstream error context
- verify
failed_invoice_expiredpayout status- the payout's internal invoice expired before the claim completed; run
zbdw onchain retry-claim <payout_id>to re-enqueue
- the payout's internal invoice expired before the claim completed; run
