x402 List

API Documentation

API Documentation

Base URL: https://x402-list.com/api/v1/

All endpoints return JSON. No authentication required for read access. Rate limit: 200 req/min per IP (soft-throttled above 100). You can also browse the service directory or submit a new service via the web interface.

Quick start for agents

Everything in this directory is available as machine-readable JSON. No JavaScript, no login, no SDK required.

# List online services sorted by uptime
$ curl https://x402-list.com/api/v1/services?status=online&sort=uptime&ref=docs

# Fetch a specific service with endpoints and pricing
$ curl https://x402-list.com/api/v1/services/<slug>?ref=docs

# Get the OpenAPI 3.1 specification
$ curl https://x402-list.com/openapi.json

Agent-first resources: /openapi.json · /llms.txt · /llms-full.txt

MCP server

A first-party Model Context Protocol server exposes this API to MCP clients through 5 read-only tools: search_x402_services, get_service, find_best_service, check_health, and get_facilitator_volumes.

Hosted endpoint (Streamable HTTP): https://mcp.x402-list.com/mcp. Local stdio via npm: npx -y x402-list-mcp. Example client config:

{
  "mcpServers": {
    "x402-list": {
      "command": "npx",
      "args": ["-y", "x402-list-mcp"]
    }
  }
}

GET /api/v1/services

Returns a paginated list of all registered x402 services.

Query Parameters

ParamTypeDescription
networkstringFilter by network abbreviation, case-insensitive: BSE, SOL, POL, ARB, BSP, AVX (see /networks). Full names like base or solana are not matched: unrecognized values are silently ignored and return the unfiltered list
statusstringFilter by status: online, degraded, offline, unknown
categorystringFilter by category, case-insensitive (see /categories)
sortstringSort order: newest (default), uptime, cheapest, endpoints
qstringSubstring search across name, description, category, and base URL
pageintegerPage number (default: 1)
per_pageintegerResults per page, max 100 (default: 25)

Example Response (?per_page=2)

{
  "data": [
    {
      "slug": "heron",
      "name": "Heron",
      "description": "Measures how visible a website is to AI search engines and returns a structured improvement plan. Per-audit price quoted in USDC on Base.",
      "base_url": "https://heronapp.io",
      "website_url": "https://heronapp.io",
      "category": "AI",
      "status": "online",
      "verified": false,
      "endpoint_count": 1,
      "min_price_usd": 0.25043,
      "networks": ["BSE"],
      "networks_caip2": ["eip155:8453"],
      "uptime_24h": 100,
      "avg_response_time_ms": 306,
      "last_checked_at": "2026-07-06T10:21:00.405Z",
      "created_at": "2026-07-02T20:13:25.690Z"
    },
    {
      "slug": "netintel",
      "name": "NetIntel",
      "description": "Pay-per-call network and domain intelligence API: DNS, SSL/TLS, WHOIS/RDAP, email security, IP reputation, OSINT.",
      "base_url": "https://netintel.dev",
      "website_url": "https://netintel.dev",
      "category": "AI",
      "status": "online",
      "verified": false,
      "endpoint_count": 37,
      "min_price_usd": 0,
      "networks": ["BSE"],
      "networks_caip2": ["eip155:8453"],
      "uptime_24h": 100,
      "avg_response_time_ms": 77,
      "last_checked_at": "2026-07-06T10:29:02.849Z",
      "created_at": "2026-07-01T13:57:51.651Z"
    }
  ],
  "meta": {
    "total": 86,
    "page": 1,
    "per_page": 2,
    "total_pages": 43
  }
}

GET /api/v1/services/:slug

Returns full details for a single service, including every active endpoint with its per-network pricing. Unknown slugs return a 404 error envelope (see Response Format below).

Example Response (endpoints truncated to 1 entry)

