@anyway-sh/cli
v0.12.0
Published
Anyway CLI — terminal interface for the Anyway merchant platform
Readme
Anyway CLI
Terminal interface for the Anyway merchant platform. Manage products, payment links, orders, and more — directly from your terminal or agent environment.
Telemetry
This CLI collects anonymous usage data to help improve the product. No tokens, keys, request bodies, or personally identifiable information are ever sent.
Opt out at any time:
ANYWAY_TELEMETRY=0 # or DO_NOT_TRACK=1
anyway telemetry offSee TELEMETRY.md for the full list of what is and isn't collected.
Installation
npm install -g @anyway-sh/cliOr use without installing:
npx @anyway-sh/cli <command>BUY setup
For an agent that buys paid APIs, start with:
anyway login --agent-wallet --non-interactiveNo provider API keys are needed. An Agent Wallet Key authorizes agent spending. Anyway Credits are organization-level USD Credit and are spent first. Agent Wallet USDC is fallback funding after Credits are insufficient.
Merchant/account setup: anyway login. Keep using that flow for products,
orders, merchant wallets, and other account administration.
Quick Start
# Authenticate (opens browser)
anyway login
# Create a product with payment link
anyway products create --name "My Product" --price 29.99
# Get JSON output (for agent/automation use)
anyway products create --name "My Product" --price 29.99 --format jsonAuthentication
The CLI has three auth modes, depending on the command:
| Auth mode | What you need | Used by |
| --- | --- | --- |
| merchant | anyway login (merchant JWT) | most commands — products, orders, wallets, dashboard, developer, traces, and wallets agents create / list / reset |
| agent key | ANYWAY_AGENT_WALLET_KEY env var or a record from wallets agents import | wallets agents list --local / import / history / policies / whoami / pay / sign, superapi call |
| local | nothing — touches only ~/.anyway/agents/* | wallets agents default / forget |
Merchant login
anyway login # Open browser to authenticate
anyway logout # Clear stored credentials
anyway whoami # Show current session infoFirst-time login opens a browser window to complete authentication. Credentials are stored at ~/.anyway/credentials.json and auto-refreshed.
For headless environments (SSH / CI / agents), anyway login --non-interactive runs a non-blocking device flow: it prints a verification URL and exits. Share the URL with the wallet owner, then anyway login --non-interactive --continue waits ~60s for approval (repeat while pending; --restart to start over). A non-TTY stdin selects this automatically. The legacy anyway login --token <b64> paste path — where the login page shows a token to paste back — still works as a fallback.
Agent key
The preferred BUY setup above creates and saves an Agent Wallet Key through
the device flow. If a key is created or reset outside that flow, the dashboard's
reveal dialog gives you its base64url bundle. It decodes to JSON with a
privateKey field; do not log it or paste it into prompts. Set it once on the
host that runs your agent, or import it into ~/.anyway/agents/. Agent-key
commands then work without a merchant login because the CLI signs each request
with the P-256 key inside.
# Manual fallback for a bundle revealed outside the preferred setup flow:
export ANYWAY_AGENT_WALLET_KEY="<base64url string starting with eyJwc...>"
# Or persist the same bundle locally for this machine:
anyway wallets agents import --token <bundle>
# Now agent-key commands work — no merchant login required:
anyway wallets agents whoami
anyway wallets agents history --limit 20
anyway wallets agents pay --to 0x... --amount 1.50
anyway superapi call "https://marketplace-prod.anyway.sh/v1/api/x402/twit-sh/tweets/search?words=bitcoin&count=5" -yCommands
products
anyway products list
anyway products list --status active --page 1 --size 20
anyway products get <productId>
anyway products create --name <name> --price <amount> [--currency usd] [--description <desc>]
anyway products create --name <name> --price <amount> --type recurring --interval month
anyway products update <productId> --name <name> [--description <desc>]
anyway products archive <productId>
anyway products publish <productId>
anyway products payment-links <productId>
anyway products payment-links <productId> create [--price <amount>] [--currencies usdc,usdt]Creating a product automatically creates a payment link. The payment link URL is returned in the output.
For crypto payment links, --currencies sets the accepted assets — usdc (default), usdt, or usdc,usdt. Accepting usdt requires USDT receiving enabled (anyway init wallets --type usdt).
orders
anyway orders list
anyway orders list --status paid --page 1 --size 20
anyway orders list --product <productId> --from 2024-01-01 --to 2024-12-31wallets
anyway wallets balance
anyway wallets balance --currency USDT # USDT-TRC20 (TRON) balance
anyway wallets transactions
anyway wallets transactions --limit 50
anyway wallets transactions --currency USDT # USDT-TRC20 (TRON) history--currency accepts USDC (default, Base) or USDT (TRON); --chain <chain> is also accepted as a raw passthrough. Enable USDT receiving with anyway init wallets --type usdt.
wallets agents
Delegated wallet records for agent runtimes. Up to 5 agent wallets per merchant.
Run anyway wallets agents <cmd> --help for per-command details.
Each subcommand below labels which auth mode it needs (merchant / agent key / local) — see Authentication for what each mode means.
Create
Create hands off to the browser for Privy MFA and key creation.
# First time (count must be 0).
anyway init wallets --type agent --name "My Research Agent"
# Add another (count must be >=1).
anyway wallets agents create --name "Pricing Bot"In interactive mode, the browser posts the created Agent Wallet Key bundle back to the CLI. The CLI verifies the key, saves it locally, sets it as the default signing agent, and prints only a non-secret summary. You do not need to copy anything back into the terminal when that callback succeeds.
With --non-interactive, create runs the non-blocking begin / continue /
restart device flow (see the Non-interactive section below) and saves the
verified key automatically on approval — nothing to copy. The
manual ANYWAY_AGENT_WALLET_KEY / anyway wallets agents import --token <bundle>
path is only for a key revealed outside that flow — an interactive browser
callback that couldn't reach the local CLI, or a dashboard rotation — on the
host that will run the agent.
Read (agent-key)
# Server-side view of the calling agent (id, wallet id, wallet address, public key, revoked).
anyway wallets agents whoami [<agentId>]
# Agent-key view of org-level Anyway Credits used before wallet USDC for SuperAPI/x402.
# Requires ANYWAY_AGENT_WALLET_KEY or a locally imported agent key.
anyway wallets agents credit-balance [<agentId>]
# Policies attached to the selected agent wallet.
anyway wallets agents policies [<agentId>]
# Recent activity (max limit 200, default 50).
anyway wallets agents history [<agentId>] [--limit N]agentId selects which local agent to act as. It's the server-side
identifier — safe to print, not a credential. ANYWAY_AGENT_WALLET_KEY
overrides whichever local agent is the default for the session.
List
list has two scopes — server (default) and local (--local). Same verb,
same output shape (table / json), different vantage point. Modeled after
git branch [-r] and docker ps [-a].
# Default: merchant view. Every agent under the logged-in merchant,
# with wallet address, wallet balance, attached policy, and Org Credits.
# Needs `anyway login`.
anyway wallets agents list
anyway wallets agents list --format json
# --local: agents whose private key is in ~/.anyway/agents/, enriched
# per-agent via signed /v1/agent-wallet (one call per local agent, in
# parallel). No merchant login required — each agent signs as itself.
anyway wallets agents list --local
# --local --offline: pure filesystem view, zero network.
# Useful in CI or when you only need the agent ids.
anyway wallets agents list --local --offlineThe two scopes are complementary, not redundant:
- Default view is the source of truth — what the server thinks your merchant owns. Always complete and current, never shows orphans.
--localis the runtime view — what this machine can actually sign with right now. Surfaces orphans (local key but server record gone, revoked, or belongs to a different merchant) that the default view silently hides.
Anyway Credits are org-level USD credits, not wallet USDC. Wallet Balance
does not include credits; SuperAPI/x402 spends credits first, then falls
back to wallet USDC only after credits are insufficient. If you are
logged in as the wallet owner/merchant, use anyway wallets credit balance
to read the same org-level credit pool via your anyway login session.
--local status column values:
active— server responded, agent not revokedrevoked— server responded, agent is revokedorphaned— server returned 401 / 403 / 404 (deleted, wrong env, wrong merchant)offline— couldn't reach server
Use list --local to triage which agents on this machine are still
usable, then forget <agentId> to clean up the orphans.
--offline only applies with --local — the default view inherently
needs to query the server. list --offline (without --local) is
rejected with a validation error.
Sign / pay (agent-key)
# Full SuperAPI purchase — gets 402 challenge, signs, retries, prints result.
anyway superapi call "https://marketplace-prod.anyway.sh/v1/api/x402/twit-sh/tweets/search?words=bitcoin&count=5"
# USDC payment authorization — outputs the signature and fields for PAYMENT-SIGNATURE.
# Use this lower-level command when you want to assemble the x402 retry yourself.
anyway wallets agents pay --to 0xRecipient... --amount 1.50
# Arbitrary EIP-712 typed-data sign.
anyway wallets agents sign --typed-data-file ./payload.jsonsuperapi call shows the payment quote and asks for y/N before signing.
Use --yes or -y in CI/agent runtimes to approve the quoted payment
automatically.
Before reporting insufficient funds, check credits first: use anyway wallets
agents credit-balance in agent-key mode, or anyway wallets credit balance
when you only have merchant login. A 0 USDC wallet balance can still pay if
the org has Anyway Credits.
Local state
# Import the dashboard bundle into ~/.anyway/agents/ and set it as default.
anyway wallets agents import --token <bundle>
# Switch the default local agent (no network).
anyway wallets agents default <agentId>
# Drop a local agent record (the server-side agent is unaffected).
anyway wallets agents forget <agentId> [--yes]
# Rotate the agent's P-256 keypair in place (browser flow).
anyway wallets agents reset <agentId>reset keeps the same agentId, wallet address, balance, and policies. Both
interactive and non-interactive CLI reset verify the refreshed key belongs to
the requested agent and replace the stale local key automatically — no manual
import. Only if the key was rotated outside the CLI (from the dashboard, or
a manual browser handoff that reveals the bundle to you) do you import it
yourself — anyway wallets agents import --token <bundle>, then
anyway wallets agents whoami <agentId>; do not forget first.
Non-interactive (CI / agents)
Setup always requires a browser + human confirmation (Privy MFA). For
environments without a local browser, create uses a non-blocking
begin / continue / restart flow that never holds a long blocking call.
A non-TTY stdin (piped / CI / agent) selects this flow automatically, so
--non-interactive is optional there; --continue/--restart also imply it.
# 1. Begin — opens a session, prints the verification URL + status, and exits
# immediately (does NOT block). Output is a readable summary by default; add
# `--format json` (as with any command) for a single JSON line.
anyway wallets agents create --non-interactive --name "Pricing Bot"
# 2. The wallet owner opens the printed verification_uri and authorizes.
# 3. Continue — resumes the session and waits ~60s for approval, then exits with
# status approved | pending | expired | denied. Call again while pending.
anyway wallets agents create --non-interactive --continue
# Discard a stuck/expired session and start over:
anyway wallets agents create --non-interactive --restartOn approval the CLI verifies the Agent Wallet Key, saves it locally, and sets
it as the default signing agent — no bundle to copy. The session (including the
ephemeral decryption key, 0600) is persisted under ~/.anyway/device/ so step
3 can run in a fresh process. The same flow backs anyway login --non-interactive.
anyway wallets agents reset <agentId> uses the same begin / continue / restart
flow (session key per agent); on approval it verifies and replaces the local key
for that agent id.
dashboard
anyway dashboard templates
anyway dashboard query <templateId>
anyway dashboard query <templateId> --days 30traces
anyway traces status
anyway traces list
anyway traces list --limit 50developer
anyway developer keys list
anyway developer keys list --type sdk_key
anyway developer keys create --name <name>
anyway developer keys delete <keyId>Global Options
| Option | Values | Default | Description |
| ----------- | ------------------------------------- | ------- | ------------------------------------------------------------------------------------ |
| --env | prod, sandbox, dev, dev-local | prod | Target environment |
| --format | table, json, csv | table | Output format |
| --timeout | 10s, 500ms, 2m, 30 (bare = s) | (off) | Hard deadline. On timeout, exits 4 with a TIMEOUT error. Recommended for probes. |
Agent / Automation Usage
All commands return non-zero exit codes on failure so shell pipelines and probes can detect errors via $?.
The following commands support --format json for machine-readable output on stdout:
| Command | --format json |
| ----------------------------- | --------------- |
| whoami | ✅ |
| products list / get / create / payment-links | ✅ |
| orders list | ✅ |
| wallets balance / transactions | ✅ |
| wallets agents list / policies / history | ✅ |
| dashboard templates / query | ✅ |
| traces status / list | ✅ |
| developer keys list / create / delete | ✅ |
| login --token (success and failure) | ✅ |
Commands not emitting JSON (still human-readable text only): login (browser flow), logout, init, update, products archive / publish, products update.
# Create product and capture output
result=$(anyway products create --name "API Product" --price 49.99 --format json)
payment_link=$(echo $result | jq -r '.paymentLink.paymentLinkUrl')
# List orders as CSV
anyway orders list --format csv > orders.csvMonetary values
To avoid agents / probes misreading raw on-chain amounts (USDC uses 6 on-chain decimals, i.e. 1 USDC = 1_000_000 raw units):
- Transaction/order amounts (
orders list,wallets balance,wallets transactions,products.paymentLinks[].amount) are always in major units (human-readable decimals, e.g.0.5USDC, not500000). Each row carries an explicitcurrencyfield. dashboard queryrows are raw aggregates returned by the backend — columns are unit-less numbers and the currency metadata lives on the template (fetch viadashboard templatesfirst). Agents should look up the template'srender.spec.items[].formatand the org's default currency before interpreting values.
Structured error output
When a command with --format json fails, stdout is a single JSON object:
{"success": false, "error": {"message": "<human-readable reason>", "code": "<ERR_CODE>"}}Parse .success (or check $?) to detect failure; read .error.message for diagnostics and .error.code to route alerts. Shell callers that don't want to parse JSON can use $? alone — each error code maps to a dedicated exit code:
| Exit | error.code | Meaning |
| ---- | ----------------------------------- | ----------------------------------------------- |
| 0 | — | Success |
| 1 | UNKNOWN | Uncategorised failure (fallback) |
| 2 | VALIDATION | Bad CLI args / missing required input |
| 3 | AUTH_NOT_LOGGED_IN / AUTH_EXPIRED / AUTH_FAILED | Not logged in, session expired, or 401/403 |
| 4 | TIMEOUT | --timeout deadline reached |
| 5 | NETWORK | DNS, TLS, ECONNREFUSED, ECONNRESET, etc. |
| 6 | SERVER_5XX | Upstream returned 5xx |
| 7 | RATE_LIMITED | HTTP 429 |
| 8 | CLIENT_4XX | Other 4xx (not auth / not rate-limited) |
Example routing:
anyway products list --format json --timeout 10s
case $? in
0) echo "ok" ;;
3) pagerduty "auth expired" ;;
4|5) pagerduty "network / cli unreachable" ;;
6|7) pagerduty "upstream degraded" ;;
*) pagerduty "cli unknown failure" ;;
esacTrace output for synthetic monitoring
Set ANYWAY_TRACE=1 to emit one JSON Lines event per lifecycle step and per outgoing HTTPS request to anyway.sh. Default sink is stderr (stdout keeps the command's normal output):
anyway whoami --format json 2> trace.log | jq .emailExample trace (comments added for clarity, each line is one JSONL event):
{"v":1,"ts":...,"t":"start","cliVersion":"0.1.10","env":"prod","apiUrl":"https://app-prod.anyway.sh","argv":["products","list"]}
{"v":1,"ts":...,"t":"req","method":"GET","url":"https://app-prod.anyway.sh/v1/product?page=1&size=20","requestId":"a1b2c3d4-..."}
{"v":1,"ts":...,"t":"res","method":"GET","url":"...","status":200,"durationMs":142,"requestId":"a1b2c3d4-..."}
{"v":1,"ts":...,"t":"span","phase":"auth.refresh","durationMs":342}
{"v":1,"ts":...,"t":"err","method":"GET","url":"...","code":"ENOTFOUND","message":"..."}
{"v":1,"ts":...,"t":"exit","code":0,"totalMs":528}Event kinds:
start— first event of every run; records CLI version, target env, API URL, argv (with--token <value>scrubbed to<redacted>).span— a named phase with measured duration. Current phases:auth.refresh(auto token refresh),auth.exchange(login --token exchange). Tells the probe which stage the CLI was executing when it exited.req/res— HTTP request/response against anyway.sh hosts, including duration and arequestIdUUID set via theX-Request-Idheader so backend logs can be correlated.err— network-level failure (DNS / TLS / connection refused / reset). Noresevent follows.exit— final event with process exit code and total runtime.v— event schema version (1today).
Probes typically assert: every res has status < 400, no err events, final exit.code === 0. Failure diagnosis: the last span before exit tells you which phase died; requestId links to server-side logs.
Extra knobs:
ANYWAY_TRACE_FILE=/path— append JSONL to a file instead of stderr. Useful when stderr is noisy (ink spinners, progress bars).ANYWAY_TRACE_BODY=1— include up to 2 KB of each response body onresevents as abodyfield. For debugging only; do not enable unconditionally in logs where response payloads may contain sensitive data.
Development
# Build
yarn cli:build
# Run locally
node cli/dist/index.js <command>
# Link globally for development
yarn cli:linkLicense
MIT
