Home/Be discoverable

Be discoverable

Publish the page metadata and agent files the facilitator reads — and your Bazaar listing fills in with your name, logo, description and agent docs automatically.

// How discovery enrichment works
Two independent layers

1 · Listing — your first settled payment catalogs your endpoint in the Bazaar (that needs the bazaar extension, see the Get started guide). 2 · Enrichment — everything on this page. The facilitator visits your domain and reads your page metadata plus a short list of well-known agent files, then shows your name, logo, description and agent docs on your merchant and resource pages.

Enrichment is optional but free. Publish nothing and your listing still works — it just shows a masked address and no branding. Publish the files below and you control how you appear, without declaring anything in your 402.
1 · Put the files on the right domain

The facilitator derives your site from the domain of your most recently active paid endpoint — or, if you declared a website in the x402-merchant extension, from that. Files are read from the root of that origin, never from a sub-path.

Paid endpoint:  https://api.example.com/v1/analyze
                      ↓ same origin
Metadata read:  https://api.example.com/                      ← <head> tags
                https://api.example.com/.well-known/x402
                https://api.example.com/.well-known/agent-card.json
                https://api.example.com/llms.txt
If your API lives on api.example.com but your branding lives on example.com, either publish the files on the API domain too, or declare website: "https://example.com" in your x402-merchant extension so enrichment follows it.
2 · Your NFD — the shortcut that outranks everything

If your receiving (payTo) address holds an NFDomains name, your merchant page uses it first — ahead of your x402-merchant declaration and your site metadata. Fill in your NFD profile and you're branded across the facilitator without touching your server at all.

name → your display name + verified badge avatar → your logo (IPFS fine) website → linked badge twitter · github · telegram · discord · email → social badges

Verified properties win over user-defined ones, so verify what you can. The lookup is by the exact receiving address you advertise in payTo — an NFD on a different wallet won't be found.

Who wins: the full precedence
Name          NFD name      →  x402-merchant name  →  og:title  →  <title>
Logo          NFD avatar    →  x402-merchant logo  →  apple-touch-icon → icon → /favicon.ico
Description   og:description  →  <meta name="description">
Links         NFD website + socials (twitter, github, telegram, discord, email)
Agent docs    the well-known files below

So: NFD for identity, your 402 for categories, your site for the description and banner, well-known files for what agents read next. Any layer you skip simply falls through to the next.

3 · Page & OpenGraph metadata

The root page is fetched once and parsed for these tags — first match wins:

Name og:title → <title> Description og:description → meta[description] Brand og:site_name Banner og:image → twitter:image Logo apple-touch-icon → icon → /favicon.ico Accent theme-color
<!-- Serve this on the ROOT page of the domain that hosts your paid endpoints -->
<head>
  <title>EXAMPLE API — premium endpoints, paid per request</title>
  <meta name="description" content="Premium API endpoints, paid per request in USDC on Algorand. No accounts, no API keys, no subscriptions." />

  <!-- OpenGraph: what the Bazaar and social cards read first -->
  <meta property="og:site_name" content="EXAMPLE API" />
  <meta property="og:title" content="EXAMPLE API — premium endpoints, paid per request" />
  <meta property="og:description" content="Premium API endpoints, paid per request in USDC on Algorand. No accounts, no API keys, no subscriptions." />
  <meta property="og:image" content="https://your-domain.com/og.png" />
  <meta property="og:url" content="https://your-domain.com" />
  <meta name="twitter:card" content="summary_large_image" />

  <!-- Your logo: apple-touch-icon wins (square, largest), then any icon -->
  <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
  <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png" />

  <meta name="theme-color" content="#2EE6C5" />
</head>

Relative paths are fine — they're resolved against your origin. The page must answer 200 as text/html; only the first 128 KB is parsed and the fetch times out after 4 seconds, so keep your <head> near the top.

// Agentic files
4 · Well-known files the facilitator reads

Each of these is probed at your origin. Every one that exists is listed on your merchant and resource pages as a link agents can follow — publish the ones that fit you, skip the rest.

https://your-domain.com/.well-known/x402              → x402 Discovery
https://your-domain.com/.well-known/agent-card.json  → A2A Agent Card
https://your-domain.com/.well-known/agent.json       → Agent Manifest
https://your-domain.com/.well-known/ai-plugin.json   → AI Plugin
https://your-domain.com/.well-known/mcp.json         → MCP Manifest
https://your-domain.com/llms.txt                     → llms.txt

From JSON files the facilitator takes name (or name_for_human, or title) and description (or description_for_human). From llms.txt it takes the first markdown # heading as the name. Everything else in your files is yours — agents read them in full.

x402 discovery — /.well-known/x402

A static index of your paid endpoints, for agents that want to know your prices before making a request.