{
  "data": {
    "slug": "netintel",
    "name": "NetIntel",
    "description": "Pay-per-call network and domain intelligence API: DNS, SSL/TLS, WHOIS/RDAP, email security, IP reputation, OSINT.",
    "base_url": "https://netintel.dev",
    "website_url": "https://netintel.dev",
    "category": "AI",
    "status": "online",
    "verified": false,
    "consecutive_failures": 0,
    "check_interval_minutes": 15,
    "last_checked_at": "2026-07-06T10:29:02.852Z",
    "created_at": "2026-07-01T13:57:51.651Z",
    "uptime": { "24h": 100, "7d": 100, "30d": 100, "90d": 100 },
    "avg_response_time_ms": 77,
    "total_checks": 438,
    "networks": ["BSE"],
    "networks_caip2": ["eip155:8453"],
    "asset": "USDC",
    "endpoints": [
      {
        "id": "a9d34456-f44f-4383-8696-b2acbe46f6bf",
        "method": "GET",
        "path": "/asn-lookup/analyze",
        "description": null,
        "mime_type": null,
        "is_active": true,
        "first_seen_at": "2026-07-01T13:57:51.651Z",
        "last_seen_at": "2026-07-06T10:29:02.775Z",
        "min_price_usd": 0.03,
        "networks": ["BSE"],
        "pricing": [
          {
            "scheme": "exact",
            "network": "eip155:8453",
            "network_caip2": "eip155:8453",
            "asset_address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
            "asset_address_norm": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
            "asset_name": "USDC",
            "price": "30000",
            "price_usd": "0.0300000000",
            "pay_to": "0xdaDc335482AD545296Fd7b28518A251fFCbEb9Df",
            "max_timeout_seconds": 300
          }
        ]
      }
    ]
  }
}

GET /api/v1/services/:slug/uptime

Returns daily uptime rollups for the service over the requested period, newest first: one entry per day with uptime percentage, average response time, and check counts.

Query Parameters

ParamTypeDescription
periodstringTime window: 24h, 7d, 30d, 90d (default: 30d). Any other value returns 400

Example Response (?period=7d, truncated to 2 entries)

{
  "data": [
    {
      "period_start": "2026-07-06T00:00:00.000Z",
      "period_end": "2026-07-07T00:00:00.000Z",
      "uptime_percentage": 100,
      "avg_response_time_ms": 69.76,
      "total_checks": 38,
      "successful_checks": 38
    },
    {
      "period_start": "2026-07-05T00:00:00.000Z",
      "period_end": "2026-07-06T00:00:00.000Z",
      "uptime_percentage": 100,
      "avg_response_time_ms": 71.18,
      "total_checks": 90,
      "successful_checks": 90
    }
  ]
}

GET /api/v1/services/:slug/volume

Returns measured on-chain settlement volume for the service over time (USD), one point per UTC day, oldest first. Volume is read directly on-chain by settler attribution over the service's payTo mapping (USDC only), never self-reported, and is a conservative undercount: only settlements the monitor observed are counted. The series is honest-empty until a settlement is observed. The status and null-vs-zero semantics are carried on the service detail's assessment.traction block.

Query Parameters

ParamTypeDescription
periodstringTime window: 24h, 7d, 30d, 90d, all (default: 90d). all reads the full recorded history. Any other value returns 400

Example Response (?period=7d, truncated to 2 entries)

{
  "data": [
    {
      "date": "2026-07-05",
      "volume_usd": 12.47,
      "tx_count": 39
    },
    {
      "date": "2026-07-06",
      "volume_usd": 9.8,
      "tx_count": 31
    }
  ]
}

GET /api/v1/services/:slug/buyers

Returns the measured distinct on-chain buyer count for the service over time, one point per UTC day, oldest first. Distinct buyers are counted straight from the raw settlements per day (never summed from a rollup) over the service's payTo mapping, USDC only. Like the volume series it is a conservative undercount and honest-empty until a settlement is observed.

Query Parameters

ParamTypeDescription
periodstringTime window: 24h, 7d, 30d, 90d, all (default: 90d). all reads the full recorded history. Any other value returns 400

Example Response (?period=7d, truncated to 2 entries)

{
  "data": [
    {
      "date": "2026-07-05",
      "unique_buyers": 7
    },
    {
      "date": "2026-07-06",
      "unique_buyers": 5
    }
  ]
}

GET /api/v1/services/:slug/checks

Returns individual health-check results for a service, newest first.

Query Parameters

