---
title: "CLI reference: commands, options, exit codes | Settlens"
description: "Settlens CLI reference: scan, facilitator, check, verify-report, verify-payment, monitor, evidence and mcp, with every option, default and exit code."
url: https://settlens.com/docs/cli
last_updated: 2026-10-14
---

# CLI reference

> **In short:** The Settlens CLI (src/cli.js, Node.js 20.19 or newer) has eight commands: scan, facilitator, check, verify-report, verify-payment, monitor, evidence and mcp. Exit code 0 means success, 1 a failed gate or an invalid result, and 2 a usage, configuration or safety error.

Every Settlens command and option, with defaults, exit codes and real output from the bundled demo target.

The Settlens CLI is one Node.js program, `src/cli.js` (version 0.5.0). It needs Node.js 20.19 or newer and no wallet or payment key; the only private key it reads is your ed25519 evidence key, in `evidence attest`. Passive scanning is the default; nothing it does calls a facilitator's `/settle` or moves funds. The code is in a private repository that pilot participants receive; it is not published on npm.

> **settlens in these docs**
>
> Examples write `settlens` for `node /path/to/settlens/src/cli.js`. Inside the repository, `npm run settlens -- <args>` does the same. An alias keeps the examples copy-pasteable:

**Run from the repository root**

```shell
alias settlens="node $PWD/src/cli.js"
settlens --version
```

## Synopsis

The usage block printed by `settlens --help`:

**settlens --help (usage)**

```text
settlens scan <url> [options]
settlens facilitator <base-url> [options]
settlens check --config <file> [options]
settlens preflight <payment-required.txt> --policy <policy.json> --resource-url <url>
settlens verify-report <report.json>
settlens verify-payment <payment.json> [--now <unix-seconds|ISO-8601>]
settlens monitor --config <file> [--state <file>] [--webhook <url>]
settlens history --history <journal.json> [--format json|html] [--out <file>]
settlens reference --history <journal.json> --target <url> --digest <reviewed-digest>
settlens incidents --history <journal.json> [--incident <id> --status open|acknowledged --comment <text>]
settlens notifications --history <journal.json> [--retry <id>] [--webhook <url>]
settlens evidence keygen [--out <key.pem>]
settlens evidence attest <report.json> --key <key.pem> [--out <file>]
settlens evidence verify <attestation.json> [--report <report.json>] [--expect-key <public-key.pem>]
settlens mcp
settlens --help
```

## Argument syntax

- Options take their value as the next argument: `--fail-on high`. The `--fail-on=high` form is not supported and is reported as an unknown option.
- A value cannot start with `--`; the CLI reports `Missing value for --option.`
- `--header`, `--allow-host` and the `--expect-*` options are repeatable. The `--expect-*` options also accept comma-separated lists.
- Unknown options and unknown commands stop the run with exit code 2 before any request is sent.

## Exit codes

_Exit codes for every command_

| Code | Meaning |
| --- | --- |
| 0 | Success. `scan`, `facilitator` and `check`: no failing check at or above `--fail-on`. `verify-report` and `evidence verify`: valid. `verify-payment`: verified. `monitor`: no blocking regression. `evidence keygen`, `evidence attest`, `--help`, `--version` and `mcp`: completed. |
| 1 | The gate failed: a failing check at or above the threshold, an `INVALID` report or attestation, a `REJECTED` payment, or a blocking monitor alert. An unreachable endpoint is a failing `transport.reachable` check (high), so it exits 1 at the default threshold. |
| 2 | Usage, configuration or safety error, printed as `Settlens error: …` on stderr: unknown command or option, missing value or file, invalid JSON or config, `--active` without `--authorized` and `--authorization-ref`, a `PAYMENT-SIGNATURE` header, a custom header sent to a host that is not allowlisted, an existing file given to `evidence keygen --out`, an invalid `monitor --fail-on`, or a malformed `--expect-key`. |

## Commands

### scan

