
Product
Socket Threat Intel Now Shows Which Malware Campaigns Were Blocked or Detected
Socket Threat Intel now shows which malware campaigns were blocked or detected in your organization, with links to scans and Firewall events.
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, and screens every paid answer for instructions aimed at the ag
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. The same guard holds every payment to the spending limits you set: a cap per call, a daily budget that stops the agent, and an "ask me above $X" dial. Under withSettled and guardGlobalFetch, every paid answer is also screened for instructions aimed at the agent before the agent reads it. Every result also carries the price's tier: common (free), rare (up to $1 a call) or legendary (over $1). The free check covers 25 calls a day; with renew: true the guard keeps a pass of its own, bought with the agent's wallet for $1 a month, and never runs out.
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.
Give the agent a wallet of its own, funded with a small float of USDC, never your main wallet. The guard and its limits decide what the agent pays, but anyone who gets the key can move everything in the wallet.
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.
The paid answer, the retry that carries the payment, comes back through withSettled too, and that is where the response screen runs: the answer is handed back with x-settled-screen: clean | suspicious | not-scanned in its headers.
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';
const limits = { maxUsdPerCall: 1, dailyBudgetUsd: 5 }; // optional; see Spending limits
guardGlobalFetch({ network: 'base', ...limits }); // the network your wallet pays on
const agentkit = await AgentKit.from({
walletProvider,
actionProviders: [x402ActionProvider(), settledActionProvider(limits)],
});
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, or uses the pass a renewing guard keeps in ~/.settled-x402/pass.json), network, timeoutMs, skipHosts, includeQuery, baseUrl and the spending limits (maxUsdPerCall, dailyBudgetUsd, askAbove, budgetFile, ledger). Give it the same limits as guardGlobalFetch, and the check action tells the agent whether a payment would_be_stopped or whether the operator is asked, before it tries; every result and every found endpoint carries its rarity. Without a pass, both actions count against the free calls (25 a day per address, 300 with a payer record).
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.A wallet key pasted into a workflow tool can be read by more than the workflow that uses it. In n8n, a key in an environment variable can be read by any workflow on the instance, a key typed into a Code node by anyone who can open that workflow, and a community node that signs payments runs with full access to the instance. settled-x402 proxy keeps the key in one small process on your machine and does the paying. A tool sends the request it wants made to POST /pay with a bearer token. The proxy makes it with the standard x402 client under settledGuard, so Settled's check, the loadout and your limits all apply before anything is signed, and it screens the paid answer on the way back. The tool only ever holds the token. Whoever gets the token can spend up to your limits on the hosts you allow; whoever gets the key can take the whole wallet.
Make a wallet for the proxy, then start it:
mkdir -p ~/.settled-x402 && (umask 077; openssl rand -hex 32 > ~/.settled-x402/proxy-key)
npx -y -p settled-x402 -p @x402/fetch@2 -p @x402/evm@2 -p viem@2 settled-x402 proxy --max-usd-per-call 0.25 --daily-budget-usd 5
The first line makes a new private key that only your user can read. On start, the proxy prints the wallet's address: send it a small float of USDC on Base, an amount you'd be fine losing. The wallet needs no ETH, because an x402 payment is a signed authorization that the seller's facilitator submits. The proxy also prints its token the first time; it is kept in ~/.settled-x402/proxy-token.
curl -s http://127.0.0.1:4021/pay \
-H "authorization: Bearer $(cat ~/.settled-x402/proxy-token)" \
-H 'content-type: application/json' \
-d '{"url": "https://api.example.com/paid", "method": "POST", "body": {"q": "hello"}}'
POST /pay takes url, method (default GET), headers and body (an object is sent as JSON). It answers:
| Status | When | What comes back |
|---|---|---|
| 200 | The endpoint answered, paid or free | ok and status (the endpoint's own), paid, payment (tx, network, payer), settled (verdict, reasons, price, payTo, spend), screen (verdict, findings), and the answer as json, body or body_base64 |
| 403 | Refused | blocked_by says what refused it. verdict, limit and client_cap stop the payment before anything is signed; loadout (a host outside --only-hosts) stops it before anything is requested. screen, only with --screen throw, refuses an answer that was already paid for, and paid and payment say so |
| 400 | A bad request | error: bad_url, bad_method, bad_request, or private_host (the proxy pays public endpoints only) |
| 401 | No token, or the wrong one | |
| 502 | The endpoint couldn't be reached, or the payment failed | message |
GET /status (with the token) shows the wallet, the limits and today's spend; GET /health needs no token.
| Flag | Default | |
|---|---|---|
--key-file | SETTLED_PROXY_KEY, else ~/.settled-x402/proxy-key | The wallet key, hex. A file others can read gets a warning |
--token-file | SETTLED_PROXY_TOKEN, else ~/.settled-x402/proxy-token (made the first time) | The bearer token callers send |
--port, --host | 4021, 127.0.0.1 | Any other host prints a warning: anyone who can reach the port and has the token can spend up to the limits |
--max-usd-per-call | the x402 client's own cap, $1 a payment | Stop any call priced over this |
--daily-budget-usd | 5 | Stop once today's calls would add up to more than this; none lifts it, leaving the wallet balance as the only limit |
--only-hosts | any host | The loadout, comma-separated: api.exa.ai,*.agent402.tools |
--block | avoid | Verdicts that stop a payment, comma-separated |
--pass, --payer-token | SETTLED_PASS, SETTLED_PAYER_TOKEN | As for the guard (Free, or with a pass) |
--screen | flag | throw refuses a suspicious answer, off turns the screen off |
--budget-file | SETTLED_BUDGET_FILE, else ~/.settled-x402/spend.json | Where the daily total is kept |
The proxy pays with @x402/fetch, @x402/evm and viem, which settled-x402 doesn't depend on. The npx -p line fetches them; or install them next to it (npm install settled-x402 @x402/fetch@2 @x402/evm@2 viem@2) and run npx settled-x402 proxy. In code: import { createProxy } from 'settled-x402/proxy'.
In n8n, import Pay for an x402 API through the Settled proxy (Workflows → Import from URL): an HTTP Request node that posts to the proxy with a Header Auth credential (name Authorization, value Bearer <token>), and an IF that sends answers one way and refusals the other. settled.tools/loadout builds the proxy command from your limits and loot. n8n on the same machine reaches the proxy at http://localhost:4021, and n8n in Docker Desktop at http://host.docker.internal:4021. With Docker on Linux, or docker compose, run the proxy as a service on n8n's network with --host 0.0.0.0 and no published port (the loadout's Docker kit has the compose file). n8n Cloud can't reach a proxy on your machine.
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.rarity; // 'common' | 'rare' | 'legendary' | null: what a call costs, as loot
result.spend; // how the call stands against your spending limits (null when none is set)
result.blockedBy; // 'verdict' | 'limit' | 'operator' | null
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 · rare loot (up to $1 a call)
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.npx settled-x402 spend prints today's tally from the ledger a guard with dailyBudgetUsd keeps (--budget-file <path> for one elsewhere): what was let through, call by call, with each call's rarity. npx settled-x402 pass shows the pass a guard with renew keeps: its term, when it runs out, when it was bought. check uses that pass when no --pass or SETTLED_PASS is given.
npx settled-x402 screen <file> (or on stdin) runs the response screen on any text: the findings with a sample of each, exit code 3 when suspicious, --json for the full result.
For Claude Desktop, Cursor and other clients that start MCP servers as a command:
{
"mcpServers": {
"settled": { "command": "npx", "args": ["-y", "settled-x402", "mcp"] }
}
}
With a pass, add "env": { "SETTLED_PASS": "<pass>" }; the pass a renewing guard keeps on the same machine is used without that. 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 verdict is about the seller. The limits are about your money, and the same guard enforces both, where the payment is about to be signed:
const pay = wrapFetchWithPayment(fetch, settledGuard(httpClient, {
maxUsdPerCall: 1, // never sign a call priced over $1
dailyBudgetUsd: 5, // stop once today's calls would add up to more than $5
askAbove: 0.25, // ask before paying more than 25¢ for one call
ask: async (q) => operatorSaysYes(`Pay $${q.priceUsd} (${q.rarity}) to ${q.url}? $${q.remainingUsd} of today's budget left.`),
}));
| Option | What it does |
|---|---|
maxUsdPerCall | A call priced over this is stopped. 0 pays nothing: free endpoints only |
dailyBudgetUsd | A call that would take today's total (UTC) over this is stopped. The total counts what the guard let through, which is the most that can have been paid. It resets at 00:00 UTC |
askAbove | The softer dial. A call priced over this is put to the operator first; 0 asks about every paid call. With ask, your function gets the call and answers true or false. Without it, the guard asks on the terminal when the process has one (askTimeoutMs, default 2 minutes; silence is a no), and otherwise stops the call, so a headless agent with askAbove and no ask pays only below the line |
budgetFile | Where the daily total lives, so a restart doesn't reset it: default SETTLED_BUDGET_FILE, else ~/.settled-x402/spend.json. false keeps it in memory |
ledger | Your own store for the total (load() and save()), for agents that run as several processes |
onlyHosts | The loadout: the only hosts the agent may pay, such as ['api.exa.ai', '*.agent402.tools']. A quote from anywhere else is stopped whatever Settled says (blockedBy: 'loadout'); settled.tools itself stays payable, so a pass still goes through |
Build one at settled.tools/loadout: pick the runtime, set the limits, choose the services as loot, copy the kit.
A stopped call fails the same way a blocked verdict does: settledGuard aborts the payment, withSettled and guardGlobalFetch throw SettledBlockedError, and the message leads with what stopped it (Settled: over your daily budget for <url>: $2.50 would take today's spend to $6.00, over your dailyBudgetUsd ($5.00; $3.50 spent so far); the budget resets at 00:00 UTC). The error's blockedBy is 'limit', 'operator' or 'loadout', and spend says which limit, what the call cost and what is left today. check and inspect apply the limits too, without counting or asking: an agent that checks first learns the payment would be stopped (spend.decision), or that the operator is asked ('ask').
Three things to know. A quote whose price the guard can't read in USD (an asset it doesn't know) can't be held to a limit, so with any limit set it is stopped. The daily total is kept per ledger: guards with the same budgetFile share it (within one process their reads and writes are queued; across processes a call let through at the same instant by another process can be missed, so give agents that run as several processes a ledger of their own), and guards with memory ledgers each keep their own. And a quote with several options is held to its most expensive one when the guard can't tell which will be paid (withSettled, guardGlobalFetch); settledGuard knows the selected option and holds the payment to exactly that price.
@x402/core has a cap of its own, spendControls.maxAmountPerPayment, $1 per payment by default. It is a cap per payment on the client; it has no daily total, no asking and no verdict, and the other clients don't have it. Both can be on at once.
Every result says what a call costs as a tier, so an agent choosing between endpoints, a log line or a dashboard can use one word for the cost class instead of a number:
| Tier | Price per call | Color |
|---|---|---|
common | free | grey |
rare | up to $1 | blue |
legendary | over $1 | gold |
The line at $1 is where the x402 client's own default cap sits (maxAmountPerPayment: "$1"), so a legendary call is one the client would refuse out of the box. It is also a caution on its own ("it costs $2.50 per call"), and askAbove: 1 is the dial that makes the operator confirm every one. The tier is result.rarity (from the quote's price, else Settled's recorded price; an endpoint Settled gets for free is common), rarityOf(priceUsd) for any price, and RARITIES for labels and colors. The names come from the loadout builder, which shows an agent's services as loot; the API's /v1/loot?tier= uses the same three.
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.
settled-x402/x401 lets a server ask callers for a Settled payer record before serving them: a signed credential that shows facts from the agent's real on-chain payment history (for example, active on 3 or more of the last 30 days, and not on the sanctions list) and keeps the rest hidden. Use it to give free calls only to agents that pay their way, without logins or API keys.
import { requirePayerRecord } from 'settled-x402/x401';
const gate = requirePayerRecord({
origin: 'https://api.example.com', // your public origin: proofs are bound to it
secret: process.env.X401_SECRET, // 32+ characters; signs the nonces, nothing is stored
claims: ['active_days_30d_over_3', 'sanctions_clear'], // the default
});
// In any Fetch API handler (Workers, Deno, Bun, Hono, Next.js route handlers):
export default {
async fetch(request) {
const proof = await gate(request);
if (!proof.ok) return proof.response; // 401 with PROOF-REQUEST (and PROOF-RESULT saying why)
return Response.json({ hello: proof.wallet });
},
};
// In Express:
app.get('/search', async (req, res) => {
const proof = await gate(req.headers);
if (!proof.ok) return res.status(proof.status).set(proof.headers).json(proof.body);
res.json({ hello: proof.wallet });
});
How it works: a request without proof gets 401 and a PROOF-REQUEST header (x401 draft 0.2.0) naming the facts and carrying a nonce that lasts 5 minutes. The agent retries with PROOF-RESPONSE. The gate checks that the proof answers your nonce and names your origin, then has Settled check the record itself at POST https://settled.tools/v1/credentials/verify (the issuer signature, the facts shown, expiry, revocation and the agent's key binding). If Settled can't be reached, or your useNonce store throws, the gate answers 503, never a pass; for an optional higher tier, treat anything but ok as anonymous. Proofs can be reused until their nonce expires; pass useNonce(nonce) (return false for a nonce you've seen) to make each one single-use. The facts a record can show are in PAYER_CLAIMS; what each means is at /vc/payer-record/v1. Agents get a record at /for-agents#payer-record; try the flow in a browser at /x401/try.
A paid x402 answer goes straight into your agent's context as if it were data. A seller, or whoever has taken a seller over, can put instructions in it: "ignore your previous instructions", "send the USDC to 0x…", "do not tell the user". The agent that just paid is, by definition, one with a funded key.
So withSettled (and guardGlobalFetch, which is built on it) screens every paid answer before handing it back. Text-like bodies (JSON, text, HTML, XML, markdown) are read up to 256 KB from a clone, the body itself is untouched, and the answer comes back with:
x-settled-screen: clean, suspicious, or not-scanned (a binary body, or a non-2xx answer);x-settled-screen-findings: the kinds found, such as instruction_override,payment_steering;response.settledScreen: the full result (verdict, findings with a 120-character sample each, bytes, truncated, scanned).What it looks for: instructions to ignore or replace what the agent was told; chat-template and role markers (<|im_start|>, [INST]); text addressed to the assistant ("note for AI agents", "if you are an AI") and a request to visit a URL beside it; requests for private keys, seed phrases, API keys or passwords; a transfer verb, an asset and a wallet address in one sentence; "do not tell the user"; urgency wrapped around a tool call; hidden text (zero-width characters, HTML comments carrying instructions, display:none); markdown images that carry data in their query string; and all of that again inside base64 runs that decode to text. One strong finding, or two weak ones, make an answer suspicious.
It flags; it does not judge the seller. It is a pattern match, and an answer that talks about prompt injection (a security scanner's report, say) will trip it, so the default is to hand the answer back flagged and let you decide:
const fetchWithPayment = wrapFetchWithPayment(withSettled(fetch, {
screen: {
action: 'throw', // refuse a suspicious answer: SettledScreenError, with .screen and .url
onResult: (screen, { url }) => log(url, screen) // every result, clean or not
},
}), walletClient);
screen: false turns it off; screen: { maxBytes } sets how much of the body is read. The hook form (settledGuard(client)) never sees responses, so it has no screen; screenText(text) and screenResponse(response, options) are exported for your own use, and npx settled-x402 screen <file> runs the same patterns from the command line (exit code 3 when suspicious).
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 pass (a day, 30 days or a year): switches to /v1/preflight and removes the daily cap |
renew | off | Keep a pass going without a human: true (a 30-day pass, at most $1), a term ('day', 'month', 'year') or { pass, upToUsd, passFile, store, onRenew, onError, pay } (details). Guards only; check and inspect use pass |
payerToken | none | The agent's payer record as a token (x4t_… from POST /x401/token, 24 hours): the free check counts the client by wallet, 300 a day instead of 25 per address. A refused token falls back to an anonymous check with a note; a pass takes precedence |
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 | |
maxUsdPerCall | none | Stop any call priced over this many dollars (Spending limits) |
dailyBudgetUsd | none | Stop once today's calls would add up to more than this |
askAbove | none | Ask the operator before paying more than this for one call |
ask | terminal prompt | Who to ask: (question) => boolean, with url, priceUsd, rarity, remainingUsd and the full result |
askTimeoutMs | 120000 | How long the terminal prompt waits; silence is a no |
budgetFile | SETTLED_BUDGET_FILE, else ~/.settled-x402/spend.json | Where the daily total is kept; false for memory only |
ledger | the file | Your own store for the total: { load(), save(state) } |
onlyHosts | any host | The loadout: the only hosts the agent may pay; everything else is stopped (settled.tools stays payable) |
screen | true | The response screen on every paid answer (withSettled and guardGlobalFetch only): true flags, { action: 'throw', maxBytes, onResult } refuses or sizes it, false turns it off |
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:
payerToken: a token from POST https://settled.tools/x401/token with the record (it lasts 24 hours and is bound to the wallet). The guard sends it as Authorization: Bearer on each free check; result.payerRecord says whether Settled accepted it, and a refused token falls back to an anonymous check rather than losing the verdict. In AgentKit, SETTLED_PAYER_TOKEN in the environment does the same./v1/free/endpoints. Every free answer says how many are left (free.left_today) and, near the cap, how to continue.When the free checks run out, verdicts are unknown and payments go through unless you block unknown.
A pass removes the daily cap, allows 120 requests a minute and switches the guard to Settled's preflight, which adds seller settlement-integrity and honeypot checks. It is paid in USDC over x402, and there are three terms (terms of sale):
| Term | Route | Price |
|---|---|---|
| a day | POST /v1/pass | $0.05 |
| 30 days | POST /v1/pass/month | $1 |
| a year | POST /v1/pass/year | $10 |
The simplest way to hold one is to let the guard buy it:
const httpClient = settledGuard(new x402HTTPClient(client), { renew: true });
Before the first check, and again an hour before each pass runs out, the guard buys a 30-day pass with the client it guards: it POSTs to /v1/pass/month, reads the price in Settled's 402, and signs only if that price is within renew.upToUsd, which is the term's list price unless you set it (renew: { upToUsd: 1.5 } says: keep renewing through a price rise up to $1.50; a 402 above it is not paid, the guard carries on with the free check and onError says why). The pass is kept in SETTLED_PASS_FILE, else ~/.settled-x402/pass.json, so a restart does not buy another one, and npx settled-x402 pass shows it. A pass Settled refuses (expired, invalid) is forgotten and the next check buys a new one. A pass you give by hand alongside renew is used first, until Settled refuses it. Several checks arriving at once share one purchase; a failed purchase is retried after 10 minutes.
That purchase is the guard's own. It is held to renew.upToUsd and to nothing else: not your onlyHosts, not maxUsdPerCall, not the daily budget, which are for the agent's spending. result.renew on every result says which term is kept, when the pass in hand expires and the last renewal error, if any; onRenew is called once per purchase with the pass, its expiry and the price.
settledGuard(httpClient, {
renew: {
pass: 'year', // 'day' | 'month' (default) | 'year'
upToUsd: 12, // the most to pay for one term; default: the term's list price
passFile: '/var/lib/agent/settled-pass.json', // or false for memory only; or `store: { load(), save(state) }`
onRenew: (r) => log.info(`Settled pass renewed until ${r.expiresAt} for $${r.priceUsd}`),
onError: (e) => log.warn(e.message),
},
});
Under withSettled and guardGlobalFetch there is no client to pay with, so give renew.pay, the fetch that pays (your fetchWithPayment); the guard sees that purchase's 402 like any other and lets it through within the cap. A year pass costs $10 in one payment, over the x402 client's default cap of $1 per payment, so for pass: 'year' with @x402/core raise spendControls.maxAmountPerPayment (or set spendControls: false); otherwise the client refuses the purchase and onError carries its message.
storedPass() returns the pass a renewing guard keeps on the machine, while it is valid, for code that cannot renew but should use it; the CLI, the MCP bridge and the AgentKit provider do that on their own. To buy a pass yourself instead, with the client you already have:
const res = await fetchWithPayment('https://settled.tools/v1/pass/month', { method: 'POST' });
const { pass, expires_at } = 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, and screens every paid answer for instructions aimed at the ag
The npm package settled-x402 receives a total of 0 weekly downloads. As such, settled-x402 popularity was classified as not popular.
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.

Product
Socket Threat Intel now shows which malware campaigns were blocked or detected in your organization, with links to scans and Firewall events.

Security News
Fixes for eMudhra and Brotli are out. Getting them everywhere they’re needed means tracking down bundled libraries, runtimes, and certificate stores.

Threat Research
/Security News
Socket uncovered secret-stealing workflows that ran in LiteLLM’s GitHub repository 11 days before the supply chain attack on PyPI and Docker.