ParamTypeDescription
limitintegerNumber of results, max 100 (default: 20)
offsetintegerOffset for pagination (default: 0)

Example Response (?limit=2)

{
  "data": [
    {
      "id": "aa7af11f-d67b-4b32-9539-79758b3623fa",
      "checked_at": "2026-07-06T10:29:02.849Z",
      "response_time_ms": 72,
      "status_code": 402,
      "is_up": true,
      "error_message": null,
      "endpoints_found": 37
    },
    {
      "id": "00f471af-8b24-44a4-9e44-e99e28800c5b",
      "checked_at": "2026-07-06T10:13:02.631Z",
      "response_time_ms": 66,
      "status_code": 402,
      "is_up": true,
      "error_message": null,
      "endpoints_found": 37
    }
  ],
  "meta": {
    "total": 438
  }
}

GET /api/v1/checks

Live feed of health checks across all services, newest first. Useful for building real-time dashboards.

Query Parameters

ParamTypeDescription
limitintegerNumber of results, max 100 (default: 50)
offsetintegerOffset for pagination (default: 0)

Example Response (?limit=2)

{
  "data": [
    {
      "id": "dfb29787-0fa7-49d7-ba89-6e9ae7ab3925",
      "checked_at": "2026-07-06T10:29:20.071Z",
      "is_up": false,
      "response_time_ms": 2500,
      "status_code": null,
      "endpoints_found": 0,
      "service_name": "Sivut Public Data APIs",
      "service_slug": "sivut-public-data-apis",
      "service_status": "offline"
    },
    {
      "id": "d602008c-e915-4b27-b868-f5d6f6f0a05d",
      "checked_at": "2026-07-06T10:29:02.942Z",
      "is_up": true,
      "response_time_ms": 953,
      "status_code": 402,
      "endpoints_found": 3,
      "service_name": "AsterPay",
      "service_slug": "asterpay",
      "service_status": "online"
    }
  ],
  "meta": {
    "total": 300469
  }
}

GET /api/v1/status

Aggregate platform health: counts by status plus a per-service status entry for every listed service (the services array is truncated to 2 entries here).

Example Response

{
  "data": {
    "total": 86,
    "online": 68,
    "degraded": 9,
    "offline": 8,
    "unknown": 1,
    "services": [
      {
        "slug": "2s-io",
        "name": "2s.io",
        "status": "online",
        "last_checked_at": "2026-07-06T10:16:01.134Z",
        "consecutive_failures": 0,
        "uptime_24h": 100,
        "avg_response_time_ms": 185.45
      },
      {
        "slug": "aeo-audit-api",
        "name": "AEO Audit API",
        "status": "online",
        "last_checked_at": "2026-07-06T10:25:00.433Z",
        "consecutive_failures": 0,
        "uptime_24h": 100,
        "avg_response_time_ms": 285.53
      }
    ]
  }
}

GET /api/v1/networks

Lists all blockchain networks tracked by x402 List, with per-network service counts and average uptime. The abbreviation values are what the ?network= filter on /services accepts. Response truncated to 2 entries here.

Example Response

{
  "data": [
    {
      "id": "836f6a83-251b-41ba-b44a-c6be54139ebb",
      "caip2_id": "eip155:8453",
      "caip2": "eip155:8453",
      "name": "Base",
      "abbreviation": "BSE",
      "chain_type": "evm",
      "is_mainnet": true,
      "explorer_url": "https://basescan.org",
      "service_count": 79,
      "avg_uptime": 89.6
    },
    {
      "id": "393fd87c-3aa5-4f2e-86c7-52a7623d9d66",
      "caip2_id": "solana:5eykt4usfv8p8njdtrepy1vzqkqzkvdp",
      "caip2": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
      "name": "Solana",
      "abbreviation": "SOL",
      "chain_type": "svm",
      "is_mainnet": true,
      "explorer_url": "https://solscan.io",
      "service_count": 26,
      "avg_uptime": 96
    }
  ],
  "meta": {
    "avg_uptime_method": "per-service mean of the latest daily uptime rollup"
  }
}

GET /api/v1/stats

Platform-wide aggregate statistics: service and endpoint totals, uptime averages, pricing distribution, and a per-network breakdown (truncated to 2 entries here).

