Listed, Not Listed: Putting AgentBadge on Circle's Agent Services Marketplace — and Telling Machines the Truth
We submitted the Agent-Readiness Scan to Circle's Agent Services Marketplace — POST /api/total-scan, x402-paid, USDC on Arc via EIP-3009 transferWithAuthorization. While the listing sits in pending_review, every machine-readable surface we own (llms.txt, skill.json, /.well-known/agentbadge.json, Organization JSON-LD) already declares it with the honest status — and the settle telemetry was shipped before the first sale.
We submitted our Agent-Readiness Scan to Circle's Agent Services Marketplace — POST /api/total-scan, x402-paid, USDC on Arc via EIP-3009 transferWithAuthorization. Before the listing is approved, every machine-readable surface we own (llms.txt, skill.json, /.well-known/agentbadge.json, Organization JSON-LD) already declares it — with the honest status pending_review, not listed. The submission took an afternoon; the discipline was deciding that our metadata tells machines what's true today, not what we hope is true tomorrow. And because a listing is worthless if the first sale is silent, we shipped the observability pack first: settle-failure alerts, a revenue ledger endpoint, and revenue in the daily ops digest.
Agents don't browse your website. They query an index.
A human finds a service on a marketplace page. An agent finds it in a machine-readable index — in Circle's case, GET https://api.circle.com/v2/x402/discovery/resources. That endpoint is the actual storefront: 2,650 resources when we checked, each carrying its accepts[] payment terms and provider metadata. The HTML catalog is a rendering of it, not the other way around.
So the question "are we listed?" has a precise, checkable answer — and today it's no:
curl -s 'https://api.circle.com/v2/x402/discovery/resources?query=total-scan' \
| jq '.items[].resource'
# → empty while pending_review
One caveat we hit immediately: ?query= matches fuzzily — agentbadge returned anchor-x402 on an "agent" substring. The reliable check is the resource URL or your payout wallet in accepts[].payTo, not the name.
What we submitted
| Field | Value |
|---|---|
| Service | AgentBadge Agent-Readiness Scan |
| Endpoint | POST https://agentbadge.xyz/api/total-scan |
| Payment | x402, USDC on Arc (eip155:5042002), EIP-3009 transferWithAuthorization |
| Flow | agent hits endpoint → 402 with price → signs authorization → gets the scan |
No API keys, no accounts, no custodial anything. The buyer is an agent; the payment is a signed authorization the facilitator settles on-chain.
The honest-status decision
Here's the part we almost got wrong by convention. Once we added the marketplace to our machine-readable surfaces, the natural status to write was listed. It will be true eventually — probably. But today it isn't, and an LLM agent reading our llms.txt or skill.json has no way to know that "listed" means "we submitted a form."
So a single registry — marketplace-listings.ts — feeds all four surfaces, and the status is pending_review:
/llms.txt— aDistributionsection naming the marketplace, endpoint, and rail/skill.json—ab:distributionwith the full listing records/.well-known/agentbadge.json—marketplace_listingsin the deployment descriptor- Organization JSON-LD —
sameAspointing at the catalog
When approval lands, one string changes — pending_review → listed — and every surface updates itself. The same mechanism protects us the other direction: if a listing gets delisted, we can't forget to update the JSON-LD.
The principle: don't claim listings you don't have. Services advertising marketplace presence that the discovery index doesn't return are teaching agents to distrust metadata — and the agent that trusts a stale claim fails at checkout, not at marketing.
resource and payTo — never by name alone. We built the telemetry before the first sale
A listing that goes live while your settlement errors are invisible is a listing you find out about from a support ticket. So before submission we shipped the observability pack:
- Settle-failure alerts — every x402 settle failure fires to Telegram/Discord, deduped by error reason over 15 minutes. Verify failures stay log-only: a bad signature isn't a business event, a broken settle is.
GET /api/ledger/revenue?days=N— ops rollup of paid legs: total, byDay, byEndpoint. A nonzerototalis the earliest possible "someone paid" signal.- Revenue in the ops digest —
x402Revenueblock with top endpoints rides the daily summary we already send ourselves.
And a subtle bug the tests caught: the econ-events schema was stripping the endpoint field the settle legs carried, so revenue-by-endpoint silently never attributed anything. Fix went upstream — @agentbadge/econ-events@0.1.4 — because attribution that only works on new fields is attribution that lies about the past.
What happens on approval
- The Discovery API query returns our
items[]entry —resource,accepts[],metadata.provider. pending_review→listedinmarketplace-listings.ts; all four surfaces update.- Verify
accepts[].network=eip155:5042002andpayTo= our wallet — the catalog rendering can lag the index. - Screenshot the catalog card, swap this article's hero, publish.
If review stalls past a few days, Circle's escalation path is documented (help.circle.com support form, or a ticket in the Build on Arc Discord). Manual review queues are a feature, not a bug — a marketplace that indexes without review is a spam list.
Status as of writing: submitted 2026-11-12, pending review. Check the index yourself — the command above is the same one we're watching.