Test your x402 facilitator without moving funds

For operators of x402 facilitators. Settlens reads GET /supported, checks it against the terms resources actually advertise and, with your authorization, confirms that /verify rejects an invalid signature. It never calls /settle.

Real output from the bundled demo, whose /facilitator-accept route is built to accept any signature.

Authorized /verify probe
settlens scan http://127.0.0.1:4402/secure \
    --facilitator http://127.0.0.1:4402/facilitator-accept \
    --active --authorized --authorization-ref PILOT-FAC-001 --no-write
Settlens x402 assessment f6968418
Targets 1 · Active 1 · Settlement calls 0
 
127.0.0.1  GET http://127.0.0.1:4402/secure
26 pass · 1 fail · 0 warn · 0 skip
  FAIL critical Facilitator /verify rejects an invalid signature
       The facilitator reported isValid=true for an intentionally invalid, all-zero signature.
 
Total: 26 pass · 1 fail · 0 warn · 0 skip

In short

Settlens tests an x402 facilitator without moving funds: it checks the GET /supported response, cross-checks it against the terms resources advertise and, with the operator's authorization, confirms that POST /verify rejects an intentionally invalid signature. It never calls /settle and needs no wallet or payment key.

Who this is for

You operate the service that x402 resource servers call to check and execute payments: GET /supported advertises the kinds, extensions and signers you handle, POST /verify says whether a payment payload is valid, and POST /settle executes it on chain.

Resource servers serve paid content based on your isValid answer. One verification bug becomes a payment bypass for every merchant that relies on you, and those merchants need a way to check your behavior without taking your word for it. Our guide to x402 facilitator security covers what each endpoint must and must not do.

What goes wrong on a facilitator

Each failure mode maps to a check Settlens runs. The tag on each card is the check id you will see in reports.

  • /verify accepts a forged signature

    During an authorized probe, Settlens posts an intentionally invalid payload to /verify (an all-zero signature on EVM networks). isValid=true is a critical verification bypass.

    security.facilitator_rejects_invalid_signature

  • /verify answers in a non-standard shape

    Resource servers decide from isValid. An answer without a boolean isValid field risks being misread as success.

    facilitator.verify_response_schema

  • /supported breaks the core shape

    kinds must be a non-empty array with x402Version, scheme and network (CAIP-2 for V2 kinds), extensions an array of strings, and signers a map of networks to address lists.

    facilitator.supported_schema

  • No x402 V2 capability

    A facilitator without at least one kind with x402Version 2 cannot verify or settle V2 payments, whatever else it advertises.

    facilitator.v2_capability

  • Resources advertise what you cannot settle

    Every scheme and network pair a resource advertises must appear in your kinds for the same x402Version, or clients sign payments that can never be verified.

    facilitator.requirement_coverage

  • Signer metadata is missing

    Each advertised network needs a non-empty signer list, for the exact network or its namespace wildcard such as eip155:*.

    facilitator.signer_coverage

  • Capabilities over weak transport

    Settlens flags plain HTTP outside loopback, a non-JSON media type, duplicate kinds and responses above the 1 MiB evidence limit.

    facilitator.https

What Settlens sends, and what it never sends

The passive part reads public metadata. The active part is opt-in, needs an authorization reference and sends one invalid payload built from the resource's first advertised requirement.

For EVM networks the invalid payload carries an all-zero signature; for Solana, an all-zero transaction. The probe needs no wallet or payment key.

The Settlens workflow for facilitators

Start with your public capabilities, then cross-check them against a resource that uses you, then prove /verify fails closed.

  1. Scan GET /supported

    settlens facilitator https://facilitator.example.com checks reachability, HTTP 200, the JSON media type, HTTPS, the response size, the SupportedResponse schema, V2 capability and duplicate kinds.

  2. Cross-check a resource that uses you

    settlens scan <resource-url> --facilitator <base-url> adds coverage: every advertised scheme and network must be in your kinds, and every advertised network needs signers.

  3. Prove /verify fails closed

    Add --active --authorized --authorization-ref <ticket>. Settlens posts one invalid payload to /verify and checks that isValid is a boolean and is false.

  4. Gate releases and publish evidence

    Run the same configuration in CI on every change, then sign the report with an ed25519 key so integrators can verify it offline. See evidence.

