quicknode-cli 0.6.0

Command-line interface for the Quicknode SDK
Documentation
# qn — usage guide for agents

`qn` is the Quicknode command-line interface. It manages endpoints, streams,
webhooks, the KV store, usage, metrics, billing, and teams.

This guide describes qn v{{VERSION}}. It prints as Markdown by default — no flag
needed to read it. For a structured envelope (`{version, guide}`), pass `-o json`.
Read the control-flow sections (auth, output, exit codes, confirmation, retry)
before the command catalog: they decide whether you can run unattended without
hanging or double-acting.

## 1. Auth

Resolution order for the API key:

1. `--api-key <KEY>` flag (highest precedence).
2. Config file: `[api] key = "..."` in `~/.config/qn/config.toml` (or the path
   passed to `--config-file`).
3. If neither resolves, the command exits **4** (`no API key found`).

There is **no environment-variable fallback** by design — a key left exported in
a shell is invisible state that outlives the session.

Non-interactive paths:

- Pass `--api-key <KEY>` on every invocation, or
- Write the key once: `qn auth login --api-key <KEY>` (saves the config file).

`qn auth logout` removes the saved API key but preserves your `[output]`
preferences in the config file.

Config file location:

- Linux/macOS: `$XDG_CONFIG_HOME/qn/config.toml`, else `~/.config/qn/config.toml`.
- Windows: `%USERPROFILE%\.config\qn\config.toml`.

Verify the resolved key against the API: `qn auth whoami` (prints the key redacted
to `****<last4>`, the account id/name and plan, and confirms it works). `qn auth
status` does the same without the network call (no account details).

## 2. Output contract

- Default format is `table` on a TTY and **`json`** when stdout is not a TTY (piped).
- Data goes to **stdout**; diagnostics, prompts, and ✓ confirmations go to **stderr**.
- Formats: `table`, `md`, `json`, `yaml`, `toon`. The structured forms
  (`json`/`yaml`/`toon`) always include every field — `--wide` is not needed and
  only affects `table`/`md`.
- Config file can set defaults: `[output] format = "json"`, `wide = true`.

## 3. Exit codes

Branch on these — especially **4** and **5**.

| Code | Meaning |
|------|---------|
| 0 | Success. |
| 1 | Generic CLI error (bad arguments, I/O, unclassified failure). |
| 2 | API error — the server returned a non-2xx response. |
| 3 | HTTP error — network failure (connect/timeout). |
| 4 | Auth/config — no API key, or a config file that can't be read or written. |
| 5 | Cancelled, or confirmation required and not granted (see §4). |
| 130 | Interrupted (SIGINT). |

On a **per-request paid** `rpc call` (`--x402`/`--mpp`, §6) the 2/3 split carries
payment semantics: **2** means the gateway refused and nothing settled (an
unmatched or unreadable offer, or a 4xx-refused payment), while **3** means the
outcome is unknown — the payment was submitted and **may have been charged** (a
gateway 5xx after the paid resend, a lost response, or an uninterpretable
post-payment response). On exit 3, check the wallet before re-running; never
blind-retry a paid call. A **drawdown** call (`--x402-drawdown`) spends prepaid
credits, not per-call funds: running out surfaces an actionable exit-2 error
pointing at `qn rpc x402 buy-credits`, and a credit is drawn only on success.

## 4. Non-interactive & confirmation behavior

Destructive commands are gated. On a TTY they prompt `y/N`. To proceed without a
prompt, pass `--yes` (`-y`).

In a non-TTY **a gated command without `--yes` exits 5 before any request is sent** —
nothing is changed. Pass `-y` to proceed, or `--no-input` to force non-interactive
behavior everywhere (it fails fast instead of prompting). `--quiet` (`-q`) suppresses
the ✓ state-change notes on stderr; it does not affect stdout.

Gated command classes:

- `endpoint archive`, `endpoint bulk pause`
- `endpoint tag delete`
- `endpoint security` removals (token/jwt/ip/referrer/domain-mask remove, and
  `set-options` toggles that disable a protection)
- `endpoint rate-limit delete-override`
- `stream delete`, `webhook delete`, `team delete`
- `kv set delete`, `kv list delete`

There is **no account-wide wipe command** — that is intentional; use the API directly
if you need it.

## 5. Retry & idempotency

