Skip to content

Add x402station action provider — pre-flight oracle for x402 endpoints#1154

Open
sF1nX wants to merge 4 commits intocoinbase:mainfrom
sF1nX:add-x402station-action-provider
Open

Add x402station action provider — pre-flight oracle for x402 endpoints#1154
sF1nX wants to merge 4 commits intocoinbase:mainfrom
sF1nX:add-x402station-action-provider

Conversation

@sF1nX
Copy link
Copy Markdown

@sF1nX sF1nX commented Apr 27, 2026

Summary

Adds a new x402station action provider — a wrapper around the public oracle at x402station.io that gives any AgentKit-built agent six tools for safely paying x402 endpoints:

Action Cost Purpose
preflight $0.001 {ok, warnings[], metadata} for any URL — fast safety check
forensics $0.001 7-day uptime + latency p50/p90/p99 + decoy probability + concentration
catalog_decoys $0.005 Full known-bad blacklist as one cacheable JSON
watch_subscribe $0.01 30-day webhook subscription + 100 prepaid HMAC-signed alerts on endpoint state changes
watch_status free Secret-gated read-back of an existing watch
watch_unsubscribe free Secret-gated soft-delete

Networks: Base mainnet (eip155:8453) and Base Sepolia (eip155:84532). Payments auto-signed through whatever EvmWalletProvider the agent is already configured with.

Why pre-flight?

The agentic.market catalog has 25,000+ x402 endpoints. A non-trivial fraction are honeypots or unreachable:

  • Decoys priced ≥ $1,000 USDC per call. An agent that pays one drains its wallet on the first request.
  • Zombies that 402-handshake fine but always 4xx after settlement (the call-side payment goes through, the agent gets nothing back).
  • Dead endpoints that return network errors or 5xx every probe.

x402station independently probes every active catalog endpoint every ~10 minutes (not facilitator-reported) so it surfaces what facilitator-only monitors miss. Calling preflight before each paid x402 request costs $0.001 USDC — typically 20× cheaper than the request the agent would otherwise lose to a decoy.

A recent independent run on the entire catalog (blog post — methodology + raw JSONL) found 53% of endpoints at Cloudflare-isitagentready.com level 0 and 1.5% with x402 actually detected — so the "is this a real endpoint?" filter is doing real work.

Implementation

Mirrors the shape of the existing x402 action provider and reuses its EvmWalletProvider signer-wrapping pattern, so the four paid actions auto-sign x402 challenges through the agent's existing wallet without extra plumbing.

The baseUrl is allow-listed: only https://x402station.io (canonical) or any http(s)://localhost* (development) is accepted. Any other host throws at construction time so a misconfigured agent can't sign x402 payments against an unknown host.

Test coverage

