@axobot/cli
v1.2.0
Published
CLI wallet and command router for ZBD agent payments
Readme
@axobot/cli
axo CLI for wallet operations, registration, history, and L402-aware fetch flows.
Requirements
- Node.js
>=22 - npm
Install
npm install @axobot/cliRun without installation:
npx @axobot/cli init --key <apiKey>Global install for frequent use:
npm install -g @axobot/cli
axo balance
axo balanceLocal repo usage from /Users/andreneves/Code/zbd/agents:
npm --prefix axobot-cli run build
alias axo='node axobot-cli/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
axo init [--key <apiKey>]
axo info
axo balance
axo receive <amount_sats>
axo receive --static
axo send <destination> <amount_sats>
axo payments
axo payment <id>
axo paylink create <amount_sats>
axo paylink get <id>
axo paylink list
axo paylink cancel <id>
axo withdraw create <amount_sats>
axo withdraw status <withdraw_id>
axo onchain quote <amount_sats> <destination>
axo onchain send <amount_sats> <destination> --accept-terms [--payout-id <id>]
axo onchain status <payout_id>
axo onchain retry-claim <payout_id>
axo fetch <url> [--method <method>] [--data <json>] [--max-sats <amount>]zbdw info zbdw balance
zbdw receive <amount_sats> zbdw receive --static
zbdw send <amount_sats> zbdw payments zbdw payment
zbdw paylink create <amount_sats> zbdw paylink get zbdw paylink list zbdw paylink cancel
zbdw withdraw create <amount_sats> zbdw withdraw status <withdraw_id>
zbdw onchain quote <amount_sats> zbdw onchain send <amount_sats> --accept-terms [--payout-id ] zbdw onchain status <payout_id> zbdw onchain retry-claim <payout_id>
zbdw fetch [--method ] [--data ] [--max-sats ]
### Destination Types (`send`)
- `lnbc...` -> Bolt11 invoice
- `lnurl...` -> 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.
```bash
# Create a paylink for 250 sats
axo 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)
axo paylink get pl_001
# {"id":"pl_001","url":"...","status":"active","lifecycle":"active","amount_sats":250,"created_at":"...","updated_at":"..."}
# List all paylinks
axo paylink list
# {"paylinks":[...]}
# Cancel a paylink (transitions lifecycle to dead)
axo 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
axo 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)
axo 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
axo 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
axo 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
axo fetch is powered by @axobot/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:
axo fetch "https://your-protected-endpoint" --max-sats 100
axo 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
axobot-cli does not ship its own examples/ folder yet, but the fastest end-to-end examples are in companion repos:
../axobot-pay/examples/http-server.mjs(serve a paid endpoint)../axobot-fetch/examples/zbd-agent-fetch.mjs(pay and fetch that endpoint)
From /Users/andreneves/Code/zbd/agents:
npm --prefix axobot-pay run build
ZBD_API_KEY=<your_api_key> npm --prefix axobot-pay run example:http-serverThen in another terminal:
npm --prefix axobot-cli run build
node axobot-cli/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: axo- 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
axo onchain retry-claim <payout_id>to re-enqueue
- the payout's internal invoice expired before the claim completed; run