- **Read-only** commands auto-retry transient failures (HTTP 429/500/502/503/504 and
  connect/timeout errors) with exponential backoff and jitter. Tune with `--retries N`
  (default 3; `0` = a single attempt, no retries).
- **Mutations never auto-retry.** A retried create/update/delete could apply twice.
- When a mutation fails transiently, its outcome is unknown until verified — e.g.
  `qn endpoint show <id>` reflects whether it took effect.
- `qn stream test-filter` evaluates a filter against historical data and changes
  nothing — it is read-only and safe to retry.
- `qn sql query` is read-only but **does not auto-retry**: a query consumes credits,
  so a retried query re-bills. `qn sql schema` is a cheap read and retries normally.
- A **paid** `rpc call` (`--x402`/`--mpp`/`--x402-drawdown`/`--mpp-session`)
  never auto-retries — `--retries` does not apply. A per-request attempt can
  move funds, and after a lost response the previous attempt may already have
  settled (§3, exit 3). A drawdown call draws 1 credit per success and is
  single-attempt (the one exception is a transparent re-auth when the session
  token expired, which draws nothing). A session call signs one cumulative
  voucher and is single-attempt.

## 6. Command catalog

Top-level nouns (plurals like `endpoints`/`streams` and `ls` are accepted aliases):

- `auth` — login, logout, whoami, status
- `endpoint` — list, show, create, update, archive, pause, resume, urls, logs,
  log-details, metrics, enable-multichain, disable-multichain; nested:
  `tag`, `security`, `rate-limit`, `bulk`
- `team` — list, create, show, delete, endpoints, set-endpoints; nested: `member`
- `usage` — summary, by-endpoint, by-method, by-chain, by-tag
- `metrics` — account, endpoint
- `chain` — list, credits
- `billing` — invoices, payments
- `stream` — list, show, create, update, delete, activate, pause, test-filter,
  enabled-count
- `webhook` — list, show, create, update, update-template, delete, activate, pause,
  enabled-count
- `kv``set` (put, get, list, delete, bulk) and `list` (list, get, create, append,
  contains, remove-item, update, delete)
- `sql` — query (inline SQL, `--file <path>`, or `--file -` for stdin), schema
- `tooling-access` — status, enable, disable (provisions the endpoint `rpc` uses)
- `rpc` — make JSON-RPC calls. `qn rpc call <method> [json-params]` calls the
  account's Tooling Access endpoint (params is a JSON array or object inline, or
  `--params-file <PATH>` / `-f` to read from a file, or `-` for stdin); the
  session JWT is minted and refreshed automatically. On a
  not-yet-enabled account it auto-enables with `--yes` (or prompts on a TTY).
  Multichain: `--network <key>` targets a specific chain by its key (e.g.
  `solana-mainnet`, `polygon`); `qn rpc list-networks` (alias `ls`) lists the
  available keys. Custom endpoint: `--endpoint-url <URL>` (or `[rpc] endpoint_url`
  in config) sends the call to a fully-formed HTTP URL that authenticates itself
  (no token minted); it's mutually exclusive with `--network`.
  **Paid lane**: use a gateway micropayment instead of an API key, login, or
  Tooling Access. Choose one mode before building the command:

  | Mode | Use it when | Call flag | What pays |
  |------|-------------|-----------|-----------|
  | x402 per request | You make a small number of calls. | `--x402` | A signed payment on each call. |
  | MPP per request | You make a small number of calls through Tempo. | `--mpp` | A signed Tempo payment on each call. |
  | x402 drawdown | You want prepaid credits and no per-call signing. | `--x402-drawdown` | One credit per successful response. |
  | MPP session | You want repeated calls from a funded Tempo channel. | `--mpp-session` | A cumulative voucher from the channel. |

  Start with discovery. These commands need no API key:

  ```sh
  qn rpc x402 supported-networks
  qn rpc x402 supported-payments
  qn rpc mpp supported-networks
  qn rpc mpp supported-payments
  ```

  Use a supported gateway slug for `--network`. It selects the chain the
  gateway call queries. Use `--payment-network` for the chain that settles the
  payment. They can differ. For example, `--network ethereum-mainnet` can query
  Ethereum while `--payment-network base-sepolia` settles an x402 payment.

  `--payment-asset` accepts a token symbol, EVM contract address, or Solana
  mint. `--max-amount` sets the per-call or per-action ceiling in integer base
  units. An offer above that ceiling is refused before signing. The CLI has no
  default ceiling.

  The key source precedence is `--payment-key-file` > `--payment-wallet` >
  `key_file` > `wallet` in `[rpc.payment]`. Keys come from a file or a stored
  wallet. The CLI does not read payment keys from environment variables,
  command-line values, or inline config. Config supplies values but never
  activates a mode; the call still needs `--x402`, `--mpp`,
  `--x402-drawdown`, or `--mpp-session`.

  `--receipt` changes paid-call stdout to
  `{"result": ..., "payment_receipt": ...}`. MPP includes the settlement
  reference. x402 returns `null`. Without `--receipt`, paid calls use the same
  result shape as unpaid calls. Paid calls cannot use `--endpoint-url`.

  **x402 drawdown** uses a cached gateway session. `qn rpc x402 buy-credits`
  signs the credit purchase and requires the full payment flags. `balance` and
  `drip` authenticate the wallet but do not sign a payment, so they need only
  the wallet and payment network. `drip` works on Base Sepolia only. Fund
  Solana wallets out of band. `buy-credits` is gated and needs `--yes` in a
  script. `qn rpc call --x402-drawdown` needs the query network and wallet; it
  uses one credit after a successful response and does not need an asset or
  spend ceiling. The pay network defaults to the query network. Credits can pay
  for calls to any supported query network.

  **MPP session** uses a cached Tempo escrow channel. `open --deposit` funds
  the channel, `top-up --deposit` adds funds, `status` reads the local record,
  and `close` settles and refunds the unused balance. These lifecycle commands
  identify the channel with `--payment-network` and `--payment-asset`; they do
  not take a query `--network`. `status --verify` contacts the gateway and
  spends one request unit. `--mpp-session` needs an open channel and adds the
  query `--network`. The channel can fund calls to any supported query network.
  `open`, `top-up`, and `close` are gated. A lost channel record under
  `<config-dir>/qn/channels.toml` requires opening a new channel.