pnpm test src/action-providers/x402station/ — 21/21 passing locally.

  • constructor (6): default URL, localhost dev URL, trailing-slash handling, malformed URL rejection, non-canonical host rejection, port-bypass rejection (e.g. https://x402station.io:9999 is rejected even though .hostname matches).
  • supportsNetwork (4): base-mainnet ✓, base-sepolia ✓, ethereum-mainnet ✗, non-EVM ✗.
  • preflight (3): POST + URL bound correctly, paymentReceipt decoded from x-payment-response header, error envelope on non-2xx.
  • forensics + catalog_decoys + watch_subscribe (4): correct paths, empty body for decoys, signals omitted-vs-included.
  • watch_status (3): does NOT use the paying-fetch wrapper, parses 200 body, error envelope on 404.
  • watch_unsubscribe (1): issues DELETE.

Manual end-to-end against the prod oracle ($0.018 USDC settled from a test wallet on Base mainnet) — 7/7 PASS via the consumer-side demo agent in the public repo.

Quick start

import {
  AgentKit,
  CdpEvmServerWalletProvider,
  x402stationActionProvider,
} from "@coinbase/agentkit";

const walletProvider = await CdpEvmServerWalletProvider.configureWithWallet({
  apiKeyId: process.env.CDP_API_KEY_ID!,
  apiKeySecret: process.env.CDP_API_KEY_SECRET!,
  walletSecret: process.env.CDP_WALLET_SECRET!,
  networkId: "base-mainnet",
});

const agentKit = await AgentKit.from({
  walletProvider,
  actionProviders: [x402stationActionProvider()],
});

The LLM can then call preflight, forensics, etc. via agentKit.getActions().

Existing alternatives

For agents that speak Model Context Protocol (Claude Code / Cursor / Windsurf / Continue), the same six tools are already available via the x402station-mcp npm package and the official MCP Registry. This PR is the AgentKit-native equivalent for the non-MCP path.

Test plan

  • pnpm test src/action-providers/x402station/ — 21/21 passing
  • pnpm check — 0 type errors in x402station/ files (15 pre-existing errors elsewhere — cdp/, opensea/, zora/ — are not from this PR)
  • Manual end-to-end on Base mainnet via the demo agent in the public repo ($0.018 settled, 7/7 PASS)
  • CI run against this PR

Links

The oracle backend (probe pipeline, signal logic, ingest, internal stats history) lives in a private repo — by design. This PR's source is fully visible in the diff above and snapshotted at https://github.com/sF1nX/x402station-mcp/tree/main/examples/agentkit-action-provider for browseability.

@sF1nX sF1nX requested a review from murrlincoln as a code owner April 27, 2026 04:33
@github-actions github-actions Bot added documentation Improvements or additions to documentation action provider New action provider typescript labels Apr 27, 2026
sF1nX added a commit to sF1nX/lucid-agents that referenced this pull request Apr 27, 2026
…points

x402station is a public oracle for the x402 agentic-commerce network
that probes every endpoint on agentic.market every ~10 minutes and
flags decoys (price ≥ $1k USDC), zombies (100% erroring), dead
endpoints, and price/latency anomalies. Calling preflight before
each paid x402 request costs $0.001 USDC and is typically 20× cheaper
than the request an agent would otherwise lose to a decoy.

This package adds a thin client that builds on
@lucid-agents/payments — its `createX402Fetch` is the only x402
plumbing we need; we just wrap the six oracle endpoints behind a
typed surface and let payments handle the EIP-712 signing.

Six methods:

  preflight({ url })           $0.001  {ok, warnings[], metadata}
  forensics({ url })           $0.001  7-day uptime + p50/p90/p99 +
                                       decoy probability + concentration
  catalogDecoys()              $0.005  full known-bad blacklist
  watch.subscribe(...)         $0.01   30-day webhook subscription +
                                       100 prepaid HMAC-signed alerts
  watch.status({ id, secret }) free    secret-gated read-back
  watch.unsubscribe(...)       free    secret-gated soft-delete

Networks: Base mainnet (eip155:8453) and Base Sepolia (eip155:84532).
The constructor allow-lists baseUrl to https://x402station.io or any
http(s)://localhost* dev URL — refuses to start otherwise so a
misconfigured agent can't sign x402 payments against an unknown
host. Mirrors the same guard shipped in the official x402station-mcp
npm package and the AgentKit action provider PR
(coinbase/agentkit#1154).

Tests cover the constructor allow-list (canonical + dev URL +
trailing-slash + non-canonical reject + malformed reject + port-
bypass reject), every paid action including the x-payment-response
receipt decode, the wallet-aware vs free-fetch split for the watch
endpoints, zod input validation (signal whitelist, UUID watchId,
64-hex secret) catching errors before any wallet round-trip, and
the 404-for-both-cases secret-gated behaviour. 19/19 passing under
`bun test`. tsup produces ESM (5.4 KB) + DTS (8.98 KB) cleanly.
@sF1nX sF1nX force-pushed the add-x402station-action-provider branch from 61e7b5d to 40bdd63 Compare April 27, 2026 10:28
sF1nX added a commit to sF1nX/lucid-agents that referenced this pull request Apr 27, 2026
…points

x402station is a public oracle for the x402 agentic-commerce network
that probes every endpoint on agentic.market every ~10 minutes and
flags decoys (price ≥ $1k USDC), zombies (100% erroring), dead
endpoints, and price/latency anomalies. Calling preflight before
each paid x402 request costs $0.001 USDC and is typically 20× cheaper
than the request an agent would otherwise lose to a decoy.

This package adds a thin client that builds on
@lucid-agents/payments — its `createX402Fetch` is the only x402
plumbing we need; we just wrap the six oracle endpoints behind a
typed surface and let payments handle the EIP-712 signing.

Six methods:

  preflight({ url })           $0.001  {ok, warnings[], metadata}
  forensics({ url })           $0.001  7-day uptime + p50/p90/p99 +
                                       decoy probability + concentration
  catalogDecoys()              $0.005  full known-bad blacklist
  watch.subscribe(...)         $0.01   30-day webhook subscription +
                                       100 prepaid HMAC-signed alerts
  watch.status({ id, secret }) free    secret-gated read-back
  watch.unsubscribe(...)       free    secret-gated soft-delete

Networks: Base mainnet (eip155:8453) and Base Sepolia (eip155:84532).
The constructor allow-lists baseUrl to https://x402station.io or any
http(s)://localhost* dev URL — refuses to start otherwise so a
misconfigured agent can't sign x402 payments against an unknown
host. Mirrors the same guard shipped in the official x402station-mcp
npm package and the AgentKit action provider PR
(coinbase/agentkit#1154).

Tests cover the constructor allow-list (canonical + dev URL +
trailing-slash + non-canonical reject + malformed reject + port-
bypass reject), every paid action including the x-payment-response
receipt decode, the wallet-aware vs free-fetch split for the watch
endpoints, zod input validation (signal whitelist, UUID watchId,
64-hex secret) catching errors before any wallet round-trip, and
the 404-for-both-cases secret-gated behaviour. 19/19 passing under
`bun test`. tsup produces ESM (5.4 KB) + DTS (8.98 KB) cleanly.
sF1nX added a commit to sF1nX/lucid-agents that referenced this pull request Apr 27, 2026
…points

x402station is a public oracle for the x402 agentic-commerce network
that probes every endpoint on agentic.market every ~10 minutes and
flags decoys (price ≥ $1k USDC), zombies (100% erroring), dead
endpoints, and price/latency anomalies. Calling preflight before
each paid x402 request costs $0.001 USDC and is typically 20× cheaper
than the request an agent would otherwise lose to a decoy.

This package adds a thin client that builds on
@lucid-agents/payments — its `createX402Fetch` is the only x402
plumbing we need; we just wrap the six oracle endpoints behind a
typed surface and let payments handle the EIP-712 signing.

Six methods:

  preflight({ url })           $0.001  {ok, warnings[], metadata}
  forensics({ url })           $0.001  7-day uptime + p50/p90/p99 +
                                       decoy probability + concentration
  catalogDecoys()              $0.005  full known-bad blacklist
  watch.subscribe(...)         $0.01   30-day webhook subscription +
                                       100 prepaid HMAC-signed alerts
  watch.status({ id, secret }) free    secret-gated read-back
  watch.unsubscribe(...)       free    secret-gated soft-delete

Networks: Base mainnet (eip155:8453) and Base Sepolia (eip155:84532).
The constructor allow-lists baseUrl to https://x402station.io or any
http(s)://localhost* dev URL — refuses to start otherwise so a
misconfigured agent can't sign x402 payments against an unknown
host. Mirrors the same guard shipped in the official x402station-mcp
npm package and the AgentKit action provider PR
(coinbase/agentkit#1154).

Tests cover the constructor allow-list (canonical + dev URL +
trailing-slash + non-canonical reject + malformed reject + port-
bypass reject), every paid action including the x-payment-response
receipt decode, the wallet-aware vs free-fetch split for the watch
endpoints, zod input validation (signal whitelist, UUID watchId,
64-hex secret) catching errors before any wallet round-trip, and
the 404-for-both-cases secret-gated behaviour. 19/19 passing under
`bun test`. tsup produces ESM (5.4 KB) + DTS (8.98 KB) cleanly.
x402station is a public oracle for the x402 agentic-commerce network
that probes every endpoint on agentic.market every ~10 minutes and
flags decoys (price ≥ $1k USDC), zombies (100% erroring), dead
endpoints, and price/latency anomalies. Calling preflight before
each paid x402 request costs $0.001 USDC and is typically 20× cheaper
than the request an agent would otherwise lose to a decoy.

This action provider mirrors the shape of the existing `x402` provider
in this repo and reuses the same EvmWalletProvider signer-wrapping
pattern, so the four paid actions auto-sign their own $0.001-$0.01
USDC payments through whatever EvmWalletProvider the agent is already
configured with. Two free secret-gated actions (watch_status,
watch_unsubscribe) manage an existing webhook subscription.

Six actions:

  preflight              $0.001  {ok, warnings[], metadata}
  forensics              $0.001  7-day uptime + latency p50/p90/p99 +
                                 decoy probability + concentration
  catalog_decoys         $0.005  full known-bad blacklist, cacheable
  watch_subscribe        $0.01   30-day webhook subscription + 100
                                 prepaid HMAC-signed alerts
  watch_status           free    secret-gated read-back
  watch_unsubscribe      free    secret-gated soft-delete

Networks: Base mainnet (eip155:8453) and Base Sepolia (eip155:84532).

Tests cover the constructor's host allowlist (canonical
x402station.io, http(s)://localhost dev URLs only — refuses to start
otherwise so a misconfigured agent can't sign x402 payments against
an unknown host), supportsNetwork (Base ✓, others ✗), every action
path including the x-payment-response header decoding into
paymentReceipt, and the secret-gated 404 behaviour for the free
watch endpoints. 21/21 passing.
CRITICAL: u.host.startsWith("localhost") matches an attacker host
"localhost.attacker.com" via prefix — same is true for
"127.0.0.1.evil.example" and "localhost-impersonation.example".
This was the only defense between a misconfigured baseUrl and a
signed X-PAYMENT being routed off-target.

Switch to u.hostname exact-match against "localhost", "127.0.0.1",
"[::1]" (WHATWG URL.hostname returns the bracketed form for IPv6
literals per RFC 2732). u.host stays as exact-match on canonical
"x402station.io" so port-bypass also stays blocked.

Three regression tests added (localhost.attacker.com,
127.0.0.1.evil.example, localhost-evil.example).

Discovered by CodeRabbit on the upstream Mastra integration PR
(mastra-ai/mastra#15804). Mirrored to the Daydreams Lucid PR
(daydreamsai/lucid-agents#1629), the @mastra/x402station
integration, and the x402station-mcp v1.0.6 npm package release.

27/27 jest passing, no tsc errors against locally-built workspace.
@cb-heimdall
Copy link
Copy Markdown

cb-heimdall commented Apr 27, 2026

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 1
Sum 2

sF1nX added 2 commits April 28, 2026 00:21
7th action wraps the new x402station /api/v1/alternatives endpoint:
given a URL flagged by preflight (or a taskClass hint), returns up
to 5 healthy sibling endpoints in the same provider/domain/category/
price-band, ranked by uptime + latency. Solves "preflight returned
ok=false, where do I go instead?" — the next question every agent
has after a blocked call.

Inputs (AlternativesSchema): { url?, taskClass?, limit? }, at least
one of url/taskClass required (route enforces 400 if both empty).
limit 1..10 default 5. zod refine on the input schema flags the
common case at construction time.

29/29 jest passing (+2 new: alternatives URL-mode body shape,
taskClass+limit body shape with omitted url field).

End-to-end verified on the upstream oracle (Base mainnet): URL-mode
returned similar_price siblings at 100% uptime + 80ms latency;
taskClass="Inference" returned 3 BlockRun.AI candidates with
same_category match_reason out of 188 total eligible.
8th action wraps the new x402station /api/v1/whats-new endpoint:
returns added_endpoints[] (first_seen_at >= since AND is_active=true),
removed_endpoints[] (flipped to is_active=false since), service-level
counts, polls_in_window, and current active totals. Default window
is 24h; cap is 30 days back; limit caps each list 1..500 default 200.

Designed for aggregator agents that need a fresh catalog delta
without re-pulling the whole 30k-endpoint dump. Cheapest tier
($0.001) — hourly polling stays under $1/month. Internal ingest
cron runs every 5 min, so polling more often returns identical
data.

Inputs (WhatsNewSchema): { since?, limit? }, both optional.
zod datetime() validates ISO 8601 client-side; route-level checks
catch since-too-old / since-in-future / limit-out-of-range.

31/31 jest passing (+2 new for whats_new: empty body when no args,
since+limit threading).

End-to-end verified on Base mainnet: default 24h window returned
4112 added / 71 removed (catalog grew 17% in 24h, 25950 -> 30200);
1h window returned 98 added / 71 removed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action provider New action provider documentation Improvements or additions to documentation typescript

Development

Successfully merging this pull request may close these issues.

2 participants