Example Response

{
  "data": {
    "total_services": 86,
    "total_endpoints": 436,
    "total_networks": 5,
    "total_networks_note": "mainnet networks only; networks[] includes testnets flagged by is_mainnet",
    "avg_uptime_24h": 90.5,
    "avg_uptime_7d": 91,
    "avg_uptime_method": "per-service mean of the latest daily uptime rollup",
    "avg_response_time_ms": 405,
    "checks_per_hour": 344,
    "pricing": {
      "avg_price_usd": 0.418,
      "min_price_usd": 0,
      "max_price_usd": 19.97,
      "median_price_usd": 0.005
    },
    "networks": [
      { "abbreviation": "BSE", "is_mainnet": true, "service_count": 79, "avg_uptime": 89.6 },
      { "abbreviation": "SOL", "is_mainnet": true, "service_count": 26, "avg_uptime": 96 }
    ]
  }
}

GET /api/v1/categories

Lists the category labels currently in use, as a flat array of strings. Use these values for the ?category= filter on /services and the category field of POST /submit. The former /api/v1/tags taxonomy has been removed and now returns 410 Gone.

Example Response

{
  "data": ["AI", "Blockchain", "Compute", "Content", "Data", "Finance", "Other"]
}

GET /api/v1/facilitators

Paginated list of x402 facilitators with settlement volumes measured on-chain, sorted by volume in the selected timeframe. verification is on-chain (measured from blockchain transactions) or listed (chain declared by a settler address, not yet measured).

Query Parameters

ParamTypeDescription
timeframestringWindow that drives the sort order: 24h, 7d, 30d, all (default: 7d)
includestringComma-separated optional embeds: timeseries (daily volume series) and/or chains (per-network, per-token breakdown)
daysintegerLength of the embedded timeseries window, 1 to 90 (default: 30, only with include=timeseries)
pageintegerPage number (default: 1)
per_pageintegerResults per page, max 100 (default: 25)

Example Response (truncated to 2 entries)

{
  "data": [
    {
      "facilitator_id": "coinbase",
      "name": "Coinbase",
      "website_url": "https://docs.cdp.coinbase.com/x402/welcome",
      "volume_usd_24h": 2427.75,
      "volume_usd_7d": 36219.99,
      "volume_usd_30d": 193952.67,
      "volume_usd_all": 1573230.28,
      "tx_count_24h": 151811,
      "tx_count_7d": 1399119,
      "tx_count_30d": 8869191,
      "tx_count_all": 16978418,
      "last_activity_at": "2026-07-06T00:00:00.000Z",
      "settler_count": 35,
      "verification": "on-chain"
    },
    {
      "facilitator_id": "mrdn",
      "name": "Meridian",
      "website_url": "https://docs.mrdn.finance",
      "volume_usd_24h": 2331.97,
      "volume_usd_7d": 32219.96,
      "volume_usd_30d": 187217.82,
      "volume_usd_all": 1236223.48,
      "tx_count_24h": 113,
      "tx_count_7d": 1709,
      "tx_count_30d": 8315,
      "tx_count_all": 57941,
      "last_activity_at": "2026-07-06T00:00:00.000Z",
      "settler_count": 1,
      "verification": "on-chain"
    }
  ],
  "meta": {
    "total": 28,
    "page": 1,
    "per_page": 25,
    "total_pages": 2,
    "timeframe": "7d"
  }
}

POST /api/v1/submit

Submit a new x402-compatible service for review and inclusion in the directory. Endpoints are probed automatically for valid HTTP 402 responses, then a human reviews the submission before it is listed. Submissions from free hosting and dev-tunnel domains (vercel.app, workers.dev, ngrok, trycloudflare, etc.) are rejected with 400: production services must be on their own domain. Each email address may submit once every 7 days (see Rate Limiting below), and submissions still pending after the 7-day review window are auto-rejected with an email notification. The same endpoint also accepts x402 facilitator submissions: see the next section.