- `wallet` — the local store of payment wallets for the paid RPC lane; no API
  key or login required. `qn wallet generate --vm <evm|svm> --name <NAME>`
  creates and stores a dedicated payment wallet (raw key at 0600 under
  `<config-dir>/qn/wallets/`, `evm` also covers MPP/Tempo), printing its
  address (and a QR to fund it on a terminal); `qn wallet list`/`show <NAME>`
  display stored wallets (address only, never the key) and the key file path;
  `qn wallet rm <NAME>` deletes one (gated: `--yes`, or exit 5 in scripts).
  Reference a wallet on a paid call with `--payment-wallet <NAME>`. These
  wallets live only on this machine — Quicknode does not hold, back up, or
  recover them; backing up the key file is the user's job.

Drill into any level with `--help`: `qn endpoint --help`, `qn endpoint security --help`,
`qn endpoint rate-limit --help`. Shell completions: `qn completions <bash|zsh|fish|...>`.

## 7. Common workflows

Capture the `id` (and any URL) from each create response and chain it into the next call.
Run `show` before a state change so you act on the current state, not an assumed one.

**Provision an endpoint and rate-limit it:**

```sh
qn endpoint create --chain ethereum --network mainnet   # → id, http_url, wss_url
qn endpoint show <id>                                    # inspect before modifying
qn endpoint rate-limit set <id> --rps 50
qn endpoint show <id>                                    # verify
```

**Create a stream (paused), inspect it, then activate:**

```sh
qn stream create --name my-stream --network ethereum-mainnet \
  --dataset block --start 15301579 --end 25301589 \
  --batch-size 2 --fix-block-reorgs 1 \
  --notification-email you@example.com --status paused \
  --webhook https://hook.example.com --region usa-east   # → id
qn stream show <id>                                       # inspect while paused
qn stream activate <id>
```

**Create a webhook from a template:**

```sh
qn webhook create --name wallet-watch --network ethereum-mainnet \
  --url https://hook.example.com --compression none --template evm-wallet \
  --wallet 0xabc...                                      # → id
qn webhook show <id>                                     # inspect before activating
qn webhook activate <id>
```

`--compression` (`gzip` or `none`) is required on create. Instead of inline
values, a template can reference a saved list with the matching
`--*-list-name` flag (e.g. `--wallets-list-name`, `--accounts-list-name`,
`--contracts-list-name`); supply either the inline flag or the list-name flag,
not both.

