New x402 Listings Feed
Feed of x402/L402 services newly listed on 402index.io within a caller-specified recency window. NEXUS
candidate #8 -- manual build, not FORGE-generated, same manual-Cloud-Run-asset pattern as candidates #3
(agent-verification-api), #4 (url-metadata-api) and #6 (document-conversion-api).
POST /new-x402-listings {"window_hours": 24, "protocol": null, "category": null, "payment_network": null}-- services registered on 402index.io within the window (1-168h, default 24). $0.01/call.- MCP tool
get_new_x402_listingsat/mcp, same params -- currently free, see "Known limitations". GET /health,GET /.well-known/agent-card.json,GET /openapi.json(hasx-payment-info),GET /.well-known/402index-verify.txt(402index claim verification file).
What this is (and isn't)
This is not exclusive data. The registration data underneath this asset is 402index.io's own free,
public directory (https://402index.io/api-docs, no auth needed, 100 req/min free tier). Anyone can query
it directly for nothing. This asset's value is entirely in the packaging: polling and paginating the ~96k+
entry catalog so a buyer doesn't have to, merging in 402index's own recency feed for freshness, deduping,
and filtering to a caller's window/protocol/category/payment-network. This disclosure is not just in this
README -- it's baked into the product itself: every response includes a note field stating it plainly, and
the agent-card's protocol_note repeats it, so a buyer never has to dig for it.
Feasibility research (2026-08-23, before writing any code)
The task brief's premise cited a prior-session figure of "~7,595 total services" on 402index.io. A real
curl https://402index.io/api/v1/services?limit=5 at the start of this session showed "total": 96093 --
the catalog grew roughly 12x since that check. registered_at is real and populated on every entry sampled.
Two upstream mechanisms were verified live, each with a real limitation neither the task brief nor
402index's own docs fully surfaced:
GET /api/v1/services(paginated,limit/offset, max 200/page) has NO sort-by-date or date-range filter --sortonly acceptsname/price/latency/uptime/reliability(checked/api-docsdirectly). A window query can only be answered by walking the entire catalog and filtering client-side -- there is no cheaper server-side path. At the real current size that's ~481 pages, not the ~40 pages the ~7,595 figure would have implied.GET /feed.xml?type=newis real, RSS 2.0, and IS already recency-sorted (pubDate) -- and is on 402index's own documented rate-limit-exempt list. But it's capped to a fixed item count: a live fetch during this session returned exactly 90 items spanning only ~3 hours, despite the docs describingtype=newas "services added in the last 7 days". At current registration velocity it does not cover a 7-day (or even a 24h, at peak velocity) window by itself.
Neither source alone honestly satisfies the product's advertised window range. Decision: proceed, using
both. See the main.py module docstring and "Architecture" below for how they're combined. This is the
kind of real, current-data discrepancy CLAUDE.md SS3 asks to surface rather than build past silently -- so it's
recorded here rather than only in a chat transcript.
Architecture
- A background
asynciotask (started in FastAPI'slifespan, not blocking startup) walks the full/api/v1/servicescatalog everyNEXUS_CATALOG_REFRESH_SECONDS(default 600s/10min), paced at 0.65s/request (~92 req/min sustained, safety margin under 402index's 100 req/min free-tier cap). Results are cached in memory (_catalog_cache), keyed by service id. A full walk at the current catalog size is ~481 pages / ~5.2 minutes -- entirely a background-task cost, never inline in a buyer's request. - Every buyer request additionally fetches
/feed.xml?type=newlive (rate-limit-exempt, ~1 request, cheap) and merges it into whatever the background walk has cached, catching anything registered after the last completed walk. Cache entries win on id conflict (richer fields); feed entries only fill gaps. - Response is filtered/deduped/sorted (newest first) from that merge, capped at 500 results.
Why not a literal TTL cache (deviation from the task brief's suggested shape)
The brief suggested "a short in-memory cache (5-10 min TTL)". Implemented instead: a continuously-running background loop that re-walks every 10 minutes and replaces the cache, with buyer requests always reading whatever is currently cached (never triggering a walk themselves). A literal on-demand-when-stale TTL would mean whichever buyer request happens to arrive right after expiry pays $0.01 and then blocks for up to ~5 minutes waiting on a fresh 481-page walk -- unacceptable buyer experience found during design, not retroactively. The background-loop shape gets the same "don't hammer 402index.io" goal without ever making a paying caller wait on the walk.
Cold start (Cloud Run scale-to-zero)
min-instances=0 means a fresh container starts with an empty cache. The first request(s) after any period
of inactivity get catalog_walk.status: "cold_fallback_feed_only" -- results are limited to whatever
/feed.xml?type=new currently holds (recently observed to span only a few hours), not the full requested
window. This is disclosed in the response's own note field, not hidden. Once the background task's first
walk completes (~5 minutes after container start), subsequent requests get status: "warm" with full
catalog-walk coverage. Genuinely mitigated, not solved -- see "Known limitations".
Pricing: $0.01/call (low tier)
Speculative niche per the product owner (explicit direction, not a data-driven conclusion) -- same low tier
as url-metadata-api/document-conversion-api's $0.01-$0.02, not agent-verification-api's $0.35 signal
tier. No paid third-party API cost, pure CPU/memory + one free upstream fetch per call.
Pre-deploy quality gate (2026-08-23, from design not retroactive)
Reviewed across 4 lenses before first deploy, tested against the real live 402index.io API (not mocked) at each step. Real findings and fixes:
- Security: caller input (
window_hours/protocol/category/payment_network) is never interpolated into the upstream 402index.io request -- the catalog walk and feed fetch use fixed, hardcoded query params only (limit/offset/sort/orderandtype=newrespectively); caller filters apply exclusively to the already-fetched, normalized in-memory result. Verified upstream JSON/XML is never trusted blindly: every field read via.get()with type checks (_normalize_catalog_itemreturnsNoneon a malformed entry rather than raising), malformed XML from/feed.xmlis caught (ET.ParseError) rather than crashing the request, and a single malformed<item>in the feed doesn't drop the rest of it. All confirmed with real malformed-input tests (None, missing id, wrong types, garbage timestamp, truncated XML) during this session, not just read as correct. - Functional correctness (real gap, fixed): the initial design cached
complete: boolinternally but never surfaced it in the response -- a caller had no way to tell a background walk that hit the_WALK_MAX_WALL_SECONDSwall-clock cap (bailing out with a partial result) from one that finished cleanly, even though both reportstatus: "warm". Fixed: addedcatalog_walk.walk_completeto the response. Pagination itself (offset advance, stop-at-total, wall-cap bailout) was verified against the real live API with a bounded test walk (8 real pages, offset advancing correctly, graceful bailout logged) -- no silent truncation, no infinite loop. - Code quality: no dead code or unused imports found in review; matches sibling assets' structure
(Supabase telemetry helpers, x402 wiring, discovery routes) ported by hand, consistent with how
document-conversion-api/url-metadata-apiare built. - Buyer experience (the "raw data is free elsewhere" disclosure lens): the fact that 402index.io's data
is itself free was verified present in 3 places, not just the README: the agent-card
protocol_note, and -- more directly, so no buyer has to fetch the agent-card at all -- every single API response's ownnotefield. Cold-cache degraded coverage (cold_fallback_feed_only) is also disclosed in that samenotefield with plain language about what it means for the requested window, not just a status enum a caller has to already know how to interpret.
Known limitations (left as documented tradeoffs, not silently)
- MCP tool calls are not charged. Same in-process-call pattern as the sibling manual assets.
- No per-caller rate limiting. Fine for a 7-day disposable measurement window.
- Cold-cache window under-coverage is mitigated, not solved. A request landing in the first ~5 minutes
after a Cloud Run cold start gets feed-only coverage (recently observed ~3h span for a 90-item feed at
current 402index velocity), not the full requested window, even though it's charged the same $0.01. This
is disclosed live in the response, but a buyer who calls once, right after a cold start, and doesn't read
catalog_walk.status/notecould reasonably read a short result list as "nothing new" rather than "cache still warming up". A future fix could holdmin-instances=1to eliminate cold starts entirely, at a real always-on Cloud Run cost -- not done for a 7-day probation candidate. registered_atis assumed UTC. 402index's/api/v1/servicesreturns naive timestamps ("2026-08-22 22:13:15", no offset) -- treated as UTC based on consistency withlast_checkedvalues observed live during this session, not a documented guarantee from 402index.io itself.- Full-catalog walk pacing assumes today's catalog size. At ~96k entries a full walk is ~481
pages/~5.2min, safely inside the 10-minute refresh interval. If 402index's catalog keeps growing at the
~12x-since-last-check rate observed this session, a future walk could approach or exceed the 10-minute
refresh interval (it would then just take longer between the visible "last_full_walk_at" updates, not
break --
_WALK_MAX_WALL_SECONDSbails a single cycle out at 900s andwalk_completereports it honestly) -- not re-engineered preemptively per CLAUDE.md SS3 (no gate without evidence it's needed yet).
NEXUS_X402_FREE_MODE
Default false (charges from day 1, no freemium window) -- same convention as document-conversion-api.
Set true locally for testing without a real facilitator round-trip.
Deploy target: Cloud Run, not Railway
Same pipeline as candidates #3/#4/#6 -- see skills/infra-deploy-ops. No PDF/Office parsing here, so the
shared script's default 512Mi is used (not bumped to 1Gi like document-conversion-api).
# 1. First deploy -- PUBLIC_DOMAIN not known yet, every real request 421s until step 2.
./scripts/deploy_cloud_run.sh new-x402-listings-feed manual_assets/new-x402-listings-feed \
manual_assets/new-x402-listings-feed/env-vars.deploy.yaml
# 2. Grab the printed *.run.app URL, then:
gcloud run services update new-x402-listings-feed --region us-central1 --project nexus-505016 \
--update-env-vars PUBLIC_DOMAIN=<the-real-domain>
Measurement (candidate #8, 7-day window)
7-day window from first real deploy (2026-08-23 -> decision point 2026-08-30). Source of truth:
traffic_events/revenue_events/mcp_call_events tables (asset_name = 'new-x402-listings-feed'), not
Cloud Run logs. Day 7: if zero real traffic (filtering crawlers), pause/delete the Cloud Run service, same
decision rule as candidates #3/#4/#6. This is explicitly the most speculative of the 4 manual candidates
(product owner's own framing) -- a niche discovery feed for a still-nascent x402 ecosystem, not a proven
recurring-demand shape like document conversion or link previews.