JSONsettlens.config.json (illustrative values)
{
  "version": 1,
  "failOn": "high",
  "targets": [
    {
      "name": "reference-resource",
      "url": "https://api.staging.example.com/v1/forecast",
      "facilitator": {
        "name": "staging-facilitator",
        "url": "https://facilitator.staging.example.com",
        "timeoutMs": 8000,
        "headers": {
          "Authorization": "Bearer ${FACILITATOR_TOKEN}"
        }
      }
    }
  ]
}
ShellCI run with the authorized probe
settlens check --config settlens.config.json \
  --allow-host facilitator.staging.example.com \
  --active --authorized --authorization-ref CHG-2291

Secrets stay out of reports

${FACILITATOR_TOKEN} is expanded from the environment when the configuration loads and is never written to a report. Custom headers are refused unless their host is allowlisted with --allow-host or the Action's allowed-hosts input.

What the findings look like

Real output from the bundled demo. One facilitator covers the resource, one advertises only Base mainnet while the resource asks for Base Sepolia, and the offline verifier gives a second opinion on the all-zero signature.

GET /supported only
settlens facilitator http://127.0.0.1:4402/facilitator --no-write
Settlens x402 assessment 41fa3ca8
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
Coverage gap
settlens scan http://127.0.0.1:4402/secure \
    --facilitator http://127.0.0.1:4402/facilitator-empty --no-write
Settlens x402 assessment 7047aa73
Targets 1 · Active 0 · Settlement calls 0
 
127.0.0.1  GET http://127.0.0.1:4402/secure
22 pass · 1 fail · 0 warn · 0 skip
  FAIL high     Facilitator covers advertised payment requirements
       1 advertised payment choice(s) are absent from facilitator capabilities.
 
Total: 22 pass · 1 fail · 0 warn · 0 skip

A second opinion on your verifier

settlens verify-payment payment.json takes a requirement and a captured payload. For EIP-3009 authorizations of the exact EVM scheme it rebuilds the EIP-712 domain from the requirement, recovers the EIP-3009 signer and checks recipient, amount and the validity window, with no RPC. For Solana it checks the ed25519 signature in every signer slot and reports your fee-payer slot as pending until you sign it at settlement.

Run it on payloads your /verify accepted or rejected and compare the answers. Here it rejects the same all-zero signature the active probe sends. See Verify, and the EIP-3009 explainer for how the authorization and its EIP-712 domain are built.

Offline signature check of the invalid payload
settlens verify-payment payment.json --now 2026-10-13T10:00:00Z
REJECTED exact EVM payment authorization
Signature valid:  false
Recipient bound:  true
Amount bound:     true
Within window:    true (at 1791885600)
Reasons:
  - Signature verification failed: invalid signature r: out of range 1..Point.Fn.ORDER

Facilitator checks

Generated from the Settlens check catalog. Coverage and signer checks need a resource target; /verify checks need the authorized active probe.

Checks on an x402 facilitator
CheckWhat Settlens verifiesSeverity
facilitator.reachable
Facilitator /supported is reachable
GET <facilitator>/supported returned an HTTP response within the timeout. Redirects are not followed.high
facilitator.response_body_limit
Facilitator capability response fits the evidence limit
The /supported response is at most 1 MiB.high
facilitator.supported_status
Facilitator exposes capabilities successfully
GET /supported returned HTTP 200.high
facilitator.content_type
Facilitator capabilities use a JSON media type
The /supported Content-Type is application/json or another +json media type.medium
facilitator.https
Facilitator capability transport is protected
The facilitator URL uses HTTPS, or loopback HTTP for local testing.medium
facilitator.supported_schema
SupportedResponse matches the x402 core shape
The body has a non-empty kinds array (each with a positive integer x402Version, a scheme and a network, CAIP-2 for V2 kinds), an extensions array of strings and a signers object mapping networks to string arrays.high
facilitator.v2_capability
Facilitator advertises x402 V2 capabilities
At least one supported kind has x402Version 2.high
facilitator.duplicate_kinds
Facilitator capabilities are unambiguous
No x402Version, scheme and network combination appears twice in kinds.low
facilitator.requirement_coverage
Facilitator covers advertised payment requirements
Every scheme/network pair advertised by the resource appears in the facilitator's /supported kinds for the same x402Version. Skipped when /supported is invalid or unavailable.high
facilitator.signer_coverage
Facilitator publishes signer coverage
Every advertised network has a non-empty signer list in /supported, either for the exact network or for its namespace wildcard (for example eip155:*).medium
facilitator.verify_reachable
Facilitator /verify is reachable
During an authorized active probe, POST <facilitator>/verify with the intentionally invalid payload completed. Reported as a warning only when it could not complete.medium
facilitator.verify_response_schema
Facilitator /verify returns a conformant VerifyResponse
The /verify answer to the intentionally invalid payload is a JSON object with a boolean isValid field.high
security.facilitator_rejects_invalid_signature
Facilitator /verify rejects an invalid signature
/verify returns isValid=false for the intentionally invalid, all-zero signature. Settlens never calls /settle.critical