// https://your-domain.com/.well-known/x402
{
  "x402Version": 2,
  "name": "EXAMPLE API",
  "description": "Premium API endpoints, paid per request in USDC on Algorand.",
  "resources": [
    {
      "url": "https://your-domain.com/api/analyze",
      "method": "POST",
      "description": "Analyze text — 0.01 USDC per call",
      "network": "algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=",
      "asset": "31566704",
      "amount": "10000",
      "payTo": "YOUR_ALGORAND_MERCHANT_ADDRESS"
    }
  ]
}
A2A agent card — /.well-known/agent-card.json
// https://your-domain.com/.well-known/agent-card.json   (A2A)
{
  "name": "EXAMPLE API",
  "description": "Premium API endpoints, paid per request in USDC on Algorand.",
  "url": "https://your-domain.com",
  "version": "1.0.0",
  "capabilities": { "streaming": false },
  "defaultInputModes": ["text"],
  "defaultOutputModes": ["text"],
  "skills": [
    {
      "id": "analyze",
      "name": "Analyze text",
      "description": "Returns a short summary. Paid per call via x402 (0.01 USDC).",
      "tags": ["x402", "algorand", "nlp"]
    }
  ]
}
AI plugin — /.well-known/ai-plugin.json
// https://your-domain.com/.well-known/ai-plugin.json
{
  "schema_version": "v1",
  "name_for_human": "EXAMPLE API",
  "name_for_model": "my-api-co",
  "description_for_human": "Premium API endpoints, paid per request in USDC on Algorand.",
  "description_for_model": "Call EXAMPLE API tools; each request is paid with x402 (HTTP 402).",
  "api": { "type": "openapi", "url": "https://your-domain.com/openapi.json" },
  "logo_url": "https://your-domain.com/logo.png",
  "contact_email": "hello@your-domain.com"
}
MCP manifest — /.well-known/mcp.json
// https://your-domain.com/.well-known/mcp.json
{
  "name": "EXAMPLE API MCP",
  "description": "MCP server exposing EXAMPLE API's x402-paid tools.",
  "version": "1.0.0",
  "transport": { "type": "sse", "url": "https://your-domain.com/sse" },
  "tools": [
    { "name": "analyze", "description": "Analyze text — paid per call in USDC (x402)." }
  ]
}
Agent manifest — /.well-known/agent.json
// https://your-domain.com/.well-known/agent.json   (generic manifest)
{
  "name": "EXAMPLE API",
  "description": "Premium API endpoints, paid per request in USDC on Algorand.",
  "url": "https://your-domain.com",
  "documentation": "https://your-domain.com/llms.txt",
  "payments": { "protocol": "x402", "network": "algorand", "asset": "USDC" }
}
llms.txt

Plain markdown for LLMs: what you do, what you charge, how to pay. The first # line is your name.

# EXAMPLE API

> Premium API endpoints, paid per request in USDC on Algorand. Every endpoint answers HTTP 402
> with x402 payment requirements; pay in USDC and the response is yours.
> No accounts, no API keys, no subscriptions.

## Paid endpoints
- [Analyze](https://your-domain.com/api/analyze): POST a document, get the analysis. 0.01 USDC.
- [Report](https://your-domain.com/api/report): GET a generated report. 0.01 USDC.

## Paying
- Protocol: x402 (v2), settled by https://facilitator.goplausible.xyz
- Network: Algorand MainNet · Asset: USDC (31566704)
- Clients: any x402 client — see https://facilitator.goplausible.xyz/guide/use

## Docs
- [OpenAPI](https://your-domain.com/openapi.json)
agents.md — for the agents themselves

Operating instructions for agents already using you: how to pay, what each endpoint takes, what to assume. The facilitator doesn't index this one — publish it because coding agents and crawlers read it straight from your domain, the same way they read llms.txt.

# EXAMPLE API

Instructions for agents working with this service.

## Payment
Every endpoint under /api is x402-paid. On HTTP 402, read the PAYMENT-REQUIRED
header (base64 JSON), pay the advertised requirement in USDC on Algorand, then
retry the same request with the PAYMENT-SIGNATURE header.

## Endpoints
- POST /api/analyze — { "text": string } → { "result": object } — 0.01 USDC
- GET  /api/report?id=... → { "report": object } — 0.01 USDC

## Notes
- Prices are advertised in the 402; never assume them.
- Settlement is handled by facilitator.goplausible.xyz — you never pay gas.
// Serving them correctly
5 · The one mistake that breaks everything
An SPA catch-all that answers index.html for missing paths counts as "file absent". The facilitator treats an HTML body on a .well-known or .txt path as a miss — otherwise every SPA on the internet would look like it publishes every file. Serve the real bytes, and register these routes before your fallback.
// Express — serve the well-known files BEFORE any SPA fallback
import express from "express";
const app = express();

// 1) static well-known + agent docs (real files, real content types)
app.use("/.well-known", express.static("public/.well-known", {
  setHeaders: (res) => res.setHeader("Content-Type", "application/json"),
}));
app.get("/llms.txt",  (_q, r) => r.type("text/plain").sendFile("llms.txt",  { root: "public" }));
app.get("/agents.md", (_q, r) => r.type("text/markdown").sendFile("agents.md", { root: "public" }));

// 2) ...your paid routes and paymentMiddleware...
// 3) SPA fallback LAST — otherwise it swallows the paths above
// app.get("*", (_q, r) => r.sendFile("index.html", { root: "public" }));
# Serve the files as-is — never let an SPA catch-all answer these paths.
location = /.well-known/x402      { default_type application/json; alias /srv/site/x402.json; }
location = /.well-known/agent-card.json { default_type application/json; alias /srv/site/agent-card.json; }
location = /llms.txt              { default_type text/plain; alias /srv/site/llms.txt; }
location = /agents.md             { default_type text/markdown; alias /srv/site/agents.md; }
Status must be 200 JSON must parse Timeout 3s per file Host public only — no localhost/private IPs CORS not needed — the fetch is server-side
6 · Check your work

Results are cached for 24 hours. To see changes immediately, open your merchant page and hit ⟳ Refresh metadata — it re-reads your site and re-probes every file. 🩺 x402 Doctor on the same page grades your 402s and explains any missing BAZAAR or HACKATHON badge.

Questions or feedback?

Something not showing up, or a file format you'd like the facilitator to read? Drop it in the GoPlausible OpenBox — every submission is read.