Assesses one paid resource. By default the scan is passive: it sends ordinary unauthenticated requests (two by default), does not follow redirects, reads at most 1 MiB of each response and never sends `PAYMENT-SIGNATURE`. The checks it runs are listed in the [check catalog](https://settlens.com/docs/checks).

**Syntax**

```shell
settlens scan <url> [options]
```

**Passive scan of the compliant demo endpoint (exit 0; absolute paths shortened)**

```text
$ settlens scan http://127.0.0.1:4402/secure
Settlens x402 assessment 8ef6b907
Targets 1 · Active 0 · Settlement calls 0
 
127.0.0.1  GET http://127.0.0.1:4402/secure
13 pass · 0 fail · 0 warn · 0 skip
 
Total: 13 pass · 0 fail · 0 warn · 0 skip
 
Reports:
  …/reports/settlens-8ef6b907.json
  …/reports/settlens-8ef6b907.html
  …/reports/settlens-8ef6b907.sarif
```

Add a local policy with the `--expect-*` options and `--max-amount`. Every option the server advertises must satisfy the policy; one non-compliant option fails the check. The demo's `/drift` endpoint alternates its price between two requests and advertises Base Sepolia (`eip155:84532`), so a mainnet policy fails:

**Policy and drift findings (exit 1)**

```text
$ settlens scan http://127.0.0.1:4402/drift \
    --expect-network eip155:8453 --max-amount 5000
Settlens x402 assessment 7093ee3c
Targets 1 · Active 0 · Settlement calls 0
 
127.0.0.1  GET http://127.0.0.1:4402/drift
12 pass · 2 fail · 1 warn · 0 skip
  FAIL high     Networks match the local policy
       Unexpected networks: eip155:84532.
  FAIL high     Amounts stay within the approved ceiling
       1 payment amount(s) exceed 5000.
  WARN medium   Payment requirements remain stable
       Payment terms changed between identical unauthenticated requests.
 
Total: 12 pass · 2 fail · 1 warn · 0 skip
```

With the endpoint owner's written approval, `--active --authorized --authorization-ref <id>` adds one request carrying an intentionally invalid `PAYMENT-SIGNATURE`. The demo's `/bypass` endpoint trusts the mere presence of the header, which is the critical finding the probe exists to catch:

**Authorized active probe against a deliberately vulnerable endpoint (exit 1)**

```text
$ settlens scan http://127.0.0.1:4402/bypass \
    --active --authorized --authorization-ref DEMO-APPROVAL-002 --no-write
Settlens x402 assessment 89ea5946
Targets 1 · Active 1 · Settlement calls 0
 
127.0.0.1  GET http://127.0.0.1:4402/bypass
13 pass · 1 fail · 1 warn · 0 skip
  FAIL critical Invalid payment authorization is denied
       The endpoint returned HTTP 200 after an invalid payment authorization.
  WARN medium   Invalid payment uses a standard failure status
       Expected HTTP 400 or 402 for invalid payment, received HTTP 200.
 
Total: 13 pass · 1 fail · 1 warn · 0 skip
```

> **Authorized testing only**
>
> Run the active probe only against endpoints you own or have written permission to test, and record the approval in `--authorization-ref`. It never calls `/settle` and needs no key, but it is still traffic the owner must approve. See the [methodology](https://settlens.com/docs/methodology#active-probe).

To reach a gateway that needs authentication, pass a header and allowlist its destination host. Without the allowlist the CLI refuses to send it:

**Custom header with an allowlisted host**

```shell
settlens scan https://merchant.example/paid \
  --header "Authorization: Bearer $ASSESSMENT_TOKEN" \
  --allow-host merchant.example
```

In CI, set the same exact hostnames in `SETTLENS_ALLOWED_HOSTS` (comma-separated) instead, outside the configuration file; the GitHub Action does this through its `allowed-hosts` input.

### facilitator

Assesses a facilitator on its own by reading `GET <base-url>/supported`: reachability, response size, HTTP 200, JSON media type, HTTPS, the SupportedResponse shape, x402 V2 capability and duplicate kinds. It never calls `/verify` or `/settle`. To check that a facilitator covers what a resource advertises, use `scan --facilitator` instead. What these checks can and cannot establish about a facilitator: [x402 facilitator security: /verify and /settle](https://settlens.com/learn/x402-facilitator-security).

**Syntax**

```shell
settlens facilitator <base-url> [options]
```

**Facilitator capability scan (exit 0)**

```text
$ settlens facilitator http://127.0.0.1:4402/facilitator --no-write
Settlens x402 assessment 0950222c
Targets 1 · Active 0 · Settlement calls 0
 
127.0.0.1  GET http://127.0.0.1:4402/facilitator/supported
8 pass · 0 fail · 0 warn · 0 skip
 
Total: 8 pass · 0 fail · 0 warn · 0 skip
```

### check

Runs every target of a [configuration file](https://settlens.com/docs/configuration) and writes one report covering all of them. This is the command the [GitHub Action](https://settlens.com/docs/github-action) runs. `--out` and `--fail-on` override the file's `output` and `failOn`; `--timeout` and `--repeat` override each target's values; `--active --authorized --authorization-ref` applies the probe to every target.

**Syntax**

```shell
settlens check --config <file> [options]
```

**The repository's example config against the demo server (exit 0)**

```text
$ settlens check --config settlens.config.example.json
Settlens x402 assessment bfd83874
Targets 1 · Active 0 · Settlement calls 0
 
local-secure-demo  GET http://127.0.0.1:4402/secure
28 pass · 0 fail · 0 warn · 0 skip
 
Total: 28 pass · 0 fail · 0 warn · 0 skip
```

### verify-report

Recomputes the SHA-256 digest of a JSON report and compares it with the report's `integrity` block. It works offline. Exit 0 means the content is unchanged since the digest was written; it does not say who wrote the report. For that, sign it with [evidence attest](https://settlens.com/docs/evidence). How the digest is computed is described in [Reports](https://settlens.com/docs/reports#integrity).

**Syntax**

```shell
settlens verify-report <report.json>
```

**An intact report (exit 0) and an edited copy (exit 1)**

```text
$ settlens verify-report reports/settlens-8ef6b907.json
VALID Report content matches its SHA-256 evidence digest.
Expected: 646b3d941885b8bf1cb50ff4f55a24b0635b936ba233d24957c235bf1ce4f1ef
Actual:   646b3d941885b8bf1cb50ff4f55a24b0635b936ba233d24957c235bf1ce4f1ef
$ settlens verify-report tampered.json
INVALID Report content was modified after the evidence digest was created.
Expected: 646b3d941885b8bf1cb50ff4f55a24b0635b936ba233d24957c235bf1ce4f1ef
Actual:   f084495caab4f2db67460c33f7de67542dac55f84c87db6a536d97739cffd55a
```

A file without a Settlens integrity block prints `INVALID Report does not contain a supported Settlens integrity block.` and exits 1.

### verify-payment

Checks a captured payment authorization offline, with no RPC. The file holds the advertised requirement (one `accepts` entry) and the payment payload. The command also accepts `paymentRequirements` instead of `requirement`, and `paymentPayload` (a full PaymentPayload object) instead of `payload`.

- **EVM `exact` scheme** (`eip155:*` networks): rebuilds the EIP-712 domain from `requirement.extra.name`, `requirement.extra.version`, `requirement.asset` and the chain id, recovers the EIP-3009 `TransferWithAuthorization` signer and requires it to equal `authorization.from`. High-s (malleable) signatures are rejected. It then checks that `to` equals `payTo`, `value` equals `amount`, and that the check time is strictly between `validAfter` and `validBefore` (`validAfter < now < validBefore`, as EIP-3009 requires). The check time is the current clock, or `--now`. Because the asset is the EIP-712 verifying contract, a signature made for another token does not recover to `from`.
- **Solana** (`solana:*` networks): checks every signature slot of a Base64 legacy or versioned transaction (`payload.transaction`) against its account key with ed25519. Empty slots are reported as pending. Without payment terms, the verdict explicitly covers signatures only: at least one signature must be present, every present signature must be valid and the slot count must match the message header. Supplying `asset`, `amount`, `payTo` and `extra.feePayer` also requires the supported offline SPL TransferChecked profile. A rejected or unverified payment profile exits 1 even when signatures are valid. Partial payment terms exit 2 rather than falling back to signatures only. Static instruction checks do not establish runtime execution, balances, replay protection or settlement; unsupported instructions, lookup tables and token extensions remain unverified.

The fields and the EIP-712 domain are explained in [EIP-3009 transferWithAuthorization for x402](https://settlens.com/learn/eip-3009). To check one authorization in the browser: [EIP-3009 signature verifier](https://settlens.com/tools/eip-3009-verifier).

**payment.json (signature and nonce shortened)**

```json
{
  "requirement": {
    "scheme": "exact",
    "network": "eip155:84532",
    "amount": "10000",
    "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
    "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
    "maxTimeoutSeconds": 60,
    "extra": { "name": "USDC", "version": "2" }
  },
  "payload": {
    "signature": "0x03d6ea79…e506221b",
    "authorization": {
      "from": "0x19e7e376e7c213b7e7e7e46cc70a5dd086daff2a",
      "to": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
      "value": "10000",
      "validAfter": "1791885175",
      "validBefore": "1791888835",
      "nonce": "0x2222…2222"
    }
  }
}
```

**A valid authorization (exit 0) and the same signature against another recipient (exit 1)**

```text
$ settlens verify-payment payment.json --now 2026-10-13T10:00:00Z
VERIFIED exact EVM payment authorization
Recovered signer: 0x19e7e376e7c213b7e7e7e46cc70a5dd086daff2a
Signature valid:  true
Recipient bound:  true
Amount bound:     true
Within window:    true (at 1791885600)
$ settlens verify-payment payment-wrong-recipient.json --now 2026-10-13T10:00:00Z
REJECTED exact EVM payment authorization
Recovered signer: 0x19e7e376e7c213b7e7e7e46cc70a5dd086daff2a
Signature valid:  true
Recipient bound:  false
Amount bound:     true
Within window:    true (at 1791885600)
Reasons:
  - authorization.to does not match requirement.payTo.
```

> **What verify-payment does not check**
>
> It does not read the chain: no balance check, no on-chain nonce or replay check and no settlement check. Other networks exit 2 with "verify-payment supports the exact EVM (eip155) and Solana schemes."

### monitor

Runs a passive scan of every configured target, compares it with the previous run stored in `--state`, prints alerts (regressions, new findings and removed checks) and exits 1 when one reaches `--fail-on`. `--webhook` posts the alerts as JSON. Monitoring is always passive, even if `--active` is given. Full usage, the state file and the webhook payload are in [Monitor](https://settlens.com/docs/monitor).

**Syntax**

```shell
settlens monitor --config <file> [--state <file>] [--webhook <url>] [--fail-on <severity>] [--timeout <ms>]
```

### evidence keygen, attest, verify

Signs a report digest with an ed25519 key and verifies the result offline. `keygen` writes a PKCS#8 PEM private key (with `--out`, to a new file with mode 0600; it refuses to overwrite an existing file and exits 2; otherwise to stdout) and prints the public key; `attest` signs a report; `verify` checks an attestation and, with `--report`, that the report is intact and is the one attested, and with `--expect-key`, that it was signed by the key you trust. Walkthrough and key management: [Evidence](https://settlens.com/docs/evidence).

**Syntax**

```shell
settlens evidence keygen [--out <key.pem>]
settlens evidence attest <report.json> --key <key.pem> [--out <file>]
settlens evidence verify <attestation.json> [--report <report.json>] [--expect-key <public-key.pem>]
```

### mcp

Starts the Settlens MCP server over stdio for Claude Desktop, Claude Code or any MCP client, so an agent can check an x402 payment request before paying. Stdout carries protocol messages only. The server exposes the offline verification tools and the passive network tools; it never signs or pays. Setup, tools and the remote endpoint: [MCP server](https://settlens.com/docs/mcp).

**Syntax**

```shell
settlens mcp
```

## Options

The options printed by `settlens --help`, in the same order. Every command accepts the same option names; each entry says which commands read it, others ignore it.

- `--method <verb>`: HTTP method. Letters only, upper-cased. A body is refused with GET and HEAD. Default `GET`. _Read by scan._
- `--name <label>`: Human-readable target name. Defaults to the URL hostname. _Read by scan, facilitator._
- `--header <name:value>`: Add a request header; repeatable. Format "Name: value", split at the first colon. Values never reach a report (only header names do). PAYMENT-SIGNATURE is refused. _Read by scan, facilitator._
- `--allow-host <hostname>`: Permit custom headers to this exact host; repeatable. Exact hostname, case-insensitive, without port. Required for every host that receives a custom header. _Read by scan, facilitator, check, monitor._
- `--body <json-or-text>`: Request body. Sent as is. Use with --method POST (or another method that takes a body). _Read by scan._
- `--facilitator <base-url>`: Cross-check requirements with GET /supported. Base URL; Settlens requests \<base>/supported and adds the facilitator and coverage checks. With an authorized active probe it also POSTs the invalid payload to \<base>/verify. _Read by scan._
- `--timeout <ms>`: Per-request timeout. Positive integer in milliseconds; overrides timeoutMs from a config file. Default `8000`. _Read by scan, facilitator, check, monitor._
- `--repeat <count>`: Passive samples used for drift detection. Positive integer; overrides repeat from a config file. 1 skips the stability comparison. Default `2`. _Read by scan, check._
- `--expect-scheme <value>`: Allowed scheme; repeatable or comma-separated. _Read by scan._
- `--expect-network <value>`: Allowed CAIP-2 network; repeatable or comma-separated. _Read by scan._
- `--expect-pay-to <value>`: Allowed recipient; repeatable or comma-separated. _Read by scan._
- `--expect-asset <value>`: Allowed asset; repeatable or comma-separated. _Read by scan._
- `--policy <file>`: Local agent policy (payTo, assets, networks, maxAmount).
- `--resource-url <url>`: Exact requested URL for offline preflight.
- `--max-amount <atomic>`: Maximum advertised atomic token amount. Integer in the asset's atomic units, compared with every advertised amount. _Read by scan._
- `--active`: Send one intentionally invalid payment probe. Requires --authorized and --authorization-ref. Sends one intentionally invalid PAYMENT-SIGNATURE. _Read by scan, check._
- `--authorized`: Confirm the endpoint owner authorized active testing. Accepted only together with --active. _Read by scan, check._
- `--authorization-ref <id>`: Approval ticket/email/scope reference for active mode. Recorded in the report under targets\[\].authorization.reference. _Read by scan, check._
- `--out <directory>`: Report directory. Created if missing. Report files are named settlens-\<reportId>.\<format>. Default `reports`. _Read by scan, facilitator, check; evidence keygen and attest (output file)._
- `--format <list>`: json,html,sarif. Any subset of json, html and sarif, comma-separated. Default `json,html,sarif`. _Read by scan, facilitator, check._
- `--fail-on <severity>`: low|medium|high|critical|none. Exit 1 when a failing check has this severity or higher. none never fails. Default `high`. _Read by scan, facilitator, check, monitor._
- `--no-write`: Do not create report files. Prints the console summary only. _Read by scan, facilitator, check._
- `--history <file>`: Persistent monitor journal with bounded history.
- `--webhook-secret-env <name>`: Environment variable containing the signing secret.

### Command-specific options

Options that are not in the help text's option list:

- `--config <file>`: Path to a JSON configuration file. Required by both commands. _Read by check, monitor._
- `--state <file>`: JSON file holding the previous run. Read if present, rewritten after every run. _Read by monitor._
- `--webhook <url>`: URL that receives a JSON POST when at least one blocking alert is raised. _Read by monitor._
- `--now <unix-seconds|ISO-8601>`: Time at which the EVM validity window is checked, for example the moment a capture was used. Default: the current clock. The output prints the time used. _Read by verify-payment._
- `--key <key.pem>`: PKCS#8 PEM ed25519 private key created by evidence keygen. _Read by evidence attest._
- `--report <report.json>`: Report to compare with the attestation's digest. _Read by evidence verify._
- `--expect-key <public-key.pem>`: The signer you trust: an ed25519 PEM public key or a file holding the 0x hex key printed by evidence keygen. An attestation signed by any other key is INVALID; a malformed or non-ed25519 key exits 2. _Read by evidence verify._
- `--version`: Prints the CLI version and exits 0. _Read by all._
- `--help`: Prints the usage text and exits 0. Running settlens with no arguments does the same. _Read by all._

## Environment variables

- `SETTLENS_ALLOWED_HOSTS`: comma-separated exact hostnames allowed to receive custom headers, added to any `--allow-host` values. It lives outside the config file on purpose, so a modified config cannot send secrets to a new host.
- `NO_COLOR`: disables ANSI colors. Colors are also off whenever stdout is not a terminal.
- `${NAME}` inside a config file: expanded from the environment when the file is loaded; a missing variable is an error. See [Configuration](https://settlens.com/docs/configuration#environment-variables).
- `SETTLENS_DEMO_PORT`: port of the local demo server started by `npm run demo:server` (default 4402).

## Safety rules the CLI enforces

- Passive mode never sends `PAYMENT-SIGNATURE`, and a user-supplied `PAYMENT-SIGNATURE` header is refused in options and config files.
- The active probe needs `--active`, `--authorized` and a non-empty `--authorization-ref`; `--authorized` alone is an error.
- Redirects are never followed; a 3xx answer is reported with its sanitized `Location`.
- URLs with embedded credentials are refused. Reports keep request header names but not their values, and redact the values of common secret query parameters (`token`, `api_key`, `signature`, `secret`…).
- No command calls `/settle`, signs a payment or needs a wallet. Every report records `settlementCalls: 0` and `privateKeysUsed: 0`.

## Run in a container

The repository's `Dockerfile` builds a non-root image (user `node`) on a digest-pinned `node:24-alpine` base, with production dependencies installed from the lockfile and install scripts disabled. The entrypoint is the CLI and the working directory is `/workspace`.

**Build and run the image**

```shell
docker build -t settlens:local .
docker run --rm settlens:local --version
docker run --rm -v "$PWD:/workspace" settlens:local check --config settlens.config.json
```

The container runs as UID 1000, so a mounted directory must be writable by that user for reports to be saved. Inside a container, `127.0.0.1` is the container itself, not the host running the demo server.

Next: write a [configuration file](https://settlens.com/docs/configuration), read the [report formats](https://settlens.com/docs/reports), or gate pull requests with the [GitHub Action](https://settlens.com/docs/github-action).

## Sources

1. [x402 Protocol Specification, version 2](https://github.com/x402-foundation/x402/blob/main/specs/x402-specification-v2.md) — x402 Foundation
2. [x402 V2 HTTP transport](https://github.com/x402-foundation/x402/blob/main/specs/transports-v2/http.md) — x402 Foundation
3. [ERC-3009: Transfer With Authorization](https://eips.ethereum.org/EIPS/eip-3009) — Ethereum Improvement Proposals
4. [EIP-712: Typed structured data hashing and signing](https://eips.ethereum.org/EIPS/eip-712) — Ethereum Improvement Proposals
5. [RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA)](https://www.rfc-editor.org/rfc/rfc8032.html) — IRTF