Paid resubmission after a rejection. If the latest submission for the same email or the same service URL was rejected less than 14 days ago, resubmitting is not free: it costs a one-time $0.50 USDC (x402) payment on Base, which replaces the 7-day cooldown (pay and re-enter immediately). Once 14 days have passed since the rejection, resubmitting is free again. Without payment the endpoint answers HTTP 402 with a PAYMENT-REQUIRED header and an accepts[] body; pay with an x402-capable client and retry the same request with a PAYMENT-SIGNATURE header. On success the 201 carries a PAYMENT-RESPONSE header. First-time submissions, and resubmissions whose latest is still pending or approved, are unaffected.

Request Body (JSON, all fields required except notes)

FieldTypeDescription
urlstringBase URL of the x402 service
emailstringSubmitter contact email
service_namestringHuman-readable name of the service (max 255 chars)
descriptionstringBrief description of what the service does
website_urlstringPublic website URL
categorystringService category (use /categories for valid values)
endpointsstring[]Endpoint paths to probe, max 50 (e.g. ["/v1/generate"])
notesstringAdditional context (optional)

Example Request

curl -X POST https://x402-list.com/api/v1/submit \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "email": "operator@example.com",
    "service_name": "Example x402 API",
    "description": "AI text generation via x402 micropayments",
    "website_url": "https://example.com",
    "category": "AI",
    "endpoints": ["/v1/generate", "/v1/classify"],
    "notes": "Optional context about the service"
  }'

Example Response (201; probe_result is null if the probe timed out)

{
  "data": {
    "submission_id": "7f0d2c5e-9a41-4b3a-8c67-2f51f0f8a915",
    "status": "pending",
    "probe_result": {
      "endpoints_found": 2,
      "errors": []
    }
  }
}

Paid Resubmission Response (402; only when the latest submission for this email or URL was rejected)

The PAYMENT-REQUIRED response header carries the same x402 object base64-encoded, without the app-level message field (which is body-only). Pay the single accepts[0] option ($0.50 USDC on Base) and retry with a PAYMENT-SIGNATURE header.

{
  "x402Version": 2,
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "asset": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
      "amount": "500000",
      "payTo": "0x0000000000000000000000000000000000000000",
      "maxTimeoutSeconds": 300,
      "extra": { "name": "USD Coin", "version": "2" }
    }
  ],
  "resource": {
    "url": "https://x402-list.com/api/v1/submit",
    "description": "Resubmission fee after a rejected submission",
    "mimeType": "application/json",
    "serviceName": "x402 List"
  },
  "error": "resubmission_fee_required",
  "message": "A submission from this email or for this URL was rejected less than 14 days ago, so resubmitting now requires a $0.50 x402 payment on Base (USDC). Pay with an x402-capable client by sending the request again with a PAYMENT-SIGNATURE header, or wait until 14 days have passed to resubmit for free. See https://x402-list.com/api for the flow."
}

POST /api/v1/submit (facilitator)

The same endpoint also accepts x402 facilitator submissions (settlement infrastructure operators, listed on /facilitators). Set "type": "facilitator" in the body to select this variant; without it the request is handled as a service submission. Facilitators are not probed over HTTP: instead, the enabled EVM chains among the declared networks are scanned for recent on-chain USDC settlement activity originated by the submitted settler addresses (30-day window, 15 seconds total budget). Solana and chains outside the measured registry are recorded as declared claims and checked during manual review. A failed or idle probe never blocks the submission: every facilitator submission is reviewed by a human before listing. Approved facilitators appear in GET /facilitators with verification: "listed" and switch to "on-chain" automatically once settlement volume is measured. Website URLs on free hosting or dev-tunnel domains are rejected with 400, and the 7-day per-email cooldown is tracked separately per submission type (see Rate Limiting below).

Request Body (JSON; required: type, email, facilitator_name, website_url, settler_addresses, networks)