**KV put / get / list:**

```sh
qn kv set put my-key my-value
qn kv set get my-key
qn kv set list
```

**Make on-chain calls (no endpoint to provision):**

```sh
qn tooling-access enable --yes        # one-time; idempotent, admin role required
qn rpc call eth_blockNumber           # → "0x…" (default network)
qn rpc call eth_getBalance '["0xabc...", "latest"]'
qn rpc list-networks                  # available network keys for this endpoint
qn rpc call getSlot --network solana-mainnet
qn rpc call eth_blockNumber --endpoint-url https://my-endpoint.example/rpc
```

`qn rpc call` mints and refreshes the session JWT for you; the only one-time step
is enabling Tooling Access (or pass `--yes` to enable on first use). A custom
`--endpoint-url` (or `[rpc] endpoint_url` in config) bypasses that entirely.

**Choose a paid RPC mode:**

Discovery and wallet setup come first. Fund the address printed by
`qn wallet generate` before you run a paid command.

```sh
qn rpc x402 supported-networks
qn rpc x402 supported-payments
qn rpc mpp supported-networks
qn rpc mpp supported-payments
qn wallet generate --vm evm --name payer
```

**x402 per request:** sign one payment for each call. Use this for occasional
calls. The query network and settlement network can differ.

```sh
qn rpc call eth_blockNumber --network ethereum-mainnet --x402 \
  --payment-wallet payer --payment-network base-sepolia \
  --payment-asset USDC --max-amount 1000
```

**MPP per request:** pay each call on Tempo. Use the same EVM wallet and add
`--receipt` when you need the settlement reference.

```sh
qn rpc call eth_blockNumber --network ethereum-mainnet --mpp --receipt \
  --payment-wallet payer --payment-network tempo-testnet \
  --payment-asset USDC --max-amount 1000
```

**x402 drawdown:** buy credits once, then spend one credit per successful call.
Use this when you want to avoid signing each call.

```sh
qn rpc x402 buy-credits --network ethereum-mainnet --yes \
  --payment-wallet payer --payment-network base-sepolia \
  --payment-asset USDC --max-amount 10000000
qn rpc x402 balance --payment-wallet payer --payment-network base-sepolia
qn rpc call eth_blockNumber --network ethereum-mainnet --x402-drawdown \
  --payment-wallet payer
```

**MPP session:** deposit into a Tempo channel, then pay with cumulative
vouchers. Use this for repeated calls. The channel's payment network and asset
identify the channel; the call's `--network` identifies the query chain.

```sh
qn rpc mpp open --deposit 1000000 --yes \
  --payment-wallet payer --payment-network tempo-testnet \
  --payment-asset USDC --max-amount 1000000
qn rpc call eth_blockNumber --network ethereum-mainnet --mpp-session \
  --payment-wallet payer --payment-network tempo-testnet \
  --payment-asset USDC --max-amount 1000000
qn rpc mpp status --payment-wallet payer \
  --payment-network tempo-testnet --payment-asset USDC --max-amount 1000000
```

Use `qn rpc mpp top-up` after the channel runs low. Use `qn rpc mpp close` to
settle the channel and refund its unused balance. Both commands need the same
channel flags and `--yes` in a script.

For Solana x402, generate an SVM wallet and set both networks to
`solana-devnet`. Set `--svm-rpc-url` when the public Solana RPC rate-limits the
payment build.

## 8. Gotchas & safety rails

- Mutations are never retried; re-running a failed create can double-provision (§5).
- Paid `rpc call` moves real funds and never auto-retries; exit 3 means the
  payment may have settled — check the wallet before re-running (§3, §5). The
  CLI never prints the payment key; it comes only from a key file or a stored
  wallet (never an env var, never argv, never inline in config).
- No account-wide wipe command exists by design (§4).
- Piped output defaults to `json`; pass `-o toon` for the compact LLM form (§2).
- `--base-url` overrides the API host; it exists for testing.
- For *this* command, `-o yaml`/`-o toon`/`-o table` print Markdown (with a note on
  stderr); `-o json` produces the `{version, guide}` envelope.

## 9. More

- `qn --help`, and `--help` at every noun/verb level, document flags exhaustively.
- Docs: https://www.quicknode.com/docs
- This guide self-describes its version: it matches qn v{{VERSION}}.