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:
alias settlens="node $PWD/src/cli.js"
settlens --version
Synopsis
The usage block printed by settlens --help:
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=highform is not supported and is reported as an unknown option. - A value cannot start with
--; the CLI reportsMissing value for --option. --header,--allow-hostand 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
| 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.
settlens scan <url> [options]
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:
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:
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:
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.
settlens facilitator <base-url> [options]
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.
settlens check --config <file> [options]
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.
settlens verify-report <report.json>
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
exactscheme (eip155:*networks): rebuilds the EIP-712 domain fromrequirement.extra.name,requirement.extra.version,requirement.assetand the chain id, recovers the EIP-3009TransferWithAuthorizationsigner and requires it to equalauthorization.from. High-s (malleable) signatures are rejected. It then checks thattoequalspayTo,valueequalsamount, and that the check time is strictly betweenvalidAfterandvalidBefore(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 tofrom. - 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. Supplyingasset,amount,payToandextra.feePayeralso 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.
{
"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"
}
}
}
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.
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.
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.
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. DefaultGET. 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. Default8000. 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. Default2. 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>. Defaultreports. 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. Defaultjson,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. Defaulthigh. 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-hostvalues. 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 bynpm run demo:server(default 4402).
Safety rules the CLI enforces
- Passive mode never sends
PAYMENT-SIGNATURE, and a user-suppliedPAYMENT-SIGNATUREheader is refused in options and config files. - The active probe needs
--active,--authorizedand a non-empty--authorization-ref;--authorizedalone 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 recordssettlementCalls: 0andprivateKeysUsed: 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.
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
Last updated