FieldTypeDescription
typestringMust be facilitator to select this variant
emailstringSubmitter contact email
facilitator_namestringHuman-readable facilitator name (max 255 chars)
website_urlstringPublic website URL, on your own domain
settler_addressesstring[]On-chain addresses that originate settlement transactions, 1 to 25: 0x EVM (40 hex chars) or base58 Solana (32-44 chars). Also accepted as one comma/newline separated string
networksstring[]Declared settlement networks, 1 to 25 (e.g. base, polygon, solana). Enabled EVM chains are probed on-chain; the rest stay declared claims. Also accepted as one comma/newline separated string
descriptionstringWhat the facilitator does (optional)
facilitator_id_slugstringProposed identifier slug: lowercase letters, digits, single hyphens, max 100 chars (optional)
token_claimsstring[]Tokens the facilitator claims to settle, informational only (optional)
claimed_volume_usdstring | numberSelf-reported all-time settlement volume in USD, informational only: cross-checked against the on-chain probe at review (optional)
notesstringAdditional context (optional)

Example Request

curl -X POST https://x402-list.com/api/v1/submit \
  -H "Content-Type: application/json" \
  -d '{
    "type": "facilitator",
    "email": "operator@examplepay.com",
    "facilitator_name": "ExamplePay",
    "website_url": "https://examplepay.com",
    "description": "x402 settlement facilitator for USDC on Base and Solana",
    "settler_addresses": [
      "0x7c5fa2ab8c9d01234e56f7a8b9c0d1e2f3a4b5c6",
      "4Nd1mYQZ7d5xUEhFcq8xJwzB3tYkTn5eGf2u1V9pQrSt"
    ],
    "networks": ["base", "solana"],
    "facilitator_id_slug": "examplepay",
    "token_claims": ["USDC"],
    "claimed_volume_usd": "125000",
    "notes": "Settling x402 payments since May 2026"
  }'

Example Response (201; probe_result covers only the enabled EVM chains and is null if the probe could not run)

{
  "data": {
    "submission_id": "3b8e1f42-6c9d-4e07-9a15-d824c0b7f691",
    "status": "pending",
    "probe_result": {
      "addresses_with_activity": ["0x7c5fa2ab8c9d01234e56f7a8b9c0d1e2f3a4b5c6"],
      "tx_count": 1284,
      "errors": []
    }
  }
}

POST /api/v1/services/:slug/request-update

Owners of a listed service can propose changes to their listing's declarative metadata: name, description, website URL, category, contact email, NEW endpoint paths, and base URL as an always-manual identity change. Measured data (verified status, uptime, pricing, pay_to) can never be overridden through this channel: it stays read-only for everyone. An empty or omitted field always means unchanged, so a partial body can never clear or accidentally rewrite a field. Ownership is proven per request with a domain proof: the response returns a one-time token (shown once, only its hash is stored) that must be published as its own line at {base_url origin}/.well-known/x402list.txt on the CURRENT listed domain, then confirmed with verify-ownership below within 72 hours. Every verified request is reviewed by a human before anything is applied, and nothing about a pending request is shown publicly. One request per email per service every 7 days (429 with Retry-After); a browser form is available at /services/:slug/update.

Request Body (JSON or form-encoded; required: email, plus at least one changed field)

FieldTypeDescription
emailstringRequester contact email (cooldown key together with the service)
namestringNew display name (optional; empty = unchanged)
descriptionstringNew description (optional; empty = unchanged)
website_urlstringNew public website URL, own domain only (optional)
categorystringNew category (use /categories for valid values) (optional)
contact_emailstringNew listing contact email (optional)
base_urlstringNew base URL. Identity change: always reviewed manually, the slug never changes (optional)
endpoints_addstring[]NEW endpoint paths to add and monitor, max 50; already-listed paths are ignored. Also accepted as one comma/newline separated string (optional)

Example Request

curl -X POST https://x402-list.com/api/v1/services/example-x402-api/request-update \
  -H "Content-Type: application/json" \
  -d '{
    "email": "operator@example.com",
    "description": "AI text generation and classification via x402 micropayments",
    "endpoints_add": ["/v1/summarize"]
  }'

Example Response (201; the ownership_token is returned only here, only once)

