On this page
See three decisions in 60 seconds
Try the same three steps yourself, or download the 60-second video.
Reproduce it in your browser
- Open the free checker, select Load sample, then Check the request. The expected decision is
payunder the complete example policy. - Select Price doubles, then check again. The quote is now
20000atomic units, above the unchanged10000ceiling. Expected decision:do_not_pay. - Select Recipient changes, then check again. The recipient differs from the unchanged allowlist. Expected decision:
do_not_pay.
The policy belongs to the reviewer. Copying an untrusted quote into its own allowlist would defeat the check. A change may be intentional: review it before updating the policy.
| Synthetic case | Decision | Failed or warned checks |
|---|---|---|
| Approved example | pay | None |
| Price doubles | do_not_pay | policy.maximum_amount, policy.acceptable_option |
| Recipient changes | do_not_pay | policy.recipient, policy.acceptable_option |
| Resource changes | do_not_pay | binding.resource_url |
| Recipient policy missing | review | None |
The approved fixture uses the specification’s Base Sepolia example (eip155:84532). These are illustrative terms, not a payment destination to fund. A pay decision means that an option meets the supplied policy and evaluated checks; it is not an instruction to transfer funds or a security guarantee.
Run the same check with curl
This public call needs no token, account or access to the private Settlens CLI. It evaluates supplied data in memory; it never requests api.example.com. Do not include credentials, private keys, seed phrases or confidential payloads. See the processing and rate-limit details.
curl -s https://settlens.com/mcp \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"evaluate_payment_requirements","arguments":{"payment_required":{"x402Version":2,"error":"PAYMENT-SIGNATURE header is required","resource":{"url":"https://api.example.com/premium-data","description":"Access to premium market data","mimeType":"application/json"},"accepts":[{"scheme":"exact","network":"eip155:84532","amount":"10000","asset":"0x036CbD53842c5426634e7929541eC2318f3dCF7e","payTo":"0x209693Bc6afc0C5328bA36FaF03C514EF312287C","maxTimeoutSeconds":60,"extra":{"name":"USDC","version":"2"}}]},"resource_url":"https://api.example.com/premium-data","policy":{"pay_to":["0x209693Bc6afc0C5328bA36FaF03C514EF312287C"],"assets":["0x036CbD53842c5426634e7929541eC2318f3dCF7e"],"networks":["eip155:84532"],"schemes":["exact"],"max_amount":"10000"}}}}'
In result.structuredContent, inspect decision, acceptable, reasons and checks. Keep the policy unchanged and replace only payment_required.accepts[0].amount with "20000" to reproduce the price case.
Keep reviewed cases in CI
Download the five synthetic fixtures and the small Node.js runner. Review both before using them. With Node.js 20.19 or newer:
curl --fail --show-error -O https://settlens.com/assets/x402-policy-cases.json
curl --fail --show-error -O https://settlens.com/assets/x402-policy-regression.cjs
node x402-policy-regression.cjs x402-policy-cases.json
The runner exits nonzero on an unexpected decision, an HTTP failure, timeout or evaluator error. Its full source is below. The public evaluator is limited to 60 requests per minute per IP; each run makes five requests. Availability and shared CI egress limits can fail this job too.
// Public example: node x402-policy-regression.cjs x402-policy-cases.json
// Synthetic fixture checks, not a scan of a deployed merchant or a settlement test.
const { readFile } = require("node:fs/promises");
async function main() {
const cases = JSON.parse(await readFile(process.argv[2] || "x402-policy-cases.json", "utf8"));
if (!Array.isArray(cases) || !cases.length) throw new Error("Expected a non-empty array of reviewed cases.");
for (const example of cases) {
const response = await fetch("https://settlens.com/mcp", {
method: "POST", redirect: "error", signal: AbortSignal.timeout(15000),
headers: { "content-type": "application/json", accept: "application/json", "mcp-protocol-version": "2025-06-18" },
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/call", params: {
name: "evaluate_payment_requirements", arguments: example.arguments,
} }),
});
if (!response.ok) throw new Error(`Evaluator unavailable (HTTP ${response.status}).`);
const message = await response.json();
const result = message.result?.structuredContent;
if (message.error || message.result?.isError || !result) throw new Error("Evaluator returned an error.");
if (result.decision !== example.expected) throw new Error(`${example.name}: expected ${example.expected}, got ${result.decision}.`);
console.log(`${example.name}: ${result.decision}`);
}
}
main().catch((error) => { console.error(error.message); process.exitCode = 1; });
Commit reviewed fixtures and the runner to your own repository. For example, after checking out your code and selecting a supported Node.js version, add this step to your existing workflow:
- name: Check reviewed x402 fixtures
run: node x402-policy-regression.cjs x402-policy-cases.json
What this example establishes
This is a regression check for supplied challenges and policy decisions. The synthetic fixtures alone do not test a deployed merchant. For your release, capture a challenge from an endpoint you are authorized to test, review its terms independently, and decide which controlled changes must be refused. Never automatically refresh an approved reference from unreviewed live data.
It does not establish live HTTP behavior, signatures, balances, nonce use, on-chain settlement or overall payment safety. The exported decision JSON is unsigned. For a scoped endpoint scan, monitoring reference and private CLI/CI integration, request a technical pilot.