Documentation menu

CLI reference

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

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.

On this page

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:

ShellRun from the repository root
alias settlens="node $PWD/src/cli.js"
settlens --version

Synopsis

The usage block printed by settlens --help:

Textsettlens --help (usage)
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
CodeMeaning
0Success. 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.
1The 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.
2Usage, 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.

ShellSyntax
settlens scan <url> [options]
Passive scan of the compliant demo endpoint (exit 0; absolute paths shortened)
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)
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)
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.

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

ShellCustom header with an allowlisted host
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.

ShellSyntax
settlens facilitator <base-url> [options]
Facilitator capability scan (exit 0)
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 and writes one report covering all of them. This is the command the 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.

ShellSyntax
settlens check --config <file> [options]
The repository's example config against the demo server (exit 0)
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. How the digest is computed is described in Reports.

ShellSyntax
settlens verify-report <report.json>
An intact report (exit 0) and an edited copy (exit 1)
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. To check one authorization in the browser: EIP-3009 signature verifier.

JSONpayment.json (signature and nonce shortened)
{
  "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)
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.

ShellSyntax
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.

ShellSyntax
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.

ShellSyntax
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.
  • 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.

ShellBuild and run the image
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, read the report formats, or gate pull requests with the GitHub Action.

Sources

  1. x402 Protocol Specification, version 2x402 Foundation · github.com
  2. x402 V2 HTTP transportx402 Foundation · github.com
  3. ERC-3009: Transfer With AuthorizationEthereum Improvement Proposals · eips.ethereum.org
  4. EIP-712: Typed structured data hashing and signingEthereum Improvement Proposals · eips.ethereum.org
  5. RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA)IRTF · rfc-editor.org

Last updated