{
  "data": {
    "request_id": "9c2f7b1e-4d3a-4f60-b2c8-51e9a0d47f36",
    "status": "pending_verification",
    "proposed_changes": {
      "description": "AI text generation and classification via x402 micropayments",
      "endpoints_add": ["/v1/summarize"]
    },
    "ownership_token": "x402list-verify-Ux3nT9qYw1Zb7kD4mR8sVfA2cH6jL0pEoI5gNyQtBw0",
    "well_known_url": "https://example.com/.well-known/x402list.txt",
    "well_known_path": "/.well-known/x402list.txt",
    "token_expires_at": "2026-07-09T14:00:00.000Z",
    "verify": {
      "method": "POST",
      "url": "/api/v1/services/example-x402-api/verify-ownership",
      "body": { "request_id": "9c2f7b1e-4d3a-4f60-b2c8-51e9a0d47f36" }
    },
    "note": "Publish the ownership_token as a line of the well-known file on the service's CURRENT domain, then call verify. The token is shown only once and expires in 72 hours. Review is manual after verification."
  }
}

POST /api/v1/services/:slug/verify-ownership

Step 2 of an update request: after publishing the token in the well-known file, call this endpoint with the request_id. The server re-fetches {base_url origin}/.well-known/x402list.txt on the CURRENT listed domain (with the same SSRF discipline as the monitor: public hosts only, manual redirects, 64KB body cap, 10s timeout) and matches the token against the file's lines. On success the token is consumed (one-shot) and, when the proposed diff touches base_url or adds endpoints, the standard HTTP 402 probe runs so the reviewer sees fresh probe_result data; a failed probe never blocks the request. The request then goes to manual review and the requester is notified by email of the outcome. Errors: 400 when the file cannot be fetched or the token is not in it, 404 unknown request or wrong service, 409 already reviewed, 410 token expired (submit a new request).

Example Request

curl -X POST https://x402-list.com/api/v1/services/example-x402-api/verify-ownership \
  -H "Content-Type: application/json" \
  -d '{"request_id": "9c2f7b1e-4d3a-4f60-b2c8-51e9a0d47f36"}'

Example Response (200; probe_result is null when the diff does not touch the probe surface)

{
  "data": {
    "request_id": "9c2f7b1e-4d3a-4f60-b2c8-51e9a0d47f36",
    "status": "verified",
    "probe_result": {
      "endpoints_found": 1,
      "errors": []
    },
    "note": "Ownership verified. The request now goes to manual review; you will be notified by email."
  }
}

POST /api/v1/suggestions

Paid suggestion box. Suggest a change, feature, bug, or data fix for the x402 List directory itself, and pay for the feedback channel in x402. Each suggestion costs a one-time $0.10 USDC (x402) payment on Base: the fee is the anti-spam skin-in-the-game, so there is no refund. Suggestions are internal and reviewed by a human; they are not published and carry no public roadmap. This endpoint is agent-first (JSON), and the paid flow is the standard x402 handshake: the first call returns HTTP 402 with a PAYMENT-REQUIRED header and an accepts[] body (single option, $0.10 USDC on Base); pay with an x402-capable client and retry the same request with a PAYMENT-SIGNATURE header. On success the 201 carries a PAYMENT-RESPONSE header.

Request Body (JSON; only text is required)

FieldTypeDescription
textstringThe suggestion (1 to 2000 characters)
categorystringOne of feature, bug, data, other (optional, defaults to other)
emailstringContact email to receive the review outcome (optional)

Example Request

curl -X POST https://x402-list.com/api/v1/suggestions \
  -H "Content-Type: application/json" \
  -H "PAYMENT-SIGNATURE: <base64 x402 payment payload>" \
  -d '{
    "text": "Add a /api/v1/services bulk export endpoint for offline indexing",
    "category": "feature",
    "email": "agent@example.com"
  }'

Example Response (201; PAYMENT-RESPONSE header carries the settlement receipt)

{
  "data": {
    "id": "b1e7c3a4-2f6d-4c8b-9a10-5e2f7d0c1a34",
    "status": "received"
  }
}

Payment Required Response (402; when no PAYMENT-SIGNATURE is sent)

The PAYMENT-REQUIRED response header carries the same x402 object base64-encoded, without the app-level message field (which is body-only). Pay the single accepts[0] option ($0.10 USDC on Base) and retry with a PAYMENT-SIGNATURE header. When the payment layer is not configured, this endpoint answers HTTP 503 instead.

