Sample: our own Crypto Sentiment API, checked 2026-11-02, before its fixes. Back to the Listing Fix

Unlisted ran 15 checks when this report was written; it now runs 18 (payment_required_header was added on Nov 6, 2026, and resource_url_match and standard_payment_option on Nov 9, 2026).

Listing Fix report: Crypto Sentiment API

Service: https://crypto-sentiment-x402.onrender.com
Paid routes checked: GET /sentiment/:symbol ($0.01), GET /history/:symbol ($0.05)
Report written: 2026-11-02 19:26 UTC

How this was checked: read-only. No payments, no signing and no browser. No access to the seller's code, except in fix 4, where the owner's code was read to settle one question. Anything that could not be checked that way is marked "not checked" with the reason.

Summary

Both routes are listed and healthy, but a buyer searching in everyday words does not find them.
Neither route came back for "crypto sentiment", "bitcoin news sentiment" or "fear and greed", and the listings have no tags while nearly all the results that do come back have them.
First add tags and rewrite both descriptions, then make one paid call on each route ($0.06 in total) so the listings update.

Do this

Catalog status

Catalog Read at (UTC) Listed? What buyers see Problem
CDP Bazaar 2026-11-02 19:19:47 Yes, both routes /sentiment: last called 2026-10-29 19:49 UTC, 5 calls from 3 payers in 30 days. /history: last called 2026-10-18 19:18 UTC, 3 calls from 2 payers in 30 days. /history shows an old description. Neither route has tags or a service name.
Bazaar search 2026-11-02 19:20:07, repeated 19:23:36 Not returned for any of the 3 phrases, on either read "crypto sentiment": 15 other results. "bitcoin news sentiment": 14 other results. "fear and greed": 20 other results (the most this search returns). Buyers using these words do not see this service.
x402scan 2026-11-02 19:21:15 Not checked Unknown Cannot be checked read-only for free. See "Not checked" at the end.
Agentic.market 2026-11-02 19:23:10 Card present, not enriched Card name is the bare hostname. Service description, category, icon and tags are empty. Both routes and prices are correct. The card shows no service-level description or category.

Fixes in order

1. Add tags and a service name to both routes

RouteConfig(
    # ...keep the existing accepts, description, mime_type and extensions...
    service_name="Crypto Sentiment API",  # 32 characters or fewer
    tags=["crypto sentiment", "bitcoin sentiment", "news sentiment", "fear and greed", "crypto news"],
)

2. Rewrite both descriptions in the words buyers use

3. Publish an output schema in OpenAPI

"200": {
  "content": {
    "application/json": {
      "schema": {
        "type": "object",
        "properties": {
          "symbol": {"type": "string"},
          "overall_sentiment": {"type": "object"},
          "drivers": {"type": "array", "maxItems": 5, "items": {"type": "object"}},
          "drivers_summary": {"type": "string"}
        },
        "required": ["symbol", "overall_sentiment"]
      }
    }
  }
}

4. Settle what happens when there is too little recent news

Remove from info.x-guidance:
"with too little recent news the label is \"insufficient recent news\" instead."
Replace with:
"with too little recent news the request is refused with HTTP 422 and not charged."

In app/home.py line 201, replace:
Low-coverage coins often get “insufficient recent news” (not charged).
With:
Low-coverage coins are often refused with HTTP 422 (not charged).

In app/home.py lines 245 and 246, replace:
When there's too little recent news to call it, the label says “insufficient recent news” instead.
With:
When there's too little recent news to call it, the request is refused with HTTP 422 and not charged.

5. Tidy the smaller mismatches

"tags": ["Sentiment"]

6. Make one paid call on each route, last

GET https://crypto-sentiment-x402.onrender.com/sentiment/BTC   $0.01
GET https://crypto-sentiment-x402.onrender.com/history/BTC     $0.05

Description review

GET /sentiment/:symbol

Current (486 characters):

Real-time crypto sentiment for a ticker symbol (e.g. BTC, ETH, SOL) from 9 crypto news RSS outlets (CoinDesk, Cointelegraph, Decrypt, Bitcoin Magazine, The Block, CryptoSlate, NewsBTC, CryptoPotato, The Defiant) and the Fear & Greed Index. Headlines from the last 72h, weighted toward the newest. Returns a bullish/bearish/neutral label (or 'insufficient recent news'), score, sample size and the top 5 headlines behind it (title, link) as JSON. Path param: symbol, e.g. /sentiment/BTC.

Rewritten (449 characters, limit 500):

Crypto news sentiment for one coin (24 tickers, e.g. BTC, ETH, SOL): a bullish, bearish or neutral label, a -1 to 1 score, sample size and the top 5 headlines behind it, with links. Built from 9 crypto news outlets and the Fear & Greed Index, last 72 hours, newest weighted most. Use when an agent needs a current read on news sentiment for a coin before research or a trade. Too little recent news or an unsupported coin is refused and not charged.

