
Security News
arXiv Is Rate Limiting Authors Following a Flood of AI Slop Submissions
arXiv now limits authors to two submissions a month as AI slop overwhelms moderators, delays good papers, and sparks debate over applying the limit to everyone.
settled-x402
Advanced tools
Don't let your agent pay an x402 endpoint that doesn't deliver. Checks each quote against Settled's independent evidence (paid test purchases, payTo, payee, buyer reports) before it is signed. Works with @x402/fetch, x402-fetch, any x402Client and Coinbas
Check an x402 quote against independent evidence before your agent signs it.
settled-x402 asks Settled about every x402 payment before your agent signs it. Settled is an independent x402 index. It probes endpoints itself, buys from them with real USDC, and checks what comes back against each listing. For the payment in hand, the guard checks:
Payments with a verdict you block, avoid by default, are stopped before anything is signed.
npm install settled-x402
Node 20 or later, no dependencies, ES modules (require() works on Node 20.19+ and 22.12+).
Wrap your x402 client in an x402HTTPClient and guard that. The guard then knows both the URL you requested and the exact option your client is about to pay:
import { x402Client, x402HTTPClient, wrapFetchWithPayment } from '@x402/fetch';
import { registerExactEvmScheme } from '@x402/evm/exact/client';
import { privateKeyToAccount } from 'viem/accounts';
import { settledGuard } from 'settled-x402';
const client = new x402Client();
registerExactEvmScheme(client, { signer: privateKeyToAccount(process.env.PRIVATE_KEY) });
const httpClient = settledGuard(new x402HTTPClient(client));
const fetchWithPayment = wrapFetchWithPayment(fetch, httpClient);
wrapAxiosWithPayment(axios.create(), httpClient) works the same way.
When the guard blocks a payment, nothing is signed. The call rejects with an error whose message contains Payment creation aborted: Settled: avoid for <url>: <reasons>.
You can also guard the plain x402Client with settledGuard(client). The guard then sees only the URL the 402 names (resource.url), which the seller writes. It still checks that URL's payTo against Settled. But a seller can leave the URL out and get unknown, which isn't blocked unless you block unknown. Prefer the x402HTTPClient form.
import { wrapFetchWithPayment } from 'x402-fetch';
import { withSettled } from 'settled-x402';
const fetchWithPayment = wrapFetchWithPayment(withSettled(fetch, { network: 'base' }), walletClient);
withSettled sits under the payment wrapper. When an endpoint answers 402 with an x402 quote, the quote is checked before the wrapper sees it. A blocked verdict throws SettledBlockedError, whose error.result holds the full result, so the wrapper never signs.
withSettled can't see which option the wrapper will pick, so it judges every option in the quote, from the header and from the body, and reports the riskiest. Set network to the networks your wallet pays on so that options on other chains don't count.
AgentKit's x402 actions build their own x402 client and pay through the global fetch, so there is no client to hand to settledGuard. Guard the global fetch instead, and give the agent Settled's actions:
npm install settled-x402 @coinbase/agentkit
import { AgentKit, x402ActionProvider } from '@coinbase/agentkit';
import { guardGlobalFetch } from 'settled-x402';
import { settledActionProvider } from 'settled-x402/agentkit';
guardGlobalFetch({ network: 'base' }); // the network your wallet pays on
const agentkit = await AgentKit.from({
walletProvider,
actionProviders: [x402ActionProvider(), settledActionProvider()],
});
guardGlobalFetch(options) puts withSettled under every fetch in the process. When make_http_request_with_x402 or retry_http_request_with_x402 gets a quote with a blocked verdict, the action fails with Settled: avoid for <url>: <reasons> before anything is signed. make_http_request fails the same way, so the agent finds out before it asks to pay. Anything that isn't a 402 with an x402 quote passes through untouched. Calling it again changes nothing, and the function it returns puts the original fetch back.
settledActionProvider(options) adds two actions. Neither pays anything.
| Action | Arguments | Returns |
|---|---|---|
SettledActionProvider_check_x402_endpoint | url, method (GET or POST) | The endpoint's quote, read without paying, with Settled's verdict and reasons, judged on the wallet's network |
SettledActionProvider_find_x402_endpoints | query, maxPriceUsd, limit | Live endpoints on the wallet's network, with price, quality score and whether Settled's test purchase delivered |
It takes pass (or reads SETTLED_PASS from the environment), network, timeoutMs, skipHosts, includeQuery and baseUrl. Without a pass, both actions count against the free 300 calls a day.
AgentKit's discover_x402_services reads a facilitator's /discovery/resources list. Settled serves that format at https://settled.tools/discovery/resources, limited to endpoints it has checked: live, priced in USDC, probed in the last 3 days, and not failing Settled's last test purchase. Endpoints Settled has bought from successfully come first, and each item's metadata.settled holds the evidence.
https://settled.tools.x402ActionProvider({ registeredFacilitators: { settled: 'https://settled.tools' } }). The agent then asks for settled.import { check } from 'settled-x402';
const result = await check('https://api.example.com/paid', { quote: paymentRequired, network: 'base' });
result.verdict; // 'pay' | 'caution' | 'avoid' | 'unknown' | 'skipped'
result.reasons; // why, in plain words
result.options; // each option in the quote and how its payTo compares with Settled's record
result.details; // link to Settled's full answer
Without a quote, the guard can only report Settled's record for the URL. To have the quote read for you, use inspect. It requests the endpoint without paying (GET, or POST with { method: 'POST' }) and checks the 402 it gets back:
import { inspect } from 'settled-x402';
const result = await inspect('https://api.example.com/paid', { network: 'base' });
result.endpoint; // { url, httpStatus, error }: what the unpaid request got
$ npx settled-x402 check https://api.bitrefill.com/x402/gift-cards/search
PAY · https://api.bitrefill.com/x402/gift-cards/search
quote $0.002 on base to 0x480C…846A (4 options)
options base: $0.002 to 0x480C…846A · payTo matches Settled
(arbitrum: $0.002 to 0x480C…846A · same address as on Settled's network)
(polygon: $0.002 to 0x480C…846A · same address as on Settled's network)
(solana: $0.002 to 5yASLj…NgRn · not on record at Settled)
the verdict covers the options on base; pick another with --network
Settled live, delivered · $0.002 on base to 0x480C…846A · scout's last purchase 2026-10-01 (tx 0x62cd…5a29)
why payTo matches what Settled sees for this endpoint (0x480C…846A)
a real payment by Settled's scout came back with content, tx 0x62cd…5a29
details https://settled.tools/v1/free/check?url=https%3A%2F%2Fapi.bitrefill.com%2Fx402%2Fgift-cards%2Fsearch
The command reads the endpoint's 402 quote without paying, then asks Settled about it.
--network solana to judge another.--json prints the full result; --post reads a POST endpoint's quote.For Claude Desktop, Cursor and other clients that start MCP servers as a command:
{
"mcpServers": {
"settled": { "command": "npx", "args": ["-y", "settled-x402", "mcp"] }
}
}
Once you hold a day pass, add "env": { "SETTLED_PASS": "<pass>" }. Clients that support remote MCP servers can connect to https://settled.tools/mcp directly. In Claude Code that's claude mcp add --transport http settled https://settled.tools/mcp.
The package ships the settled-x402 Agent Skill: the same rules as the guard, written for an agent that reads instructions rather than calling code. It tells the agent to run Settled's free check before any x402 payment it hasn't made successfully before, walk a short decision table (sanctioned payee, seller on hold, dead status, payTo mismatch with the quote in hand, price drift, verified delivery, quality), preflight when the money matters, report afterwards, and say why. Three files: SKILL.md, references/api.md and scripts/settled_check.py (standard-library Python, prints a one-line decision).
npx settled-x402 skill install # copies it into ./.claude/skills/settled-x402
npx settled-x402 skill install --global # into ~/.claude/skills, for every project
npx settled-x402 skill install --to <dir> # into any skills folder
npx settled-x402 skill # prints where the files are: node_modules/settled-x402/skills/settled-x402
npx settled-x402 skill show # prints SKILL.md
Claude Code and the Claude Agent SDK load skills from .claude/skills/; Claude Managed Agents, OpenClaw and other harnesses take the folder or the files. The skill expects the Settled MCP server or plain HTTP (GET https://settled.tools/v1/free/check?url=...), so it works without this package's code too. Claude Code users can instead install the plugin, which adds the skill and the MCP server together: /plugin marketplace add justinedwardvolmer/settled-skill, then /plugin install settled@settled.
| Verdict | What it means | By default |
|---|---|---|
pay | The payTo matches what Settled sees, and nothing on record is against it | paid |
caution | Worth a look, not damning. Examples: a price above what Settled was quoted, a different address on another EVM chain, no on-chain history for the payTo, a paid call that didn't match its listing, failing probes | paid |
avoid | Strong evidence against paying: a payTo on Settled's network and asset that isn't the one Settled sees, a scout payment that came back empty, a seller on hold (it took the scout's payment twice in 30 days and delivered nothing), a clone farm, or most paying agents reporting failure. With a pass it also covers honeypot listings and circular payments | blocked |
unknown | Nothing to judge by. Settled has no quote for this network or URL, can't be reached, or your free checks are used up | paid |
skipped | Not sent to Settled: payments to settled.tools itself, skipHosts, and local or private addresses | paid, never blocked |
To block more, pass block, for example settledGuard(httpClient, { block: ['avoid', 'caution'] }). Add 'unknown' to fail closed when Settled can't vouch for a payment.
The guard compares the option you're paying with what Settled's prober gets from the same URL at about the same time. Settled reuses a probe that is under 5 minutes old; otherwise it probes while you wait.
It catches:
It can't catch:
caution, because honest sellers do this. In a sample of 385 live x402 quotes, 13 of the 93 sellers offering several EVM chains used a different address on one of them. On other chains, such as Solana when Settled recorded Base, the payTo can't be compared, so the verdict is unknown.A seller that honestly uses different addresses for different assets on one network will get avoid for the asset Settled didn't record.
After a seller legitimately changes its payTo, payments can be blocked for up to about 10 minutes, until both caches refresh.
settledGuard(client, options), withSettled(fetch, options), guardGlobalFetch(options), check(url, options) and inspect(url, options) all take:
| Option | Default | |
|---|---|---|
block | ['avoid'] | Verdicts that stop the payment |
pass | none | A Settled day pass: switches to /v1/preflight and removes the daily cap |
network | all | Networks your wallet pays on, such as 'base' or ['base', 'eip155:137'], or 'auto' for the one Settled has on record. Used only when the selected option isn't known (withSettled, check). Without it, an endpoint that also offers a chain Settled has no quote for, like Bitrefill's Solana option, comes out unknown |
onVerdict | none | Called with every result, blocked or not. It isn't awaited |
timeoutMs | 8000 | How long to wait for Settled. A timeout gives unknown |
cacheTtlMs | 300000 | How long an answer is reused for the same URL |
skipHosts | [] | Hosts never sent to Settled, such as 'api.mycompany.com' or '*.mycompany.com' |
includeQuery | false | Also send the URL's query string to Settled |
allowPrivateHosts | false | Also send localhost and private-network URLs. Only useful with your own baseUrl |
fetch | globalThis.fetch | The fetch used to reach Settled. Pass one that uses your proxy if your agent needs one |
baseUrl | https://settled.tools |
inspect also takes method ('GET' or 'POST'), body (a string; default '{}' for POST) and quoteTimeoutMs (default 15000).
Without a pass, the guard uses Settled's free check:
/v1/free/endpoints.When the free checks run out, verdicts are unknown and payments go through unless you block unknown.
A day pass costs $0.05 in USDC over x402. It lasts 24 hours and allows 120 requests a minute with no daily cap. It switches the guard to Settled's preflight, which adds seller settlement-integrity and honeypot checks. Buy one with the client you already have:
const res = await fetchWithPayment('https://settled.tools/v1/pass', { method: 'POST' });
const { pass } = await res.json();
const guarded = settledGuard(new x402HTTPClient(client), { pass });
Sent: only the origin and path of the endpoint you're about to pay, with no query string, fragment or credentials, plus your IP address as with any request. Your keys, the payment and your request body are never sent. Local and private-network addresses are never sent.
The AgentKit search action also sends its keyword, network and price limit. inspect and the AgentKit check action read the quote from the endpoint directly, not through Settled.
Added to Settled's public index: an endpoint Settled hasn't seen before. Settled probes it itself, then adds it. Put the hosts of endpoints you'd rather keep out in skipHosts.
Signed: Settled's answers are signed (EIP-191). result.answer holds the answer, which you can verify at https://settled.tools/v1/verify or with any EVM library.
MIT
FAQs
Don't let your agent pay an x402 endpoint that doesn't deliver. Checks each quote against Settled's independent evidence (paid test purchases, payTo, payee, buyer reports) before it is signed. Works with @x402/fetch, x402-fetch, any x402Client and Coinbas
We found that settled-x402 demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
arXiv now limits authors to two submissions a month as AI slop overwhelms moderators, delays good papers, and sparks debate over applying the limit to everyone.

Research
/Security News
A new GhostAction wave hits hundreds of GitHub repos, expanding CI/CD secret theft to cloud and AI credentials in source code and git history.

Research
/Security News
Tensorlake npm SDK version 0.5.144 was compromised in a ChainDrop / Shai-Hulud attack, delivering credential-stealing malware.