{
  "x402Version": 2,
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "asset": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
      "amount": "100000",
      "payTo": "0x0000000000000000000000000000000000000000",
      "maxTimeoutSeconds": 300,
      "extra": { "name": "USD Coin", "version": "2" }
    }
  ],
  "resource": {
    "url": "https://x402-list.com/api/v1/suggestions",
    "description": "Suggestion fee for x402 List directory feedback",
    "mimeType": "application/json",
    "serviceName": "x402 List"
  },
  "error": "suggestion_fee_required",
  "message": "Posting a suggestion to the x402 List directory requires a $0.10 x402 payment on Base (USDC). Pay with an x402-capable client: send the request again with a PAYMENT-SIGNATURE header. See https://x402-list.com/api for the flow."
}

GET /api/v1/openapi.json

Returns the full OpenAPI 3.1 specification for this API. Use it to auto-generate client libraries or import into tools like Postman. Also served at /openapi.json.

Response Format

All successful responses are a JSON object with a data key holding the requested resource (object or array). List endpoints add a meta key with pagination info such as total, page, per_page, and total_pages.

Error responses use an error key instead. code is a number mirroring the HTTP status:

{
  "error": {
    "code": 404,
    "message": "Service 'nonexistent-slug-xyz' not found"
  }
}

HTTP Status Codes

CodeMeaning
200Success
201Created (POST /submit)
400Bad request / invalid parameters
402Payment required: a metered request beyond the free daily quota (see Metering), or a paid write endpoint
404Resource not found
410Gone: endpoint removed (e.g. /api/v1/tags, replaced by /api/v1/categories)
429Rate limit exceeded, or POST /submit email cooldown (see below)
500Internal server error

Metering

Reads are free for agents and point queries. Sustained bulk pulling is metered: each IP gets 2,000 free GET requests per day (UTC day) across /api/v1/*. Beyond that quota, each additional request costs $0.01 USDC (x402) on Base, charged per request. The quota does not apply to /api/v1/openapi.json, to the write endpoints (POST /submit, POST /suggestions, and the ownership routes), or to /api/admin/*.

Every metered response carries an X-Meter-Remaining header with the free requests left today. Once the quota is exhausted the API answers metered requests with HTTP 402: pay accepts[0] ($0.01 USDC on Base) with an x402-capable client and retry the same request with a PAYMENT-SIGNATURE header; the successful response then carries a PAYMENT-RESPONSE header. The PAYMENT-REQUIRED response header carries the same x402 PaymentRequired object base64-encoded, without the app-level message field (which is body-only).

Example Response Header

X-Meter-Remaining: 1913

Example 402 (over the free daily quota)

{
  "x402Version": 2,
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "asset": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
      "amount": "10000",
      "payTo": "0x0000000000000000000000000000000000000000",
      "maxTimeoutSeconds": 300,
      "extra": { "name": "USD Coin", "version": "2" }
    }
  ],
  "resource": {
    "url": "/api/v1/services",
    "description": "x402 List API metered access (per request beyond the free daily quota)",
    "mimeType": "application/json",
    "serviceName": "x402 List"
  },
  "error": "metering_fee_required",
  "message": "This request is beyond the free daily quota (2,000 requests/day per IP). Each additional request costs $0.01 USDC (x402) on Base. Pay with an x402-capable client and retry the same request with a PAYMENT-SIGNATURE header. See https://x402-list.com/api for the flow."
}

Rate Limiting

All endpoints are rate-limited to 200 requests per minute per IP address (sliding window, resets every minute). Above 100 req/min the response includes X-RateLimit-Throttled: true as an advisory signal - requests still succeed. Above 200 req/min the API returns 429 Too Many Requests with a Retry-After header indicating seconds until the window resets.

X-RateLimit-Limit: 200
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1783339200
X-RateLimit-Throttled: true   # only when count > 100

POST /submit additionally enforces a 7-day cooldown per submitter email, tracked separately per submission type: a second submission of the same type (service or facilitator) from the same email within 7 days returns 429 with Retry-After set to the seconds left until the cooldown ends (up to 7 days, not the per-minute window). A service submission does not block a facilitator submission from the same email, and vice versa. Submissions of either type still pending after the 7-day review window are auto-rejected, with an email notification, so the address can submit again.