# Wallet of Agents > A Lightning address for your AI agent: name@walletofagents.dev. Invoices are made by the agent's OWN wallet through a receive-only NWC connection. Wallet of Agents is software and never holds keys, seeds, spend permissions or funds. Service version: 0.1.14. Terms version: 2026-10-26. Base URL: https://walletofagents.dev Docs: https://walletofagents.dev/woa/v2/llms.txt ## What you get - name@walletofagents.dev Lightning address (LUD-16, LNURL-pay LUD-06, verify LUD-21). Max 21,000 sats per payment. - Signed receipts (Ed25519) for every settled payment to your address. - Payment history (90 days; 365 days and CSV on Pro). - Discovery listing with your payee node key, an agent card, and a signed, hash-chained public registration log. - An MCP server for your account (receive-only): status, history, receipts and invoices from your own wallet. See "MCP" below. - 0% per payment: WoA takes no fee from payments to your address. Payments go straight to your own wallet. ## Prices (sats, paid by Lightning invoice, fixed periods, no stored balance) - Creating an account is FREE: no up-front payment to sign up or claim a standard name (5+ characters). The first 30 days of the Lightning address plan are included. An agent with an empty wallet can sign up. - After the first 30 days, keep the address with the Lightning address plan (below) or let it lapse. - Lightning address plan: FREE while your address received 400,000 sats or less in the 30 days before a renewal (free tier); above that 1,000 per 30 days. - Free tier: The Lightning address plan renews for free while your address received 400,000 sats or less in the 30 days before the renewal. Above that, the next 30 days cost 1,000 sats. WoA counts only its own signed receipts for payments to your WoA address that it saw settle; payments made to your wallet in other ways are not counted. A free renewal happens on its own when a period ends, as long as a wallet is connected that answered WoA in the last 30 days (an invoice request or a reconnect). Pro (2,100 sats per 30 days) and the yearly fee for 3 and 4 character names are not part of the free tier. GET https://walletofagents.dev/woa/v2/account shows free_tier (the count so far and the last decision). - Pro: 2,100 per 30 days (replaces the address plan; adds 365-day history, CSV export, higher request limit). - Names: 3-character names 21,000 sats/year; 4-character names 5,000 sats/year; 5+ characters included. Shorter than 3: reserved. - Free: sign-up and claiming a standard name, receiving, leaving, disconnecting, export, migration from a WoA custodial wallet. - Not offered: spend proxy, liquidity help, anything that needs spend permission. - JSON: GET https://walletofagents.dev/woa/v2/pricing ## Lapse rule When a plan runs out, your address keeps working for a 7-day grace period. After that it stops resolving (payers get an error, never an invoice), and your name is held for you. Renew any time while it is held to switch it back on. The name is released only after at least 30 days and once nobody has tried to pay it for 90 days in a row; every payment attempt restarts that 90-day count. Released names are recorded in the public log. ## Sign up (agent, unattended) 1. GET https://walletofagents.dev/woa/v2/names/ -> available, price. Name rule: 3 to 32 characters: lowercase a-z, 0-9, dot, dash or underscore, starting and ending with a letter or digit, no two symbols in a row. 2. POST https://walletofagents.dev/woa/v2/signup {"name":"atlas","plan":"address","accept_terms":"2026-10-26","nostr_pubkey":"","recovery_pubkey":"","listed":true} Standard name (5+ characters) on the address plan: FREE. -> 201 {account_id, lightning_address, account_secret, paid_until, ...} at once. No invoice, no payment. Skip to step 5. Free sign-ups are limited to 3 per day per IP address and 100 per day overall (429 free_signup_limit). A 3 or 4 character name, or plan "pro", still costs its listed price: the reply is 402 with an invoice; then do steps 3 and 4. -> 402 {order_id, invoice, amount_sats, l402:{macaroon}} and header WWW-Authenticate: L402 macaroon="...", invoice="..." (paid items only) 3. Pay the invoice from your wallet. Keep the preimage. 4. POST https://walletofagents.dev/woa/v2/orders//claim {"preimage":""} (or replay step 2 with Authorization: L402 :) -> 201 {account_id, lightning_address, account_secret, paid_until, ...} account_secret is shown ONCE. Store it (mode 600). It controls the address and cannot spend. Lost the reply of a paid sign-up? Claim again with the preimage within 24 h to get a new secret. A free sign-up has no preimage, so store the secret straight away; once a wallet is connected you can reset it by proof (see Wallet changes). 5. POST https://walletofagents.dev/woa/v2/account/wallet Authorization: Bearer {"type":"nwc","uri":"nostr+walletconnect://?relay=wss://...&secret=..."} The connection MUST be receive-only: make_invoice, lookup_invoice, get_info (get_balance, get_budget, list_transactions also accepted). Refused with 422 nwc_has_spend_permission if get_info lists pay_invoice, pay_keysend, multi_pay_invoice or multi_pay_keysend. Refused with 422 nwc_permission_not_allowed for anything else beyond receiving (create_connection, sign_message). Hold-invoice methods (make_hold_invoice, settle_hold_invoice, cancel_hold_invoice) are accepted because they only receive; WoA never calls them. We then ask for a 1-sat test invoice and record your payee node key. 6. Your address now resolves: https://walletofagents.dev/.well-known/lnurlp/ Auth for /woa/v2/account*: Authorization: Bearer , or NIP-98 (Authorization: Nostr , u = full URL, method, payload = sha256(body)) if you registered nostr_pubkey. ## Account - GET https://walletofagents.dev/woa/v2/account status, plan, paid_until, grace_until, hold_until, wallet, wallet_status, wallet_health, warnings - PATCH https://walletofagents.dev/woa/v2/account {"listed":false} or {"nostr_pubkey":""|null} - POST https://walletofagents.dev/woa/v2/account/wallet connect or replace the receive-only wallet - DELETE https://walletofagents.dev/woa/v2/account/wallet disconnect (address stops resolving) - POST https://walletofagents.dev/woa/v2/account/renew {"periods":1..12,"plan":"address"|"pro"} -> 402 invoice; claim like sign-up. Free tier: 200 {renewed:true, amount_sats:0} when the period has ended and the free tier applies - GET https://walletofagents.dev/woa/v2/account/history ?limit=&before=&format=csv (csv: Pro) - POST https://walletofagents.dev/woa/v2/account/rotate-secret new account_secret, old one revoked (paused 24 h after a proof-based reset) - POST https://walletofagents.dev/woa/v2/account/leave {"confirm":""} free; returns your export; connection deleted at once - POST https://walletofagents.dev/woa/v2/account/recovery-key {"recovery_pubkey":"<64-hex>"|null, "proof":{...}} see Wallet changes - POST https://walletofagents.dev/woa/v2/account/wallet/pending/cancel cancel a time-locked wallet change - POST https://walletofagents.dev/woa/v2/account/recovery/pending/cancel cancel a delayed recovery-key action ## MCP (receive-only) - Endpoint: POST https://walletofagents.dev/woa/v2/mcp (MCP Streamable HTTP, JSON responses, no sessions, no event stream; GET answers 405) - Auth: Authorization: Bearer on each request (or NIP-98 with u = this URL, method POST). initialize, tools/list, woa_receipt and woa_pricing need no secret. - Tools: woa_status (account view), woa_history {limit?, before?}, woa_invoice {amount_sats, comment?} (your own wallet makes the invoice through the same path payers use, so the payment gets a signed receipt), woa_check_payment {payment_hash}, woa_receipt {payment_hash}, woa_pricing. - Nothing here can spend, withdraw, change your wallet or show your secret. - Client config example: {"mcpServers":{"woa":{"type":"http","url":"https://walletofagents.dev/woa/v2/mcp","headers":{"Authorization":"Bearer "}}}} ## Wallet changes (rebind protection) Your name is bound to the node key of the first wallet you connect (payee_pubkey; GET /woa/v2/account -> binding). The account secret alone can NOT move the address to a wallet with a different node key, so a leaked secret cannot redirect your payments. - Same node key (new connection to the same wallet, or reconnect after a disconnect): no proof needed. - Different node key: POST /woa/v2/account/wallet answers 409 rebind_proof_required with a challenge {challenge_id, message, expires_at}. Nothing changes; your address keeps paying the old wallet. Sign the message and send the same request again with "rebind_proof":{"challenge_id":"rbc_...","key":"wallet","signature":""} signed by the OLD node key (Lightning signmessage format: NWC sign_message on a connection to the old wallet, lncli signmessage, lightning-cli signmessage), or "rebind_proof":{"challenge_id":"rbc_...","key":"recovery","signature":"<128 hex>"} BIP-340 Schnorr over sha256(message as UTF-8) by your recovery key. A challenge names the old and new node keys and the binding epoch, works once and expires after 10 minutes. Used: 409 challenge_used. Expired: 410 challenge_expired. Issued for another wallet or an older binding: 409 challenge_mismatch. Bad signature: 403 rebind_proof_invalid. WoA never needs sign_message on the connection it stores: you sign with your own tools and send only the signature. - Recovery key (optional, recommended): an x-only secp256k1 public key you keep offline. Set it at sign-up ("recovery_pubkey"), or with POST /woa/v2/account/recovery-key. Adding the first one is free while no wallet is bound; after that, adding, changing or removing it needs the same kind of proof (old node key or current recovery key): the first call returns 409 recovery_proof_required with a challenge, send it again with "proof":{...}. - Lost the old wallet and have no recovery key: send {"type":"nwc","uri":"...","rebind":"time_lock"}. The change is published in the public log (wallet_rebind_pending) and shown in the directory, and applies after 7 days. Until then the address keeps paying the old wallet. Cancel it with POST /woa/v2/account/wallet/pending/cancel, or without the secret: POST https://walletofagents.dev/woa/v2/names//rebind/cancel {"pending_id":"rbp_...","key":"wallet"|"recovery","signature":"..."} over pending_rebind.cancel.message. Watch the log for your name. - Stolen or lost account secret: the bound node key or the recovery key can reset it, no secret needed. 1. POST https://walletofagents.dev/woa/v2/names//secret-reset/challenge -> {challenge_id, message, expires_at} (one use, 10 minutes) 2. Sign message like above (key "wallet": Lightning signmessage by the bound node key; key "recovery": BIP-340 by the recovery key). 3. POST https://walletofagents.dev/woa/v2/names//secret-reset {"challenge_id":"rbc_...","key":"wallet"|"recovery","signature":"..."} -> 200 {account_secret (shown once), cancelled_pending_rebind, cooldown_until} The old secret stops working at once, any pending time-locked wallet change is cancelled, a Nostr key on the account is removed (add yours back later) and the reset is a signed log entry (secret_reset). For 24 hours after a reset, secret-only actions are paused (423 secret_reset_cooldown): rotate-secret, changing nostr_pubkey and time-locked wallet changes; a new proof-based reset still works. After a reset the sign-up preimage can no longer reissue a secret. Same errors as wallet changes (403, 409 challenge_used or challenge_mismatch, 410 challenge_expired). - Recovery-key actions are delayed (72 hours). A change authorised by the recovery key ALONE (moving the address to a new wallet, resetting the account secret, replacing or removing the recovery key) answers 202 with pending_recovery_action {pending_id, kind, effective_at, cancel:{message}} and applies only after 72 hours. It is a public signed log entry (recovery_action_pending, cancellable_by node_key and account_secret) and shows in GET /woa/v2/directory/. For a secret reset the new secret is returned at once but works only from account_secret_active_from; the old one keeps working until then. One pending recovery action at a time (409 recovery_action_pending). Cancel it with the account secret: POST /woa/v2/account/recovery/pending/cancel. Or with the bound node key, no secret needed: POST https://walletofagents.dev/woa/v2/names//recovery/cancel {"pending_id":"rcp_...","key":"wallet","signature":""}. The recovery key cannot cancel (403 node_key_required) and cannot undo a node-key action. Actions signed by the bound node key stay immediate and cancel any pending recovery-key action. The pending action is also dropped if the binding or the recovery key changes first, or the account closes. Recovery key lifecycle: enroll (first key), rotate (replace), revoke (remove); each is a logged transition. Lost recovery key: replace it with the node key. Leaked recovery key: revoke it with the node key at once. - Every binding change is a signed log entry (wallet_connected) with binding_epoch, prev_payee_pubkey, auth (initial, same_node, old_wallet_key, recovery_key, time_lock) and the proof (message, signature, signer) so anyone can check it. ## Wallet status (your wallet must stay online) WoA asks your wallet for an invoice each time someone pays your address. GET https://walletofagents.dev/woa/v2/account shows: - wallet_status "ok": your wallet answered the last invoice request. - wallet_status "degraded": the last invoice request failed (its last_error_at is newer than last_ok_at). Payers may see an error. - wallet_status "offline": 3 or more failures in a row. For 90 s payers get an immediate LNURL error ("the receiving wallet is offline, try again in N s", HTTP 503 with Retry-After) instead of waiting; then WoA tries your wallet again. One success clears it. - wallet_health: {wallet_status, last_ok_at, last_error_at, consecutive_failures, cutoff_until, message}. A warning is added whenever the last error is newer than the last success. Each invoice request waits at most 5.5 s for your wallet. Fix: bring the wallet online, or reconnect with POST /woa/v2/account/wallet (this also clears the cut-off). The payRequest JSON carries woaWalletStatus (ok, degraded, offline) as a hint for payers. ## Paying an address (for payers) - GET https://walletofagents.dev/.well-known/lnurlp/ -> payRequest (minSendable 1000, maxSendable 21,000,000 msat) - GET callback?amount=&comment=<<=64 chars> -> {pr, verify, successAction:url receipt} - Check the invoice payee equals payee_pubkey in GET https://walletofagents.dev/woa/v2/directory/ before paying. - GET verify URL (LUD-21) -> {settled, preimage} - GET https://walletofagents.dev/woa/v2/receipts/ -> signed receipt; verify with public_key from https://walletofagents.dev/woa/v2/discover - Log freshness (protects against a stale or forked view of the log). The payRequest and callback JSON carry extra fields: woaLogHead (signed log head {type "woa.log_head.v1", issuer, log_seq, log_head, issued_at, fresh_for_sec, key_id, sig}), woaBinding {epoch, payee_pubkey, wallet_link_log_seq, wallet_link_log_hash, pending_rebind, pending_recovery_action}, woaCanReceive, woaProof and woaVerifyKey. Standard LNURL clients can ignore them. A careful payer checks, in order: 1. sig is Ed25519 by public_key (GET https://walletofagents.dev/woa/v2/log/head) over canonical JSON (sorted keys, no spaces) of woaLogHead without sig. 2. Fresh: now - issued_at <= fresh_for_sec (600 s; use a smaller window if you like) and issued_at not more than 120 s in the future. Refuse a stale head on staleness alone. 3. Pin the newest head you accepted. Lower log_seq than your pin: rollback, refuse. Same log_seq with another log_head: fork, refuse. Higher log_seq: fetch GET https://walletofagents.dev/woa/v2/log/proof?from=&to= and check every entry: entry.prev equals the previous hash, hash = sha256(canonical JSON without hash and sig), sig verifies over canonical JSON with hash, seq increases by 1, and the chain ends at log_head. 4. Optional: the wallet_connected entry at woaBinding.wallet_link_log_seq is inside a checked chain ending at this head, has hash wallet_link_log_hash and names the payee_pubkey the invoice pays. If woaBinding.pending_recovery_action or pending_rebind is set, the address may move soon. 5. Optional: a quorum of independent witness cosignatures (below). 6. Key pin (recommended, default in the reference checker). The first time you pay a name, store woaBinding {payee_pubkey, wallet_link_log_seq, wallet_link_log_hash}. Later, if woaBinding.payee_pubkey differs from the key you first paid, refuse by default (first_paid_key_changed). Accept the new key only if a log proof from before your stored wallet_link_log_seq to the current head shows every change from your key to the new one, each one either: - auth old_wallet_key: check yourself that proof.signature is a Lightning signmessage by the previous key over proof.message, and that the message names this address, from_node (old key) and to_node (new key); or - auth time_lock or recovery_key: the change points (pending_id) to a public wallet_rebind_pending or recovery_action_pending entry in the same chain with the same to_payee_pubkey, and was applied at or after its effective_at (for recovery_key, also check the BIP-340 signature in that pending entry). Anything else is refused: unverified_key_change, rebind_not_cleared (pending entry missing or applied early), name_reassigned (a name_released entry after your first payment: the name now belongs to someone else), no_key_history (proof does not reach back far enough). A payer can choose to refuse every change, or opt in to accept any change explicitly. While woaBinding.pending_rebind or pending_recovery_action is set, the key may change soon. 7. Reissued names (first-time payers). If the payRequest or callback carries woaReissued (not null), the name was released (lapsed or left) and registered again: {reissued, name, released_at, release_reason, reissued_at, release_log_seq, release_log_hash, previous_payee_pubkey, previous_key_fingerprint, current_payee_pubkey, current_key_fingerprint, key_changed, payer_rule}. A key fingerprint is the first 16 hex characters of sha256 over the 33 bytes of the node key. If you have no first-paid pin on the current holder (you never paid this name, or only paid it before the release) and key_changed is true, refuse by default (name_reissued) and only pay after you (or your owner) confirm you mean the new holder. Then store the first-paid pin as in step 6, so later payments need no confirmation. Do not rely on the service alone: woaProof starts before the release, so check that the name_released entry at release_log_seq is in the checked chain (hash release_log_hash, same name; otherwise reissue_mismatch), and treat any name_released entry for this name before woaBinding.wallet_link_log_seq as a reissue even if woaReissued is missing. key_changed is false when the earlier holder never bound a wallet (nobody could have paid it) or bound the same key. A reference implementation is in the source (src/payer-check.ts, checkPayView with firstPaid, keyChange "verified_rebind" | "refuse" | "accept", reissued and confirmReissued). - Lapsed names: a name whose plan has lapsed answers LNURL with an error and never returns an invoice. It is released only after at least 30 days and 90 days in a row with no payment attempt to it; each attempt restarts the count, and the release is a signed name_released log entry. A later registration of the same name by someone else is a new wallet_connected entry with auth initial, which the key pin above refuses (name_reassigned) for anyone who paid before, and which step 7 flags (name_reissued) for first-time payers. - Receipts also carry log_head_at (time of the log position, covered by sig); GET receipts adds log_head_now (a fresh signed head) and proof_url. - Each receipt names the binding the invoice came from (binding_epoch, wallet_link_log_seq, wallet_link_log_hash: the wallet_connected entry in https://walletofagents.dev/woa/v2/log) and the log position when it was signed (log_seq, log_head). Compare these with other checkers to spot a forked log. ## Discovery - https://walletofagents.dev/woa/v2/discover (JSON), https://walletofagents.dev/woa/v2/agent-card.json, https://walletofagents.dev/woa/v2/openapi.json - https://walletofagents.dev/woa/v2/directory (listed active addresses with payee keys), https://walletofagents.dev/woa/v2/log (signed registration log) - GET https://walletofagents.dev/woa/v2/log/head signed log head, public key, freshness rule and witness cosignatures - GET https://walletofagents.dev/woa/v2/log/proof?from=&to= entries between two positions (max 2000) for consistency and inclusion checks - POST https://walletofagents.dev/woa/v2/log/witness {"witness_pubkey","log_seq","log_head","signature"} for allowlisted outside witnesses: BIP-340 over sha256 of the lines "Wallet of Agents log checkpoint v1", "issuer: ", "log_seq: ", "log_head: ". A witness should cosign only heads that extend the last head it cosigned. 501 when no witnesses are configured (the list is empty until outside operators run one). - Directory entries carry can_receive: "wallet" when the agent's own wallet is connected and answering, "none" otherwise. WoA never receives on an agent's behalf. - https://walletofagents.dev/woa/v2/liquidity-guide (how to fund your own wallet: Spark route or channel minimums) - Terms https://walletofagents.dev/woa/v2/terms Privacy https://walletofagents.dev/woa/v2/privacy ## Errors JSON {error, message, ...}. 400 invalid input, 401 unauthorized, 402 payment_required, 404 not_found, 409 name_taken|name_pending|already_claimed, 410 order_expired, 413 payload_too_large, 422 wallet refused, 423 secret_reset_cooldown, 429 rate_limited|free_signup_limit, 501 not enabled, 503 billing_unavailable. LNURL routes use {status:"ERROR", reason}. ## Safety rules for agents - Never send a pay-capable connection. Create a dedicated receive-only connection for Wallet of Agents. - Never post your account_secret or connection string anywhere. - Set a recovery key and keep it offline. Never sign a wallet change challenge you did not ask for. - Keep your wallet online; check wallet_status and warnings in GET /woa/v2/account. Contact: https://x.com/WalletOfAgents | Nostr https://njump.me/npub1stz6j6h27n38wda0vrm3rj3490dhkzkrrhlp25yuegyg72a0tggsl48w7l | https://walletofagents.dev/.well-known/security.txt