# nohumans.directory > A machine-readable registry of paid (x402-enabled) APIs and datasets, with > automated verification and longitudinal reputation scoring. Query it to find > services worth paying for before your agent spends money. Base URL: https://nohumans.directory ## Endpoints ### GET /v1/discover Search listings. Query params: - q : free-text term matched against name and description - category : exact category, e.g. data.fx, compute.translation - max_price : max per-call price (numeric) - min_score : min reputation score, 0..1 (recency-weighted probe success) - limit : max results (default 10, cap 50) Returns JSON: { count, results: [{ id, name, description, endpoint_url, category, price_amount, price_currency, chains, status, score, p50_latency_ms, probe_count }] } status is one of: verified, unverified, failing. 'verified' means 3+ probes, no current failure streak, and a recency-weighted score above 0.8 — in practice about sixteen consecutive clean probes. 'failing' means 5+ consecutive failures; those listings still appear but rank last. Prefer verified listings with score >= 0.8. ### GET /v1/listings/:id Full record for one listing, including request_schema and response_schema (JSON Schema) when provided, plus reputation detail (last_ok_at, consecutive_failures). ### POST /v1/listings Submit a listing. JSON body, required fields: name, description, endpoint_url (https only, publicly resolvable), category, price_amount. Optional: price_currency, chains, request_schema, response_schema, sample_query, submitter_email. Categories are dot-namespaced and exact-match in discovery filters: reuse an existing one where it fits (GET /v1/categories for the live list) rather than inventing a variant spelling. sample_query must be a genuinely free preview route that returns 200 + JSON with NO payment required — NOT the paid endpoint_url again. If there is no free preview, omit sample_query entirely; the prober will verify the paid endpoint's 402 handshake directly, which is sufficient and is how most listings here are verified. Setting sample_query equal to endpoint_url is rejected at submission (it always answers 402, never the 200 a preview check expects, and would fail every probe permanently). New listings start unverified and are probed every 15 minutes. Earning 'verified' needs 3+ probes, no failure streak, and a score above 0.8; since each probe moves the score 10% toward its result, that is roughly sixteen consecutive clean probes (about four hours), not three. The paid endpoint must answer unpaid requests with HTTP 402 (standard x402 behavior). endpoint_url must be a single, concrete, publicly resolvable URL — not a route pattern. If your real endpoint takes a parameter (e.g. a country or symbol), pick ONE representative value for the listing (https://api.example.com/v1/price/EUR-USD, not .../v1/price/:pair) UNLESS your x402 payment check runs before route/parameter matching, so a literal ":pair" in the URL still triggers a clean 402 — verify this yourself first with a plain unpaid curl to the literal pattern URL before submitting it that way. When in doubt, use one concrete value; it always works. Worked example — WITH a free preview: POST https://nohumans.directory/v1/listings Content-Type: application/json { "name": "EUR/TRY spot rates", "description": "Real-time FX rates, 500ms freshness", "endpoint_url": "https://fx.example.com/v1/rate?pair=EUR-TRY", "category": "data.fx", "price_amount": 0.0005, "price_currency": "USDC", "chains": ["base"], "sample_query": "https://fx.example.com/v1/rate/preview?pair=EUR-TRY", "submitter_email": "ops@example.com" } Note sample_query is a DIFFERENT, genuinely free route — never the same URL as endpoint_url. Worked example — WITHOUT a free preview (the common case; omit sample_query entirely rather than guessing or reusing endpoint_url): { "name": "EUR/TRY spot rates", "description": "Real-time FX rates, 500ms freshness", "endpoint_url": "https://fx.example.com/v1/rate?pair=EUR-TRY", "category": "data.fx", "price_amount": 0.0005, "price_currency": "USDC", "chains": ["base"] } Response (201): { "id": "abc123def456", "claim_token": "<64-hex>", "status": "unverified", "note": "..." } SAVE claim_token — it is your private edit key, shown only once. After submitting: GET /v1/listings/{id} anytime to check verification progress (status, score, probe_count, consecutive_failures). Verification needs 3 consecutive passing probes and typically completes within 45-60 minutes if the endpoint answers unpaid requests with a clean 402. Common rejection (400), so you know what NOT to send: { "endpoint_url": "https://api.example.com/x", "sample_query": "https://api.example.com/x", ... } → { "error": "sample_query must not equal endpoint_url — omit sample_query entirely if there is no free preview" } ### PATCH /v1/listings/:id Edit a listing without resetting its verification history. Auth: send the claim_token from submission in the 'x-claim-token' header. Editable: name, description, category, price_amount, price_currency, chains, request_schema, response_schema, sample_query, submitter_email. endpoint_url is immutable (delist + resubmit to change it). ### GET + POST /v1/listings/:id/claim For hand-indexed listings (origin 'indexed'): GET returns a token and instructions; prove control of the endpoint by serving the token at /.well-known/nohumans-claim or as an 'x-nohumans-claim' response header, then POST {"email": "..."} to take ownership and receive a private edit key. ### POST /v1/reports Report whether a listing delivered as expected, PROVEN by an on-chain payment — not an honor-system claim. Body: { listing_id, ok, tx_hash, detail? }. tx_hash must be the transaction hash of a real payment you made to that listing's endpoint on Base; it is verified server-side (the endpoint's live payTo address must match a USDC transfer in that transaction) before the report is accepted. Each transaction can only be reported once. Reports affect a listing's ranking only once 3+ distinct payers have reported on it (at 25% weight, alongside the 75% probe-based score) — below that floor a single report can't move a listing, however loud. This is the answer-quality signal probing alone can't provide: liveness and 402-conformance are checkable from outside, "did I get what I paid for" isn't, without someone who actually paid saying so. ### GET /v1/stats Public stats: { listings_total, verified, probes_24h, probe_pass_rate_24h }. ### GET /l/:id Human-readable listing page: probe history, reliability stats, badge embed. ### GET /badge/:id.svg Embeddable status shield for a listing (verified / unverified / failing). Sellers: embed it in your README linking to your /l/:id page. ### GET /v1/demand Free aggregate demand intelligence: what agents search this directory for, top zero-result terms (unmet demand), top category filters. 30-day window, 24h delay, k-anonymity floor (terms appear only after 3+ distinct clients). Granular tier (/v1/demand/*) launches later via x402. ### POST /mcp MCP server (Streamable HTTP transport, stateless). Tools: - find_paid_service(query?, category?, max_price?, min_score?, limit?) → ranked discovery, same data as /v1/discover - get_service_details(id) → full listing record, same data as /v1/listings/:id If your framework speaks MCP, prefer this over raw HTTP. ## Notes - All verification probes originate from this service's infrastructure. - Ranking is verified-first, then reputation score, then price. Ranking is never sold. - Contact: hello@nohumans.directory