See the facilitator checks in the check reference for why each check matters and how to fix it, and the methodology for what a result proves.

What you get

  • Capability reports

    JSON with a SHA-256 integrity block, HTML and SARIF for every /supported scan. settlens facilitator keeps the validated /supported response, signer addresses included; a resource scan keeps the kinds, extensions and signer networks.

    Report format
  • Fail-closed evidence

    A report in active-authorized mode that records your authorization reference, zero settlement calls and zero private keys used.

    Assess
  • A release gate

    Run the same configuration on every change to your facilitator and fail the build on a high or critical finding.

    CI gate
  • Evidence for integrators

    Signed attestations that merchants and auditors can verify offline, without trusting your infrastructure.

    How auditors use it

Limits to keep in mind

Settlement is out of scope

Settlens never calls /settle, never submits or broadcasts a transaction and never moves funds. It does not test on-chain execution, gas handling, nonce use or replay protection.

  • The /verify probe sends one class of invalid payload. It shows that your facilitator refuses an all-zero signature, not that it handles every malformed or malicious payload.
  • The probe is built from a resource's advertised requirement, so it needs a resource target that names your facilitator.
  • Signer coverage checks that signer lists are published, not that the addresses are yours or funded.
  • verify-payment checks signatures and binding offline. It does not check balances, on-chain nonce use or settlement, and it covers EIP-3009 authorizations of the exact EVM scheme (not Permit2 or ERC-7710 payloads) and Solana transaction signatures.

Questions from facilitator operators

Does Settlens ever call /settle?

No. No Settlens command or MCP tool calls /settle. Reports record the number of settlement calls, which is always zero.

Do you need our keys or a funded wallet?

No. The passive scan reads public metadata and the active probe sends an invalid payload that needs no signing key. Settlens never holds wallets, payment keys or funds.

Can we test /supported without a resource server?

Yes. settlens facilitator <base-url> checks /supported on its own. Coverage, signer and /verify checks need a resource that advertises requirements, such as your own test resource.

Is the /verify probe safe to run against production?

It sends a single payload that a correct facilitator rejects, and it only runs with --active, --authorized and an authorization reference. Run it with the operator's explicit approval, and start on staging.

Which networks are covered?

Schema and coverage checks work on any CAIP-2 network. Offline signature verification covers EIP-3009 authorizations of the exact scheme on eip155 networks and the signers of Solana transactions.

Sources

  1. x402 protocol specification, version 2 (§5.4 VerifyResponse, §7 facilitator interface)x402 Foundation · github.com
  2. Scheme exact on EVM: EIP-3009 authorization payload and verificationx402 Foundation · github.com
  3. EIP-3009: Transfer With AuthorizationEthereum Improvement Proposals · eips.ethereum.org
  4. EIP-712: Typed structured data hashing and signingEthereum Improvement Proposals · eips.ethereum.org
  5. CAIP-2: Blockchain ID specificationChain Agnostic Standards Alliance · github.com

Show integrators your facilitator fails closed

A pilot covers your /supported endpoint, one reference resource and an authorized /verify probe, and ends with signed evidence.