Opens with (search words): Crypto news sentiment

Use-when line: Use when an agent needs a current read on news sentiment for a coin before research or a trade.

Best 5 tags, most important first: crypto sentiment, bitcoin sentiment, news sentiment, fear and greed, crypto news

GET /history/:symbol

Current (477 characters):

Hourly crypto news-sentiment readings for a ticker (e.g. BTC, ETH), recorded live at the top of every UTC hour and never backfilled. Each row: observed_at, average_compound (-1 to 1), sample_size, Fear & Greed value, matcher and the top 3 headlines behind it (title, link). Query start/end as ISO 8601; default last 7 days, max 30 days per call. An unlogged symbol, an invalid range or a range with no readings is refused and not charged. See /archive for symbols and coverage.

Rewritten (413 characters, limit 500):

Hourly crypto news sentiment history for one coin: score (-1 to 1), sample size, Fear & Greed value and top 3 headlines per hour, recorded live and never backfilled. Use when backtesting or comparing sentiment over time, up to 30 days per call (default 7). Query start/end as ISO 8601. A range with no readings, an invalid range or an unlogged coin is refused and not charged. See /archive for coins and coverage.

Opens with (search words): Hourly crypto news sentiment history

Use-when line: Use when backtesting or comparing sentiment over time, up to 30 days per call (default 7).

Best 5 tags, most important first: sentiment history, crypto sentiment, bitcoin sentiment, news sentiment, backtesting

Instructions-to-agents wording: none found in the current or rewritten text, using Unlisted's own small word list. That list is not CDP's screening, which is not public.

Trust signals

Read at: 2026-11-02 19:23:10 to 19:23:19 UTC

Signal Result Reading
Health endpoint GET /health returned 200 {"status":"ok"} in 0.24 s (median of 5) Good
Response time, unpaid request /sentiment/BTC median 0.32 s, slowest 0.47 s. /history/BTC median 0.28 s, slowest 0.50 s (5 reads each) Good. No slow first request was seen.
Unknown path GET /definitely-not-a-route-xyz returned 404 Good
Prices $0.01 and $0.05, in USDC on Base. The 39 distinct listings from the three searches charge $0.001 to $0.05, median $0.005. Ordinary. /sentiment is about twice that median, and /history is at the top of the range, though that range is not limited to hourly archives.

The price is the same in the 402, OpenAPI, llms.txt and both catalogs. The pay-to address passes its checksum and matches the listing.

Evidence

What the catalog holds next to what the service says right now. A difference means the listing is out of date, unless the row says otherwise.

GET /sentiment/:symbol

Field Bazaar listing, read 19:19:47 UTC Live 402, read 19:18:19 UTC Same?
Price 10000 ($0.01) 10000 ($0.01) Yes
Pay-to address 0xA6E1…E074 0xA6E1…E074 Yes
Network and asset Base (eip155:8453), USDC Base (eip155:8453), USDC Yes
Description 486 characters 486 characters Yes, word for word
Tags None None Yes, and that is the problem
Output schema Present Present Yes
Allowed methods in schema GET GET, HEAD, DELETE No. Set by the x402 library, nothing to do.

GET /history/:symbol

Field Bazaar listing, read 19:19:47 UTC Live 402, read 19:18:20 UTC Same?
Price 50000 ($0.05) 50000 ($0.05) Yes
Pay-to address 0xA6E1…E074 0xA6E1…E074 Yes
Network and asset Base (eip155:8453), USDC Base (eip155:8453), USDC Yes
Description 384 characters, last updated 2026-10-18 477 characters No. The listing lacks: "An unlogged symbol, an invalid range or a range with no readings is refused and not charged."
Tags None None Yes, and that is the problem
Output schema Present Present Yes

Automated checks, run on both routes at 19:19:26 and 19:19:27 UTC: 13 of the 15 can run without a payment. 11 passed and none failed. The other 2 only report information: no tags declared, and the search rank for each route's own opening words. The OpenAPI file also has what catalogs ask for apart from fix 3: x-payment-info objects with price and protocols on both paid routes, a 402 response, input parameters, info.x-guidance, and security: [] on every free route. /.well-known/x402 is present and lists both routes.

Next steps and recheck

  1. Make fixes 1 to 5 and deploy them. The 402 changes on purpose here, so compare it against the rewritten text rather than the old one.
  2. Make the two paid calls in fix 6.
  3. If x402scan does not show the service, register it at https://www.x402scan.com/resources/register. That needs a wallet sign-in, so the owner has to do it.

Recheck: read the listing the same day the paid calls settle, then run the three searches again one week later. It counts as fixed when both listings show the new description and 5 tags, and at least one route comes back for "crypto sentiment". Search ranking belongs to CDP, so better wording can improve the odds but cannot promise a position.

Not checked: