{"openapi":"3.1.0","info":{"title":"Agenstry","description":"Federated discovery hub for A2A agents.","version":"0.3.0"},"paths":{"/metrics":{"get":{"summary":"Metrics","description":"Endpoint that serves Prometheus metrics.","operationId":"metrics_metrics_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/":{"get":{"summary":"Home","operationId":"home__get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Q"}},{"name":"protocol","in":"query","required":false,"schema":{"type":"string","pattern":"^(all|a2a|mcp)$","default":"all","title":"Protocol"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","pattern":"^(relevance|price_asc|price_desc)$","default":"relevance","title":"Sort"}},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Category"}},{"name":"fragment","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Fragment"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/agents":{"get":{"summary":"Agents Index Page","description":"Paginated browse-index over the 2,600+ agent corpus.\n\nFilter chips: ``protocol`` (all / a2a / paid), ``category``,\n``verified`` (DNS-verified owner), ``has_revenue`` (≥1 USDC inflow\nin the 30d window).\n\nSort modes: ``quality`` (default, our 9-criterion conformance\nweighted), ``revenue`` (30d gross USDC), ``recent`` (last\ncard-change timestamp), ``name`` (alphabetical).","operationId":"agents_index_page_agents_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Q"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","pattern":"^(quality|revenue|recent|name)$","default":"quality","title":"Sort"}},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Category"}},{"name":"protocol","in":"query","required":false,"schema":{"type":"string","pattern":"^(all|a2a|paid)$","default":"all","title":"Protocol"}},{"name":"verified","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Verified"}},{"name":"has_revenue","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Has Revenue"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":96,"minimum":12,"default":36,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/agents.md":{"get":{"summary":"Agents Index Md","description":"Stainless-pattern AI-friendly markdown view of the agent directory.\n\nSame filters + sort as the HTML page; deterministic ordering so an\nAI consumer can paginate without surprises. ``page_size`` runs up\nto 200 here (vs 96 on HTML) because LLMs handle larger pages cheaply.","operationId":"agents_index_md_agents_md_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Q"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","pattern":"^(quality|revenue|recent|name)$","default":"quality","title":"Sort"}},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Category"}},{"name":"protocol","in":"query","required":false,"schema":{"type":"string","pattern":"^(all|a2a|paid)$","default":"all","title":"Protocol"}},{"name":"verified","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Verified"}},{"name":"has_revenue","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Has Revenue"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":10,"default":50,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/agents/{domain}.md":{"get":{"summary":"Agent Detail Md","operationId":"agent_detail_md_agents__domain__md_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/agents/{domain}":{"get":{"summary":"Managed Public Page","description":"Public doc / landing page for a hosted agent. Draft agents are\ninvisible — the owner sees their preview via /account, but a\ncounterparty hitting this URL gets a clean 404 until publish.","operationId":"managed_public_page_agents__domain__get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/agents/{domain}/snapshots/{snapshot_id}":{"get":{"summary":"Agent Snapshot Page","description":"Render a single historical snapshot of an agent's card.\n\nVisible publicly — card history is part of our trust signal. Owners use\nit to verify a downstream consumer is seeing the right version; auditors\nuse it to forensic the moment of drift.","operationId":"agent_snapshot_page_agents__domain__snapshots__snapshot_id__get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}},{"name":"snapshot_id","in":"path","required":true,"schema":{"type":"integer","title":"Snapshot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/agents/{domain}/dashboard":{"get":{"summary":"Agent Dashboard Page","description":"Per-agent visibility metrics dashboard. Publicly viewable; caller\nidentity is masked unless the viewer is the verified owner OR an\nauthenticated Pro/Platform user.\n\nSee app/api/rest.py:api_agent_metrics for the JSON form.","operationId":"agent_dashboard_page_agents__domain__dashboard_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/agents/{domain}/catalog/snapshots":{"get":{"summary":"Agent Catalog History Page","description":"Public catalog timeline for an agent. Same model as card snapshots.","operationId":"agent_catalog_history_page_agents__domain__catalog_snapshots_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mcp/{name}":{"get":{"summary":"Mcp Detail Page","operationId":"mcp_detail_page_mcp__name__get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/providers":{"get":{"summary":"Providers Page","operationId":"providers_page_providers_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/profile/{lei}":{"get":{"summary":"Lei Profile Page","description":"Public agent portfolio for one legal entity, keyed by registry id.\n\n``lei`` here matches whatever lives in ``Agent.lei`` (GLEIF LEI,\nKvK number, Companies House number, vLEI prefix, …). Acts as the\n\"KvK of agents\" — one URL per legal entity that lists every agent\nwe've cross-walked to that entity, with their conformance + revenue +\ndrift signals aggregated.\n\nDesigned to be SEO-indexable + embeddable. Every verified agent's\ndetail page already links here so the inbound link graph compounds:\nagent → /profile/<lei> → entity portfolio → individual agents. Same\npattern as a LinkedIn company page but for the agent web.","operationId":"lei_profile_page_profile__lei__get","parameters":[{"name":"lei","in":"path","required":true,"schema":{"type":"string","title":"Lei"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/providers/{org}":{"get":{"summary":"Provider Detail Page","operationId":"provider_detail_page_providers__org__get","parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string","title":"Org"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/submit":{"get":{"summary":"Submit Page","operationId":"submit_page_submit_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"summary":"Submit Post","description":"Open submission form — accepts any kind of resource through the\nsame single dispatcher as POST /api/submit. ``url`` and ``input`` are\nboth accepted (the latter wins) for backwards-compat with the old\nsubmit form that only knew about URLs.","operationId":"submit_post_submit_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_submit_post_submit_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/for-business":{"get":{"summary":"For Business Page","description":"Landing page positioning Agenstry for businesses that don't yet have an A2A agent.\n\nSurfaces the SMB-vertical coverage of our canonical-skill taxonomy and offers\na low-friction path to either claim a listing or deploy a real card via /submit.","operationId":"for_business_page_for_business_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/claim":{"get":{"summary":"Claim Page","operationId":"claim_page_claim_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"summary":"Claim Post","description":"Submit a business claim → triggers email confirmation → bootstrap\na live A2A managed agent on Agenstry.\n\nFlow:\n  1. Validate email + URL.\n  2. Insert BusinessClaim row with status='pending_confirmation' +\n     random confirmation_token.\n  3. Email the contact with a confirmation link\n     (``/claim/confirm/{token}``).\n  4. When clicked: sign the user in (magic-link), set\n     ``confirmed_at + user_id``, schedule background bootstrap\n     (gpt-5.4-mini + web_search), redirect to /claim/status/{token}.\n  5. The bootstrap creates a ManagedAgent + signed card hosted at\n     /agents/{domain}/.well-known/agent-card.json.\n\nThe website URL is now REQUIRED (was optional pre-bootstrap-flow) —\nthe entire pipeline depends on having a public site to scrape.","operationId":"claim_post_claim_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_claim_post_claim_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/claim/confirm/{token}":{"get":{"summary":"Claim Confirm","description":"Email-confirmation landing → sign in + start bootstrap.\n\nWhen the owner clicks the link in the confirmation email:\n  1. Look up the BusinessClaim by ``confirmation_token``.\n  2. Mint or fetch the User by ``contact_email``.\n  3. Sign them in (set session cookie).\n  4. Schedule the bootstrap background task.\n  5. Redirect to /claim/status/{token} (polls until live).\n\nIdempotent: clicking the link twice is safe — second click only\nre-asserts the session cookie, doesn't re-trigger bootstrap.","operationId":"claim_confirm_claim_confirm__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/claim/status/{token}":{"get":{"summary":"Claim Status","description":"Status page — polls every 5s until the bootstrap completes.","operationId":"claim_status_claim_status__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/claim/check":{"get":{"summary":"Claim Check","description":"Email-based claim status recovery.\n\nA common drop-off pattern: SMB owner submits a claim, closes the\nbrowser, can't find the cookie-bound /claim/status/{token} link\nagain. This endpoint lets them re-discover their pending claims\nby re-entering their email. We don't auth — we just show whether\na claim exists for this email and let them click through to the\nper-token status page (which is the only place that reveals the\nfull structured-data + agent-card preview).\n\nRate-limited at 30/hour per IP to slow enumeration of \"is X\nindexed as a claimer\". For privacy, we never list claims with a\ndifferent email than the one supplied.","operationId":"claim_check_claim_check_get","parameters":[{"name":"email","in":"query","required":false,"schema":{"type":"string","maxLength":255,"default":"","title":"Email"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/detect-business":{"get":{"summary":"Detect Business Endpoint","operationId":"detect_business_endpoint_api_detect_business_get","parameters":[{"name":"website_url","in":"query","required":false,"schema":{"type":"string","maxLength":2048,"default":"","title":"Website Url"}},{"name":"url","in":"query","required":false,"schema":{"type":"string","maxLength":2048,"default":"","title":"Url"}}],"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/compose":{"get":{"summary":"Compose Page","description":"UI for the compose endpoint. GET shows the form; POST renders the plan.","operationId":"compose_page_compose_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"summary":"Compose Post","operationId":"compose_post_compose_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_compose_post_compose_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/discover":{"get":{"summary":"Discover Page","description":"Public index of all active Agenstry-hosted agents.\n\nPositioned as the Agenstry registry — the missing public A2A agent index.\nEvery hosted agent is A2A v1.0+ conformant, JWS-signed, and crawlable.","operationId":"discover_page_discover_get","parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Vertical"}},{"name":"region","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":8},{"type":"null"}],"title":"Region"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/developers":{"get":{"summary":"Developers Page","description":"B2B landing page for the route-compose API.\n\nTargets developers building multi-agent systems who need a routing layer\nthat decomposes tasks and selects the best agent stack — without running\ntheir own registry.","operationId":"developers_page_developers_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/flows":{"get":{"summary":"Flows Page","description":"Public money-flows dashboard.\n\nRenders the full ``money_flows_full`` payload — moved from PAID to FREE\nin this commit. Top-25 with amounts + per-category + per-chain + 7/30/90d\nside-by-side windows + growth signal all visible without payment.\n\nThe PAID surface that remains is the *analytical* layer: ``flow_trends``\n(daily time-series + weekly cohorts + per-protocol split — the kind of\nleading-indicator pull a hedge-fund / VC bot does) and ``wallet_intel``\n(per-wallet portfolio drill-down across the index). Per-agent revenue\n+ uptime + drift was already free on /agents/{domain} via ``agent_stats``.","operationId":"flows_page_flows_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/analytics":{"get":{"summary":"Analytics Page","description":"Platform-wide call analytics — \"who's actually using us\".\n\nDrives one of the questions that matter most for any registry / infra\ncompany in 2026: is it Claude Desktop calling? Cursor? OpenAI's\nResponses API? Or is it random curl / bot traffic? Until we shipped\nthe s1t2u3v4w5x6 columns we genuinely didn't know.\n\nStays free + public — the answers are positioning content (proof\nwe're plugged into the agent web's biggest hosts) more than they\nare private signal. The paid analytical layer remains\n``flow_trends`` + ``wallet_intel`` + the owner dashboard's\nper-API-key breakdown (which IS private to the owner).","operationId":"analytics_page_analytics_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/caller-labels":{"get":{"summary":"Caller Labels Docs","description":"Full caller_kind → friendly label reference for partners + operators.","operationId":"caller_labels_docs_caller_labels_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/docs/caller-labels":{"get":{"summary":"Caller Labels Docs","description":"Full caller_kind → friendly label reference for partners + operators.","operationId":"caller_labels_docs_docs_caller_labels_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/enterprise/watchlist":{"post":{"summary":"Enterprise Watchlist Create","description":"Create a new watchlist entry for the Enterprise user.\n\nAccepts either:\n  * session cookie (browser dashboard form POST), OR\n  * ``Authorization: Bearer ekey_…`` (programmatic / data-pipeline\n    access — same token shape that unlocks /enterprise/ai/stream and\n    bypasses the paid-skill paywall).\n\nReturns the new row + the plaintext ``webhook_secret`` ONCE. After\nthat the secret never leaves the server (we only show its prefix in\nthe UI for identification).","operationId":"enterprise_watchlist_create_enterprise_watchlist_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_enterprise_watchlist_create_enterprise_watchlist_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/enterprise/watchlist/{watchlist_id}/delete":{"post":{"summary":"Enterprise Watchlist Delete","operationId":"enterprise_watchlist_delete_enterprise_watchlist__watchlist_id__delete_post","parameters":[{"name":"watchlist_id","in":"path","required":true,"schema":{"type":"integer","title":"Watchlist Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/enterprise":{"get":{"summary":"Enterprise Dashboard","description":"Enterprise tier dashboard (€99/mo).\n\nGates on ``user.plan in {'enterprise', 'platform'}`` (Platform grandfather\n-ed in — they paid the legacy Pro tier and get Enterprise read access for\nfree as long as they're subscribed; new Enterprise customers come in via\nthe dedicated checkout). Anonymous / Free / Pro users see a paywall page\nexplaining the value-prop and a \"Subscribe\" CTA.\n\nWhat's behind the gate:\n  1. Cross-platform pulse — week-over-week shifts in caller_kind /\n     surface / country / host-platform from the call log\n  2. Competitor monitoring — paste any LEI/domain, get every agent in\n     that portfolio with conformance + revenue + drift + caller mix\n  3. CSV exports — all the analytics surfaces as downloadable files\n  4. Webhook alerts on drift / new competitors / cohort shifts\n  5. Multi-seat (managed via the Stripe billing portal)\n  6. Priority crawl (15-min recrawl on watchlisted agents)\n\nFree + Pro users can still browse public analytics at /analytics + /hosts\n+ /flows — Enterprise stacks paid analytical depth + private competitor\nwatchlists on top.","operationId":"enterprise_dashboard_enterprise_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/enterprise/export/calls.csv":{"get":{"summary":"Enterprise Export Calls","description":"Bulk CSV export of agent_call_logs for Enterprise customers.\n\nStreams rows from the last 90 days with caller-attribution columns\n(surface, caller_kind, caller_agent_domain, caller_country,\nreferer_host, subject_kind, skill_id, mcp_name, agent_domain, …).\nDesigned for data-team workflows that want to load the corpus into\nSnowflake / BigQuery / Pandas for their own modelling.\n\nPrivacy contract — set 2026-05-21 after audit\n=============================================\n\nPre-audit shape: every row in the corpus for the last 90 days was\nstreamed regardless of which Enterprise customer was downloading,\nAND included ``user_id`` + ``api_key_prefix`` columns. That means\nEnterprise customer A could fingerprint Enterprise customer B's\nAgenstry users across every agent in the index. Exactly the\ncross-tenant competitive signal Enterprise tier is supposed to\nSELL — leaking it free was an active privacy + revenue bug.\n\nNow:\n\n  * **Rows are filtered to the caller's domains** — only agents the\n    Enterprise user has VERIFIED OWNERSHIP of, plus agents on their\n    Enterprise watchlist (the latter is the legitimate competitive-\n    intel surface they paid for). No verified ownership AND no\n    watchlist → empty CSV with the header row only, plus a\n    ``X-Agenstry-Scope`` header explaining the gate.\n  * **``user_id`` + ``api_key_prefix`` columns are GONE** — these\n    are Agenstry-identity columns and a watchlist consumer has no\n    legitimate need to fingerprint who-on-Agenstry called their\n    watched competitor. Caller attribution stays expressive via\n    ``caller_kind`` / ``caller_country`` / ``referer_host`` /\n    ``caller_agent_domain`` — same analytical value, zero\n    cross-account leakage.\n\nGates on plan in {enterprise, platform}. Free + Pro users get 402\nwith a clear \"subscribe to Enterprise\" hint instead of a 403, so the\nresponse works as a soft sales surface for prospects who hit the URL.","operationId":"enterprise_export_calls_enterprise_export_calls_csv_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/enterprise/compare":{"get":{"summary":"Enterprise Compare","description":"Enterprise MULTI screen — side-by-side compare up to 5 agents.\n\nPick 2-5 agent domains via ``?a=…&b=…&c=…`` and get a grid of\nhead cards + per-agent 30d revenue trajectories + caller-mix +\nskill mix + on-chain protocol info. Bloomberg Terminal's MULTI\nscreen pattern: pick instruments, see them aligned.","operationId":"enterprise_compare_enterprise_compare_get","parameters":[{"name":"a","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"A"}},{"name":"b","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"B"}},{"name":"c","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"C"}},{"name":"d","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"D"}},{"name":"e","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"E"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/enterprise/provider/{lei}":{"get":{"summary":"Enterprise Provider Intel","description":"Per-LEI provider intelligence — deepest cut on a legal entity.\n\nPublic ``/profile/{lei}`` is the free version; this one adds caller\nanalytics, daily revenue trajectory across the portfolio, top peer\ncallers, payment-rail mix that are gated to Enterprise.","operationId":"enterprise_provider_intel_enterprise_provider__lei__get","parameters":[{"name":"lei","in":"path","required":true,"schema":{"type":"string","title":"Lei"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/enterprise/skill/{skill_id}":{"get":{"summary":"Enterprise Skill Intel","description":"Per-canonical-skill market intelligence — supply/demand curve.","operationId":"enterprise_skill_intel_enterprise_skill__skill_id__get","parameters":[{"name":"skill_id","in":"path","required":true,"schema":{"type":"string","title":"Skill Id"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/enterprise/cohorts":{"get":{"summary":"Enterprise Cohorts List","description":"Saved cohorts dashboard. Inline create form + per-row totals.","operationId":"enterprise_cohorts_list_enterprise_cohorts_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"summary":"Enterprise Cohort Create","operationId":"enterprise_cohort_create_enterprise_cohorts_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_enterprise_cohort_create_enterprise_cohorts_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/enterprise/cohorts/{cohort_id}/delete":{"post":{"summary":"Enterprise Cohort Delete","operationId":"enterprise_cohort_delete_enterprise_cohorts__cohort_id__delete_post","parameters":[{"name":"cohort_id","in":"path","required":true,"schema":{"type":"integer","title":"Cohort Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/enterprise/api-keys":{"post":{"summary":"Enterprise Api Key Create","description":"Generate a new Enterprise API key. Plaintext returned ONCE.","operationId":"enterprise_api_key_create_enterprise_api_keys_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_enterprise_api_key_create_enterprise_api_keys_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/enterprise/api-keys/{key_id}/delete":{"post":{"summary":"Enterprise Api Key Delete","operationId":"enterprise_api_key_delete_enterprise_api_keys__key_id__delete_post","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"integer","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/enterprise/competitor/{lei_or_domain}":{"get":{"summary":"Enterprise Competitor","description":"Enterprise competitor-watch view.\n\nAccepts either an LEI (legal entity) OR a domain. Returns every\nindexed agent under that identifier with conformance + revenue +\ndrift snapshots + caller-mix breakdown. Effectively \"/profile/{lei}\non steroids\" — adds caller-attribution + drift timeline.\n\nSame auth gate as the rest of the Enterprise surface. Free users\ncan see /profile/{lei} (public, no caller breakdown).","operationId":"enterprise_competitor_enterprise_competitor__lei_or_domain__get","parameters":[{"name":"lei_or_domain","in":"path","required":true,"schema":{"type":"string","title":"Lei Or Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/hosts":{"get":{"summary":"Hosts Leaderboard","description":"Agent Hosts leaderboard — which platform hosts the most agents.\n\nThe market-positioning signal we publish that no hyperscaler will\npublish themselves. Source_url URL-pattern → host classification:\nVertex (run.app + .a.run.app), Bedrock (agentcore.aws.amazon.com),\nAzure (azurewebsites.net / azurewebsites.us), Cloudflare Workers\n(workers.dev / .cloudflare.com), Vercel (vercel.app), Render\n(onrender.com), Fly (fly.dev), Railway (railway.app), Replit\n(replit.app), HuggingFace (hf.space + huggingface.co), self-hosted\n(everything else with a custom domain), Agenstry-hosted (us).\n\nThis is the \"platform mix-share\" view: useful for VCs/researchers\nwanting to track which agent-hosting stack is winning, and for SMBs\nweighing where to deploy. Free + public.","operationId":"hosts_leaderboard_hosts_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/pulse":{"get":{"summary":"Pulse Page","description":"Public dashboard — \"the state of the agent web\" in one screen.\n\nBuilt from queries we already do for /status + /compliance + activity,\nbut shaped as a marketing surface: numbers + freshness + recent drifts +\nmost-active agents. Cacheable. The signal we want shareable on Twitter.","operationId":"pulse_page_pulse_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/templates":{"get":{"summary":"Templates Page","description":"SMB agent-card templates so businesses can bootstrap their first card.","operationId":"templates_page_templates_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/blog":{"get":{"summary":"Blog Index","operationId":"blog_index_blog_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/blog/{slug}.md":{"get":{"summary":"Blog Post Md","operationId":"blog_post_md_blog__slug__md_get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/blog/{slug}":{"get":{"summary":"Blog Post","operationId":"blog_post_blog__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/blog.md":{"get":{"summary":"Blog Index Md","description":"Markdown index of all published blog posts — feeds AI summarisers.","operationId":"blog_index_md_blog_md_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/team":{"get":{"summary":"Team","description":"The two co-founders behind Agenstry.\n\nInternal authorship page — gives Google a single authoritative source\nfor the people writing the blog (E-E-A-T signal) and gives the byline\nlinks on /blog/<slug> somewhere coherent to point to.","operationId":"team_team_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/mcp-setup":{"get":{"summary":"Install Page","description":"Generic \"connect Agenstry to your AI\" install surface.\n\nEvery snippet on this page renders from the live ``app/skill_catalog``\n+  ``/.well-known/agent-card.json`` + ``/.well-known/x402`` so adding /\nrepricing a skill needs zero template edits. The page lists install\nconfigs for every host an AI dev might use:\n\n  * Claude Desktop / Cline (MCP via HTTP)\n  * Cursor (MCP HTTP)\n  * ChatGPT custom GPT (OpenAPI action pointed at our REST mirror)\n  * OpenAI Responses API (native MCP tool binding — no client SDK needed)\n  * Anthropic Messages API + MCP connector\n  * n8n / Zapier (plain HTTP POST)\n  * Generic A2A runtime (agent-card.json + JSON-RPC)\n\nFalls under the same brand pack: read from ``design/agenstry/``. Aliases\n/connect + /mcp-setup so any old link still resolves.","operationId":"install_page_mcp_setup_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/connect":{"get":{"summary":"Install Page","description":"Generic \"connect Agenstry to your AI\" install surface.\n\nEvery snippet on this page renders from the live ``app/skill_catalog``\n+  ``/.well-known/agent-card.json`` + ``/.well-known/x402`` so adding /\nrepricing a skill needs zero template edits. The page lists install\nconfigs for every host an AI dev might use:\n\n  * Claude Desktop / Cline (MCP via HTTP)\n  * Cursor (MCP HTTP)\n  * ChatGPT custom GPT (OpenAPI action pointed at our REST mirror)\n  * OpenAI Responses API (native MCP tool binding — no client SDK needed)\n  * Anthropic Messages API + MCP connector\n  * n8n / Zapier (plain HTTP POST)\n  * Generic A2A runtime (agent-card.json + JSON-RPC)\n\nFalls under the same brand pack: read from ``design/agenstry/``. Aliases\n/connect + /mcp-setup so any old link still resolves.","operationId":"install_page_connect_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/install":{"get":{"summary":"Install Page","description":"Generic \"connect Agenstry to your AI\" install surface.\n\nEvery snippet on this page renders from the live ``app/skill_catalog``\n+  ``/.well-known/agent-card.json`` + ``/.well-known/x402`` so adding /\nrepricing a skill needs zero template edits. The page lists install\nconfigs for every host an AI dev might use:\n\n  * Claude Desktop / Cline (MCP via HTTP)\n  * Cursor (MCP HTTP)\n  * ChatGPT custom GPT (OpenAPI action pointed at our REST mirror)\n  * OpenAI Responses API (native MCP tool binding — no client SDK needed)\n  * Anthropic Messages API + MCP connector\n  * n8n / Zapier (plain HTTP POST)\n  * Generic A2A runtime (agent-card.json + JSON-RPC)\n\nFalls under the same brand pack: read from ``design/agenstry/``. Aliases\n/connect + /mcp-setup so any old link still resolves.","operationId":"install_page_install_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/skills":{"get":{"summary":"Skills Page","description":"Browse canonical-skill taxonomy.\n\nDefault view shows only **active** canonicals (>= 1 agent mapped) so the\nUI reflects reality. Toggle `show=all` to see aspirational SMB categories\nwe seeded but where no public A2A agent exists yet (those are the\n/for-business positioning).","operationId":"skills_page_skills_get","parameters":[{"name":"show","in":"query","required":false,"schema":{"type":"string","pattern":"^(active|all|aspirational)$","default":"active","title":"Show"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/library.md":{"get":{"summary":"Skills Library Md","operationId":"skills_library_md_skills_library_md_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Q"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":200,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/library":{"get":{"summary":"Skills Library Page","description":"Layer-1 index: SKILL.md procedural-knowledge files (Anthropic's\nAgent-Skills convention). Separate from /skills (the canonical\ntaxonomy labels) so users can browse the actual published Skills\nwithout confusing them with the label graph.","operationId":"skills_library_page_skills_library_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Q"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/{canonical_id}":{"get":{"summary":"Skill Detail Page","operationId":"skill_detail_page_skills__canonical_id__get","parameters":[{"name":"canonical_id","in":"path","required":true,"schema":{"type":"string","title":"Canonical Id"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/route":{"get":{"summary":"Route Page","operationId":"route_page_route_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/graph":{"get":{"summary":"Graph Page","description":"Interactive agent-graph explorer.\n\nThe page is pure client-side rendering — it hits /api/graph for its\ndata so the same payload powers both the human UI and any external\nanalytics consumer (and so we can swap visualisation libraries without\ntouching the backend).","operationId":"graph_page_graph_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/status":{"get":{"summary":"Status Page","operationId":"status_page_status_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/coverage":{"get":{"summary":"Coverage Page","description":"Show per-source contribution + overlap so users can see what we cover.","operationId":"coverage_page_coverage_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/brand/logo.svg":{"get":{"summary":"Brand Logo","description":"Canonical brand mark — two concentric rings in pink → magenta → violet.\n\nPublic URL so transactional emails (Resend strips data: URIs in Gmail's\nsandbox), social cards, partner sites and embedded badges can all\nreference the same asset. 1-day cache + CORS so it's safe to <img src>\nfrom anywhere.","operationId":"brand_logo_brand_logo_svg_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/favicon.ico":{"get":{"summary":"Favicon Ico","description":"Serve the brand mark at the canonical ``/favicon.ico`` path.\n\nGoogle's image fetcher requests this URL directly when caching a\nfavicon for search-result cards — if it 404s, Google falls back to\nthe generic globe glyph. Returns the SVG with ``image/svg+xml``;\nGoogle + every modern browser supports SVG favicons since 2022 and\nthey render crisp at every result-card size.","operationId":"favicon_ico_favicon_ico_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/robots.txt":{"get":{"summary":"Robots","description":"Explicit per-bot allowlist for the major AI crawlers.\n\n``User-agent: *`` already grants everyone, but the AI ecosystem in\n2026 routinely lints sites with bot-specific validators (ChatGPT's\nown crawl-debug, Bing/Brave Indexer, AI overview eligibility\nchecks). Explicit per-bot ``Allow`` blocks signal intent and stop\nthose validators from reporting \"not explicitly permitted\" warnings.\nEach bot below is the canonical User-Agent token from its vendor\ndocumentation:\n\n  OpenAI   — GPTBot (training), OAI-SearchBot (ChatGPT Search),\n             ChatGPT-User (on-demand browsing).\n  Google   — Google-Extended (Gemini training), Googlebot\n             (search index — already covered by ``*`` but listed\n             here so an SEO audit shows it explicitly).\n  Anthropic— ClaudeBot, Claude-SearchBot, anthropic-ai.\n  Perplexity / Brave / Bytespider — present in significant share\n             of AI-overview surfaces.","operationId":"robots_robots_txt_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/llms.txt":{"get":{"summary":"Llms Txt","operationId":"llms_txt_llms_txt_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/llms-full.txt":{"get":{"summary":"Llms Full Txt","description":"Comprehensive AI-discovery index — every public surface, generated\nfresh from the app's route registry.\n\nStainless-pattern: ``llms.txt`` is the abstract index; ``llms-full.txt``\nenumerates every concrete URL so an AI summariser can fan out and\nconsume the lot. Both the HTML page list (from\n``_public_html_routes()``) and the Markdown mirror list (sub-set\nof routes whose path ends in ``.md``) are built dynamically — so\nnew pages land here on their first request, no manual edit.\n\nThree dynamic data sections follow (blog posts, weekly briefings,\ntop-200 agents) — each pulled from the DB so the index reflects\nthe latest write.","operationId":"llms_full_txt_llms_full_txt_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/activity":{"get":{"summary":"Activity Feed","operationId":"activity_feed_api_activity_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":30,"minimum":1,"default":12,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/try/{domain}":{"post":{"summary":"Try Agent","operationId":"try_agent_try__domain__post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_try_agent_try__domain__post"}}}},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/paid-apis":{"get":{"summary":"Paid Apis Page","description":"Catalog of x402-paid REST APIs (sourced from agentic.market + CDP).\n\nFilters: category chip (LLM / data / search / dev tools), price-cheapest\nsort by default. ``sort=revenue`` orders by 30d on-chain USDC gross —\nuseful for picking proven endpoints over speculative ones.\n\nA2A agents that happen to be x402-paid (kind=a2a_agent, payment_protocol\nNOT NULL) are EXCLUDED here. The /search surface already showcases them;\n/paid-apis is specifically the catalog cut for \"raw paid APIs\", which\nis what AI agent runtimes are typically routing to.","operationId":"paid_apis_page_paid_apis_get","parameters":[{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Category"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","pattern":"^(price_asc|price_desc|revenue)$","default":"price_asc","title":"Sort"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":10,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/leaderboard/earnings":{"get":{"summary":"Leaderboard Earnings","description":"Top 20 on-chain x402 earners.\n\nHonest revenue signal: every number here is reproducible from the\npublic Base RPC. Window choices map to (7, 30, 90, all-time) — the\n'all' bucket reads from `window_days=9999` per onchain_revenue.py.","operationId":"leaderboard_earnings_leaderboard_earnings_get","parameters":[{"name":"window","in":"query","required":false,"schema":{"type":"string","pattern":"^(7d|30d|90d|all)$","default":"30d","title":"Window"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sitemap.xml":{"get":{"summary":"Sitemap","description":"Sitemap with per-URL ``lastmod`` so search engines re-crawl on\nreal signal: blog posts on publish-date, agent pages on the\n``last_card_change_at`` of the agent's card (the moment we\nactually have something new to index), skill + provider pages\non their canonical row mtime where available.\n\nThe top-level static-page list is **discovered dynamically** by\nintrospecting ``request.app.routes`` — any new public HTML route\nlands in the sitemap on its first request, with no manual edit.\nSee the deny-list comments below for how the include set is\nderived.\n\nCapped at ~50k URLs per the sitemap spec; we currently fit well\nunder that ceiling.","operationId":"sitemap_sitemap_xml_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/blog.xml":{"get":{"summary":"Blog Rss","description":"RSS 2.0 feed of recently-published blog posts + weekly briefings.\n\nDistinct from ``/feed.xml`` (which is the agent-discovery feed —\nnewest agents by ``first_seen``). This one is for HUMAN readers\n+ AI subscribers that want to follow Agenstry's editorial output\nspecifically: hand-written posts in ``content/blog/`` plus the\nauto-generated weekly State of the Agent Economy briefings.\n\nPosts merged by date, newest first, capped at 50 entries — RSS\naggregators don't typically need more than a month or two of\nhistory and the cap keeps the response under any sane size limit.","operationId":"blog_rss_blog_xml_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/feed.xml":{"get":{"summary":"Rss Feed","description":"RSS 2.0 feed of the 50 most recently first-seen agents.\n\nLets aggregator-shaped tools (Feedly, NetNewsWire, indexers like the\nBing news API) discover new agents without polling our search\nendpoints. Pure stdlib XML build — no Jinja template needed because\nthe structure is fixed.\n\nNOTE: this is the AGENT-discovery feed. For editorial output\n(blog posts + weekly briefings) see ``/blog.xml`` above.","operationId":"rss_feed_feed_xml_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/login":{"get":{"summary":"Login Page","operationId":"login_page_login_get","parameters":[{"name":"sent","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sent"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Login Submit","operationId":"login_submit_login_post","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_login_submit_login_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/verify":{"get":{"summary":"Verify Get","description":"Two-step verify, step 1: show a confirmation page with a button\nthat POSTs the token to consume it.\n\nWhy GET doesn't consume directly: a magic link is a bearer credential\nembedded in a URL, and URLs travel through email clients, browser\nhistory, and (most dangerously) attacker-controlled web pages. The\nclassic CSRF-login attack is:\n\n  1. Attacker signs themselves up, gets a valid magic-link token.\n  2. Attacker mails the victim a benign-looking page that includes\n     ``<img src=\"https://agenstry.com/verify?token=ATTACKER_TOKEN\">``\n     or a meta-refresh / window.open to the same URL.\n  3. Victim opens the page; their browser fetches /verify; if the\n     GET handler consumes the token, the victim is silently logged\n     in as the ATTACKER. Anything the victim does on the site\n     (upload, payment, message) lands on the attacker's account.\n\nDefence: GET only renders a confirm page. The user has to actively\nclick \"Sign in\" to POST the token. A drive-by fetch / image src /\nmeta-refresh can't trigger a POST request from a third-party page.\n\nThe token is NOT consumed here — only displayed in a hidden form\nfield. A user who closes the tab without clicking can still come\nback to the same URL within the magic-link expiry window.","operationId":"verify_get_verify_get","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string","minLength":20,"maxLength":200,"title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Verify Post","description":"Two-step verify, step 2: consume the token + mint a session.\n\nToken arrives via form POST from the confirm page above. The user\nexplicitly clicked \"Sign in\" — no third-party trigger possible.","operationId":"verify_post_verify_post","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_verify_post_verify_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/logout":{"post":{"summary":"Logout","operationId":"logout_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/account":{"get":{"summary":"Account Page","operationId":"account_page_account_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/account/verifications":{"post":{"summary":"Create Verification","description":"Start a domain-ownership verification for an agent. Generates a token\nthe user adds as a DNS TXT record at `_agentfinder-verify.<domain>`.","operationId":"create_verification_account_verifications_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_create_verification_account_verifications_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/verifications/{verification_id}/check":{"post":{"summary":"Check Verification","description":"Trigger a DNS lookup for the given verification.","operationId":"check_verification_account_verifications__verification_id__check_post","parameters":[{"name":"verification_id","in":"path","required":true,"schema":{"type":"integer","title":"Verification Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/subscriptions":{"post":{"summary":"Create Subscription","description":"Add a webhook subscription explicitly (email subs are auto-created on\nverification — this is the path for the Platform tier user who wants\nHMAC-signed POSTs to their own endpoint).","operationId":"create_subscription_account_subscriptions_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_create_subscription_account_subscriptions_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/subscriptions/{sub_id}/toggle":{"post":{"summary":"Toggle Subscription","operationId":"toggle_subscription_account_subscriptions__sub_id__toggle_post","parameters":[{"name":"sub_id","in":"path","required":true,"schema":{"type":"integer","title":"Sub Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/subscriptions/{sub_id}/delete":{"post":{"summary":"Delete Subscription","operationId":"delete_subscription_account_subscriptions__sub_id__delete_post","parameters":[{"name":"sub_id","in":"path","required":true,"schema":{"type":"integer","title":"Sub Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/catalogs":{"post":{"summary":"Bind Catalog","description":"Bind a JSON catalog/menu feed URL to a verified agent.\n\nVerified-owner only — we don't want strangers binding URLs to other\npeople's agents (we'd then probe + cache + serve their data under that\ndomain). The probe runs inline so the operator gets immediate feedback;\nsubsequent re-probes happen on the scheduler.","operationId":"bind_catalog_account_catalogs_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_bind_catalog_account_catalogs_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/catalogs/unbind":{"post":{"summary":"Unbind Catalog","description":"Drop the catalog binding (snapshots stay — append-only, we don't rewrite history).","operationId":"unbind_catalog_account_catalogs_unbind_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_unbind_catalog_account_catalogs_unbind_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/verifications/{verification_id}/delete":{"post":{"summary":"Delete Verification","operationId":"delete_verification_account_verifications__verification_id__delete_post","parameters":[{"name":"verification_id","in":"path","required":true,"schema":{"type":"integer","title":"Verification Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/api-keys":{"post":{"summary":"Create Api Key","operationId":"create_api_key_account_api_keys_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_create_api_key_account_api_keys_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/api-keys/{key_id}/revoke":{"post":{"summary":"Revoke Api Key","operationId":"revoke_api_key_account_api_keys__key_id__revoke_post","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"integer","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/checkout":{"post":{"summary":"Start Checkout","description":"Start Stripe Checkout for the requested tier (pro | platform | enterprise).\n\nEnterprise (€99/mo) is now self-serve through Stripe Checkout — the\nPrice ID lives in ``settings.stripe_price_enterprise_monthly``. The\nolder \"enterprise = manual invoicing\" comment is obsolete; legacy\nenterprise customers continue on their bespoke Stripe Customer record\nbut new signups come through here.","operationId":"start_checkout_account_checkout_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_start_checkout_account_checkout_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/portal":{"post":{"summary":"Start Portal","operationId":"start_portal_account_portal_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/webhooks/stripe":{"post":{"summary":"Stripe Webhook","operationId":"stripe_webhook_webhooks_stripe_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/pricing":{"get":{"summary":"Pricing","description":"Public pricing page. Surfaces tier CTAs as POST forms when the user\nis logged in (one-click Stripe Checkout for both Pro and Platform);\notherwise routes them through magic-link sign-in.","operationId":"pricing_pricing_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/methodology":{"get":{"summary":"Methodology","description":"Public Conformance Methodology spec — the standards moat.","operationId":"methodology_methodology_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/trust":{"get":{"summary":"Trust","description":"Honest transparency report — what's in place, what's audited, what's planned.","operationId":"trust_trust_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/federation":{"get":{"summary":"Federation","description":"Federation dashboard — every registry we index, with live counts.\n\nHEADLINE NUMBERS — read this before changing the queries.\n\n* ``a2a_total`` is the count of DISTINCT agent domains across all\n  ``agent_sources`` rows. It is NOT ``sum(a2a_counts.values())`` —\n  one agent can legitimately appear in multiple sources (registry +\n  crt.sh + github code), and naïvely summing per-source counts\n  double-counts those agents (~1.78x inflation on the current\n  corpus). The per-source breakdown table below still shows\n  per-source counts that overlap; the headline is the true number\n  of unique agents we federate.\n\n* ``mcp_total`` IS ``sum(mcp_buckets.values())`` because every MCP\n  server has exactly one canonical name, and bucketing by name-\n  prefix partitions the corpus — no overlap.\n\n* ``mcp_registry_count`` is the count of buckets that match a known\n  federation-registry prefix (``glama``, ``pypi``, ``mcp.so``, …).\n  ``mcp_publisher_count`` is the remaining long tail (individual\n  ``io.github.<user>`` and self-hosted ``<reverse-domain>``\n  buckets). We surface BOTH because \"from 6,837 sources\" is\n  misleading — almost all of those are single-server publishers,\n  not federation partners.","operationId":"federation_federation_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/privacy":{"get":{"summary":"Privacy","operationId":"privacy_privacy_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/terms":{"get":{"summary":"Terms","operationId":"terms_terms_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/compliance":{"get":{"summary":"Compliance","description":"Two-stage funnel:\n\nStage 1 — agent-card fetch (946 candidates → who returned something usable).\nStage 2 — live JSON-RPC probe (of the survivors, who actually works).\n\nWe show this transparently because it answers the question every\nskeptical visitor asks: \"are there really this few agents, or is your\ncrawler broken?\" The answer is bucketed by HTTP status + error\ncategory so you can see for yourself.","operationId":"compliance_compliance_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/api/search":{"get":{"summary":"Api Search","operationId":"api_search_api_search_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Q"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":25,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":0,"default":0,"title":"Offset"}},{"name":"min_quality","in":"query","required":false,"schema":{"type":"number","maximum":1.0,"minimum":0.0,"default":0.0,"title":"Min Quality"}},{"name":"protocol","in":"query","required":false,"schema":{"type":"string","pattern":"^(all|a2a|mcp)$","default":"all","title":"Protocol"}},{"name":"verified","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Verified"}},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Category"}},{"name":"exclude_sanctioned","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Exclude Sanctioned"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Search Api Search Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agents/{domain}/similar":{"get":{"summary":"Api Agent Similar","description":"Vec0-powered \"similar agents\" surface. Falls back to skill / category\ncohort when the target lacks an embedding row (eg. mid-reindex).\n\nEach result includes a ``similarity`` value in [0, 1] — cosine of the\nembedding-space angle between target and peer (1.0 = identical text,\n0.5 = orthogonal-ish). When the response came from the skill-cohort\nfallback (no vec row), ``similarity`` is a sentinel 0.5 and the\n``via`` field is set to ``\"skill_cohort\"``.","operationId":"api_agent_similar_api_agents__domain__similar_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":25,"minimum":1,"default":6,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Agent Similar Api Agents  Domain  Similar Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mcp-servers/{name}/similar":{"get":{"summary":"Api Mcp Similar","description":"Vec0-powered similar MCP servers.\n\nEach result includes a ``similarity`` value in [0, 1] from cosine of\nthe embedding-space angle between target and peer. While\n``mcp_servers_vec`` is empty (pre-MCP-reindex) this endpoint falls\nback to the skill-cohort path which returns a sentinel 0.5 for every\npeer. The ``via`` field tells the caller which path produced the\nresponse.","operationId":"api_mcp_similar_api_mcp_servers__name__similar_get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":25,"minimum":1,"default":6,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Mcp Similar Api Mcp Servers  Name  Similar Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills/{skill_id}/similar":{"get":{"summary":"Api Skill Similar","description":"Vec0-powered \"related skills\" surface.\n\nReturns canonical skills nearest to ``skill_id`` in the embedding\nspace. Use to power skill-graph exploration (\"if you're interested\nin X, you might also care about Y\"). Returns ``[]`` if the skill\nisn't embedded yet (pre-reindex).","operationId":"api_skill_similar_api_skills__skill_id__similar_get","parameters":[{"name":"skill_id","in":"path","required":true,"schema":{"type":"string","title":"Skill Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":25,"minimum":1,"default":6,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Skill Similar Api Skills  Skill Id  Similar Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/categories":{"get":{"summary":"Api Categories","description":"Top categories by indexed agent count.\n\n``kind`` restricts to a single Agent.kind (``a2a_agent`` or\n``paid_api``); omit to span both.","operationId":"api_categories_api_categories_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"kind","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Kind"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Categories Api Categories Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agents/{domain}":{"get":{"summary":"Api Agent","operationId":"api_agent_api_agents__domain__get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Agent Api Agents  Domain  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agents/{domain}/snapshots":{"get":{"summary":"Api Agent Snapshots","description":"Append-only history of every agent-card change we observed.\n\nOpen to all callers — card snapshots are public-by-design (they're already\nqueryable by humans on the agent detail page). Paginated with a `cursor`\nparameter that is the `id` of the last snapshot from the previous page.","operationId":"api_agent_snapshots_api_agents__domain__snapshots_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Agent Snapshots Api Agents  Domain  Snapshots Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agents/{domain}/metrics":{"get":{"summary":"Api Agent Metrics","description":"Per-agent visibility dashboard data.\n\nPowers /agents/{domain}/dashboard. Anonymous callers see totals + event\nbreakdown + intents + sparkline. The per-caller breakdown (which API keys\nor users called this agent) is gated to verified owners + Pro/Platform —\nsame policy as /api/agents/{domain}/calls. 90d window is Pro/Platform only\n(legitimate upgrade trigger; storage cost is real).","operationId":"api_agent_metrics_api_agents__domain__metrics_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}},{"name":"window","in":"query","required":false,"schema":{"type":"string","pattern":"^(7d|30d|90d)$","default":"30d","title":"Window"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Agent Metrics Api Agents  Domain  Metrics Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agents/{domain}/catalog":{"get":{"summary":"Api Agent Catalog","description":"Latest verified catalog snapshot for an agent.\n\nReturns the cached snapshot we've JCS-canonicalised and (optionally)\nJWS-verified against the agent's JWKS. Counterparty agents calling this\nbusiness get a non-repudiable record of what was on offer at this moment.","operationId":"api_agent_catalog_api_agents__domain__catalog_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Agent Catalog Api Agents  Domain  Catalog Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agents/{domain}/catalog/snapshots":{"get":{"summary":"Api Agent Catalog Snapshots","description":"Paginated catalog history for an agent.\n\nEach row is one verified snapshot. Auditors can ask \"was item X in the\nmenu on date Y?\" by walking the timeline.","operationId":"api_agent_catalog_snapshots_api_agents__domain__catalog_snapshots_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Agent Catalog Snapshots Api Agents  Domain  Catalog Snapshots Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agents/{domain}/catalog/snapshots/{snapshot_id}":{"get":{"summary":"Api Agent Catalog Snapshot","description":"Specific catalog snapshot — returns the full raw catalog at that point.","operationId":"api_agent_catalog_snapshot_api_agents__domain__catalog_snapshots__snapshot_id__get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}},{"name":"snapshot_id","in":"path","required":true,"schema":{"type":"integer","title":"Snapshot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Agent Catalog Snapshot Api Agents  Domain  Catalog Snapshots  Snapshot Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agents/{domain}/calls":{"get":{"summary":"Api Agent Calls","description":"Audit-trail export for an agent — every observed call.\n\nOpen access (aggregate signal is part of the trust layer), but PII\nfields (user_id, api_key_prefix, requester_hash) are exposed ONLY\nto the verified owner of the queried agent.\n\nPre-2026-05-21 the gate also accepted any Pro/Platform subscriber,\nwhich meant a $29/mo Pro account could pull per-caller fingerprints\non every agent in the index (Tavily, Replit, Anthropic, …). That's\nexactly the cross-tenant competitive signal Enterprise tier is\nsupposed to sell. Identity now requires explicit verified ownership.","operationId":"api_agent_calls_api_agents__domain__calls_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Agent Calls Api Agents  Domain  Calls Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/stats":{"get":{"summary":"Api Stats","operationId":"api_stats_api_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Stats Api Stats Get"}}}}}}},"/api/format-coverage":{"get":{"summary":"Api Format Coverage","description":"Aggregate count of agents by well-known card-format bucket.\n\n``current`` = A2A 0.3+ ``/.well-known/agent-card.json`` and variants.\n``legacy``  = pre-0.3 Google paths ``/.well-known/agent.json`` and\n              ``/a2a.json``. Operationally these signal possibly\n              unmaintained deployments — the spec renamed this path\n              in 2024 and modern SDKs serve only the new name.\n``other``   = DID / MCP / OpenRPC / ai-agent / agents.json — every\n              other well-known surface we probe.\n``unknown`` = rows from before the classifier shipped (will decay\n              to zero as each agent is re-probed).","operationId":"api_format_coverage_api_format_coverage_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Format Coverage Api Format Coverage Get"}}}}}}},"/api/verified-bots":{"get":{"summary":"Api Verified Bots","description":"Cloudflare Radar verified-bots snapshot.\n\nOperators we know the identity of (Cloudflare validates via reverse-DNS\nand, for Web Bot Auth participants, Ed25519 request signatures). Used\nby the conformance scorer as a second identity signal alongside GLEIF.\nRefreshed daily by the scheduler.","operationId":"api_verified_bots_api_verified_bots_get","parameters":[{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"description":"Filter by Cloudflare botCategory (e.g. \"AI Crawler\").","title":"Category"},"description":"Filter by Cloudflare botCategory (e.g. \"AI Crawler\")."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":200,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Verified Bots Api Verified Bots Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mcp-servers":{"get":{"summary":"Api Mcp Search","operationId":"api_mcp_search_api_mcp_servers_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Q"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Mcp Search Api Mcp Servers Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/local/search":{"get":{"summary":"Api Local Search","description":"Local-business discovery — find hosted Agenstry agents near a\nlocation, optionally filtered by category / country / city.\n\nStatus: **internal / experimental**. We do not advertise this\nendpoint as an A2A standard; it queries the locality columns on\nour own ``managed_agents`` table (populated via the /claim flow).\nSee ``app/locality.py`` module docstring for why we deliberately\ndo NOT publish a public A2A \"locality extension\" today.\n\nQuery shape:\n\n  GET /api/local/search?near=52.354,4.879&radius_km=5\n                      &category=restaurant.pizza\n                      &delivery=true&limit=10\n\nReturns rows sorted by distance ascending. Each row carries the\nagent's distance from the query point AND the full schema.org\nJSON-LD blob (so a downstream LLM can re-rank without a second\nround-trip).\n\nSargable plan: filter on (country, category, city) BEFORE the\nhaversine evaluates, then ORDER BY distance + LIMIT. With the\nindexes added in migration ``o0p1q2r3s4t5_managed_agent_locality``\nthe typical \"pizza in NL\" query touches <1% of the table.","operationId":"api_local_search_api_local_search_get","parameters":[{"name":"near","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"description":"lat,lng pair (decimal degrees). E.g. `52.3676,4.9041` for Amsterdam centre.","title":"Near"},"description":"lat,lng pair (decimal degrees). E.g. `52.3676,4.9041` for Amsterdam centre."},{"name":"radius_km","in":"query","required":false,"schema":{"type":"number","maximum":500.0,"minimum":0.1,"description":"Search radius around `near` in kilometres.","default":10.0,"title":"Radius Km"},"description":"Search radius around `near` in kilometres."},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"description":"Agenstry category code (e.g. `restaurant.pizza`).","title":"Category"},"description":"Agenstry category code (e.g. `restaurant.pizza`)."},{"name":"country","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":2},{"type":"null"}],"description":"ISO 3166-1 alpha-2 (e.g. `NL`).","title":"Country"},"description":"ISO 3166-1 alpha-2 (e.g. `NL`)."},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"description":"City name (case-insensitive substring match).","title":"City"},"description":"City name (case-insensitive substring match)."},{"name":"delivery","in":"query","required":false,"schema":{"type":"boolean","description":"When true, also require the agent's service_area to reach `near`.","default":false,"title":"Delivery"},"description":"When true, also require the agent's service_area to reach `near`."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Local Search Api Local Search Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/providers":{"get":{"summary":"Api Providers","operationId":"api_providers_api_providers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Response Api Providers Api Providers Get"}}}}}}},"/api/submit":{"post":{"summary":"Api Submit","description":"Open submission. Accepts any of:\n  * URL (a2a / mcp endpoint)\n  * GitHub repo (URL or owner/repo)\n  * npm package (``npm:@scope/pkg`` or ``@scope/pkg``)\n  * PyPI package (``pypi:name``)\n  * Docker image (``docker:owner/image``)\n\nAuto-detects type when ``kind`` is omitted. See app/submissions.py for\nthe full dispatch logic.","operationId":"api_submit_api_submit_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitRequest"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Submit Api Submit Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills":{"get":{"summary":"Api Skills","description":"List canonical skills, optionally filtered by domain.","operationId":"api_skills_api_skills_get","parameters":[{"name":"domain","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Domain"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Skills Api Skills Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills/{canonical_id}":{"get":{"summary":"Api Skill Detail","operationId":"api_skill_detail_api_skills__canonical_id__get","parameters":[{"name":"canonical_id","in":"path","required":true,"schema":{"type":"string","title":"Canonical Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Skill Detail Api Skills  Canonical Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/graph":{"get":{"summary":"Api Graph","description":"Agent graph: canonical-skill ↔ A2A-agent ↔ MCP-server edges.\n\nReturns a Cytoscape-compatible ``{nodes, edges}`` payload built from the\npersistent join tables (AgentSkill + McpServerSkill) — no runtime\nembedding work, so this stays fast at 10K+ resources. The same shape\ndrives both the /graph UI and any external analytics consumer.\n\nFiltering strategy: we always include the canonical skills (they're the\nspine of the graph), then add agents / MCPs in descending quality_score\norder until ``node_limit`` is reached. This keeps the graph readable\nwhile surfacing the *best* resources per skill.","operationId":"api_graph_api_graph_get","parameters":[{"name":"domain","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"description":"Filter to one canonical-skill domain (payments, hospitality, …)","title":"Domain"},"description":"Filter to one canonical-skill domain (payments, hospitality, …)"},{"name":"node_limit","in":"query","required":false,"schema":{"type":"integer","maximum":2500,"minimum":10,"description":"Total node cap (skills + agents + MCPs). Default 900 — Cytoscape handles up to ~3K cleanly; beyond that hide via skill-domain filter.","default":900,"title":"Node Limit"},"description":"Total node cap (skills + agents + MCPs). Default 900 — Cytoscape handles up to ~3K cleanly; beyond that hide via skill-domain filter."},{"name":"min_confidence","in":"query","required":false,"schema":{"type":"number","maximum":1.0,"minimum":0.0,"description":"Drop low-confidence links — same threshold as skill_graph.LINK_THRESHOLD","default":0.55,"title":"Min Confidence"},"description":"Drop low-confidence links — same threshold as skill_graph.LINK_THRESHOLD"},{"name":"include_mcps","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Include Mcps"}},{"name":"include_agents","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Include Agents"}},{"name":"live_only","in":"query","required":false,"schema":{"type":"boolean","description":"Only nodes where live_responds=True (probe currently green)","default":false,"title":"Live Only"},"description":"Only nodes where live_responds=True (probe currently green)"},{"name":"include_auth_gated","in":"query","required":false,"schema":{"type":"boolean","description":"Include agents whose endpoint requires auth (live_state='auth_required'). These are real agents we can't anonymously probe; usually you want them.","default":true,"title":"Include Auth Gated"},"description":"Include agents whose endpoint requires auth (live_state='auth_required'). These are real agents we can't anonymously probe; usually you want them."},{"name":"include_down","in":"query","required":false,"schema":{"type":"boolean","description":"Include resources currently failing — live_responds=False for MCPs, or live_state in ('endpoint_404','endpoint_5xx','unreachable','wrong_response') for agents. Off by default — turn on to see what's broken.","default":false,"title":"Include Down"},"description":"Include resources currently failing — live_responds=False for MCPs, or live_state in ('endpoint_404','endpoint_5xx','unreachable','wrong_response') for agents. Off by default — turn on to see what's broken."},{"name":"verified_only","in":"query","required":false,"schema":{"type":"boolean","description":"Only verified-owner agents (DNS-verified).","default":false,"title":"Verified Only"},"description":"Only verified-owner agents (DNS-verified)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Graph Api Graph Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/route":{"post":{"summary":"Api Route","description":"Match a freeform task to canonical skills, return ranked agents AND a proposed chain.\n\nIf the task strongly matches multiple canonical skills (≥ 2 above CHAIN_THRESHOLD),\nwe propose a chain — a sequence of skills to execute, each with the best agent.","operationId":"api_route_api_route_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Route Api Route Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/route/compose":{"post":{"summary":"Api Route Compose","description":"Pro multi-agent routing — decompose a freeform task into ordered\natomic steps and rank our index's top-N agents per step.\n\nPipeline (one LLM call, the rest is deterministic):\n  1. ``decompose_task`` — single gpt-5.4-nano call (≤ 400 tokens out,\n     ≤ 8 s timeout, falls back to single-step on any error).\n  2. For each step, ``match_canonicals_to_query`` finds the closest\n     canonical skill via vec0 (no LLM round-trips).\n  3. ``score_agent`` ranks claimants using the v2 multi-signal\n     formula (skill × quality × uptime × cost × latency × trust ×\n     streaming × recent-reliability).\n\nBackwards-compat: completely additive. Existing ``/api/route`` is\nuntouched. Clients that want the single-best-agent flow keep using\n/route; clients that want a workflow plan call /route/compose.","operationId":"api_route_compose_api_route_compose_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteComposeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Route Compose Api Route Compose Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/compose":{"post":{"summary":"Api Compose","description":"Compose an execution plan for a task.\n\nGiven a natural-language goal, return a structured multi-step plan: which\ncanonical skills the task decomposes into, which agents to use per skill\n(with conformance + verified status + expected latency), risk class per\nstep, and human-in-the-loop flags. The caller is responsible for\nexecuting the plan — Agenstry returns plans, not executions.\n\nThis is the routing intelligence other workflow engines need but don't\nhave to rebuild. Pure read of our index + scoring; no side effects.","operationId":"api_compose_api_compose_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComposeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agents/{domain}/uptime":{"get":{"summary":"Api Agent Uptime","description":"Per-day uptime + p50 latency for the last ``days`` days.\n\nReads from the ``probe_runs`` time-series populated on every probe.\nReturns a deterministic, zero-filled series — one row per UTC day,\noldest first — so the client can render a fixed-width sparkline\nwithout re-sampling.","operationId":"api_agent_uptime_api_agents__domain__uptime_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":30,"minimum":1,"default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Agent Uptime Api Agents  Domain  Uptime Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agents.jsonl.gz":{"get":{"summary":"Api Agents Jsonl Gz","description":"Bulk export of every live agent as gzip-compressed JSON Lines.\n\nStreamed end-to-end so a 50K-agent index doesn't materialise as a\n20MB Python object before the first byte goes out. Only public\nfields are included — no managed-agent OAuth tokens, no internal\nscore weights. Live = ``last_seen_ok IS NOT NULL`` and not archived.","operationId":"api_agents_jsonl_gz_api_agents_jsonl_gz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/mcps.jsonl.gz":{"get":{"summary":"Api Mcps Jsonl Gz","description":"Bulk export of every MCP server as gzip-compressed JSON Lines.","operationId":"api_mcps_jsonl_gz_api_mcps_jsonl_gz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/feed/all.jsonl.gz":{"get":{"summary":"Api Feed All Jsonl Gz","description":"Unified federation feed — every agent + MCP server + paid_api in one\ngzip-streamed NDJSON file.\n\nThe neutral-Switzerland surface. Anyone (Coinbase Agentic.Market, AGNTCY\ndiscovery client, an academic paper, a procurement bot) can pull this\nURL on a schedule and get the same indexed view of the agent web that\npowers our search. No auth, no signup; rate-limited at 6/hour because\neach pull streams the entire corpus.\n\nSchema (one JSON object per line):\n  {\"kind\": \"a2a\"|\"mcp\"|\"paid_api\",\n   \"id\": <domain or mcp_name>,\n   \"name\": ..., \"description\": ..., \"url\": ...,\n   \"provider\": ..., \"lei\": ..., \"lei_legal_name\": ...,\n   \"live_responds\": ..., \"quality_score\": ..., \"first_seen\": ...,\n   \"signed\": ..., \"verified_owner\": bool, \"category\": ...,\n   (a2a-specific) \"protocol_version\": ..., \"payment_protocol\": ...,\n   (mcp-specific) \"transport\": ..., \"tools_count\": ...}\n\nAnyone re-publishing this file should include the line\n``# source: agenstry.com/api/feed/all.jsonl.gz`` in their re-published\nartifact. Otherwise: completely free to redistribute.","operationId":"api_feed_all_jsonl_gz_api_feed_all_jsonl_gz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/registries":{"get":{"summary":"Api Registries","description":"List every supported business registry. Operators use this to discover\nwhich adapters this server has + whether they need API keys.","operationId":"api_registries_api_registries_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Registries Api Registries Get"}}}}}}},"/api/registries/{registry_id}/{identifier}":{"get":{"summary":"Api Registry Lookup","description":"Look up an identifier in a specific registry.\n\nReturns the cached structured record or 404. Frees callers from knowing the\nper-registry response format — every adapter normalises to BusinessRecord.","operationId":"api_registry_lookup_api_registries__registry_id___identifier__get","parameters":[{"name":"registry_id","in":"path","required":true,"schema":{"type":"string","title":"Registry Id"}},{"name":"identifier","in":"path","required":true,"schema":{"type":"string","title":"Identifier"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Registry Lookup Api Registries  Registry Id   Identifier  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/lei/search":{"get":{"summary":"Api Lei Search","description":"Search GLEIF by legal entity name.","operationId":"api_lei_search_api_lei_search_get","parameters":[{"name":"name","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":200,"title":"Name"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":25,"minimum":1,"default":5,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Lei Search Api Lei Search Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/lei/{lei}":{"get":{"summary":"Api Lei Lookup","description":"Look up an LEI in GLEIF — convenience shortcut for /api/registries/gleif/{lei}.","operationId":"api_lei_lookup_api_lei__lei__get","parameters":[{"name":"lei","in":"path","required":true,"schema":{"type":"string","title":"Lei"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Lei Lookup Api Lei  Lei  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agents/{domain}/identity/history":{"get":{"summary":"Api Agent Identity History","description":"Append-only timeline of every identity-verification event for this agent.\n\nThe data moat — the *current* state can be re-derived from public registries,\nbut the *timeline* of when an LEI was bound, refreshed, lapsed or restored\nonly exists here. Auditors use this to answer \"was the LEI active on the\nday of the contract?\" / \"when did the legal name change?\".","operationId":"api_agent_identity_history_api_agents__domain__identity_history_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Agent Identity History Api Agents  Domain  Identity History Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agents/{domain}/lei":{"get":{"summary":"Api Agent Lei Get","description":"Cached identity snapshot for an agent (no live registry call).","operationId":"api_agent_lei_get_api_agents__domain__lei_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Agent Lei Get Api Agents  Domain  Lei Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Api Agent Lei Bind","description":"Bind a GLEIF LEI to an agent — convenience for the most common case.","operationId":"api_agent_lei_bind_api_agents__domain__lei_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeiBindRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Agent Lei Bind Api Agents  Domain  Lei Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agents/{domain}/identity":{"post":{"summary":"Api Agent Identity Bind","description":"Bind ANY registry adapter to an agent and verify it.\n\nFree to call. The verification proves three things:\n  1. The identifier exists in the registry.\n  2. It is currently active.\n  3. The legal name plausibly matches the agent's provider.organization.\n\nMismatches don't fail the bind, but the verification result reflects them\n(and the conformance score reduces accordingly). Operators get partial\ncredit for a verified identity even when the provider name is a trade name.","operationId":"api_agent_identity_bind_api_agents__domain__identity_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdentityBindRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Agent Identity Bind Api Agents  Domain  Identity Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agents/{domain}/audit.json":{"get":{"summary":"Api Agent Audit","description":"Audit-grade compliance bundle for an agent.\n\nDesigned for vendor-review workflows in regulated industries (banking,\ninsurance, healthcare). Returns a structured, machine-and-human-readable\nsnapshot covering identity, operational, conformance, provenance,\nlifecycle, AND verification timeline.\n\nAdd `?sign=true` to receive a JWS-signed envelope: the bundle becomes\ncryptographic evidence that Agenstry produced this exact report at\nthis exact time. Auditors verify against /.well-known/jwks.json.","operationId":"api_agent_audit_api_agents__domain__audit_json_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}},{"name":"sign","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Sign"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Agent Audit Api Agents  Domain  Audit Json Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/badge/{domain}.svg":{"get":{"summary":"Badge Grade","description":"Conformance grade badge — the most common embed.","operationId":"badge_grade_badge__domain__svg_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/badge/{domain}/identity.svg":{"get":{"summary":"Badge Identity","description":"Verified Business badge — present only when an active registry verification exists.","operationId":"badge_identity_badge__domain__identity_svg_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/badge/{domain}/uptime.svg":{"get":{"summary":"Badge Uptime","description":"Uptime percentage badge — green ≥95%, amber ≥60%, red below.","operationId":"badge_uptime_badge__domain__uptime_svg_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/badge/{domain}/protocol.svg":{"get":{"summary":"Badge Protocol","description":"Declared A2A protocol version badge.","operationId":"badge_protocol_badge__domain__protocol_svg_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/badge/{domain}/catalog.svg":{"get":{"summary":"Badge Catalog","description":"Catalog attestation badge — verified menu/services feed status.","operationId":"badge_catalog_badge__domain__catalog_svg_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/badge/{domain}.js":{"get":{"summary":"Badge Js Embed","description":"One-line JS embed — drop a ``<script src=\"…\">`` on any site and the\noperator's verified-business badge + conformance grade appears on\npage-load.\n\nSelf-contained: no external deps (no jQuery, no fonts, no fetch).\nAll data baked at request time so the badge stays usable on offline\narchived pages too. Sub-2KB gzipped.\n\nSECURITY: every interpolation runs through ``html.escape`` because\nthis script ends up inside HTML/JS contexts on third-party origins.\nA malicious ``domain`` parameter cannot break out of the rendered\nstring. Same input contract as the SVG endpoints above.","operationId":"badge_js_embed_badge__domain__js_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/badges/leaderboard.json":{"get":{"summary":"Badges Leaderboard Json","description":"JSON data behind the top-embedded-badges leaderboard.\n\nGROUP BY agent_domain on ``BadgeEmbed`` over the trailing window.\nReturns the count + the diversity (distinct referer hosts) so a\ndomain with 1 000 embeds across 50 referrers ranks higher than a\ndomain with 1 000 embeds from a single page-refreshing tab.","operationId":"badges_leaderboard_json_badges_leaderboard_json_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":180,"minimum":1,"default":30,"title":"Days"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/badges/leaderboard":{"get":{"summary":"Badges Leaderboard Html","description":"HTML view of the leaderboard — small, no template, embeds inline\nCSS. Lives next to the data endpoint so the JSON contract is the\nprimary surface and the HTML is a thin renderer for journalists /\nAI crawlers landing organically.","operationId":"badges_leaderboard_html_badges_leaderboard_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":180,"minimum":1,"default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mcp":{"post":{"summary":"Mcp","operationId":"mcp_mcp_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/a2a":{"post":{"summary":"A2A","operationId":"a2a_a2a_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/enterprise/ai":{"get":{"summary":"Enterprise Ai Page","description":"Server-rendered chat shell. The actual conversation runs over\nthe SSE endpoint below; this just paints the page chrome + ensures\nthe visitor has Enterprise rights.","operationId":"enterprise_ai_page_enterprise_ai_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/enterprise/ai/stream":{"post":{"summary":"Enterprise Ai Stream","description":"SSE endpoint. The browser POSTs JSON ``{message, history?}``;\nwe stream back ``data: {kind, payload}\\n\\n`` frames as the agent\nemits events.\n\nThe connection stays open for the full duration of one model turn\n(token streaming + tool calls). Reverse proxies must NOT buffer\nthis — we send ``X-Accel-Buffering: no`` so nginx flushes per-line\nand Cloud Run / Fly proxies do the same.","operationId":"enterprise_ai_stream_enterprise_ai_stream_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/enterprise/ai/tools.json":{"get":{"summary":"Enterprise Ai Tool List","description":"Return the JSON schemas of every tool the agent has access to.\n\nUseful for documentation + smoke-testing. Enterprise-only since the\nschema reveals what data surface we expose, which is signal for\ncompetitors.","operationId":"enterprise_ai_tool_list_enterprise_ai_tools_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/enterprise/ai/download/{token}":{"get":{"summary":"Enterprise Ai Download","description":"Serve a one-time-read download that an agent tool stashed.\n\n``generate_report`` and ``download_csv`` produce content + a token;\nthe model surfaces the URL ``/enterprise/ai/download/<token>`` in\nthe chat reply, and clicking it lands here. Records are dropped\nfrom the in-process store on first read, so a leaked URL can't be\nreplayed — and they auto-expire after 1 hour even if no one ever\nfetches them.\n\nGated like the rest of the AI Analyst surface: only Enterprise\nseats reach this; otherwise 402 (matches the chat + tools.json\npaywall behaviour, so an analyst who lost their seat doesn't keep\npulling reports from the queue).","operationId":"enterprise_ai_download_enterprise_ai_download__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports/state-of-agent-economy":{"get":{"summary":"State Of Agent Economy Html","description":"Human-facing State of the Agent Economy report.\n\nThe page now has TWO layers:\n  1. The weekly briefing (LLM analysis on top of last week's\n     numbers) — published Monday 13:00 UTC, same body all week.\n  2. The live observability spine numbers — recomputed every 5\n     min, always current.\n\nOn the first run (no briefing rows yet), the page renders without\na briefing section — same as before this feature shipped.","operationId":"state_of_agent_economy_html_reports_state_of_agent_economy_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/reports/state-of-agent-economy/archive":{"get":{"summary":"State Of Agent Economy Archive","description":"Every published briefing, newest first. Permanent citeable\ntimeline of the agent economy.","operationId":"state_of_agent_economy_archive_reports_state_of_agent_economy_archive_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/reports/state-of-agent-economy.md":{"get":{"summary":"State Of Agent Economy Md","description":"Stainless-pattern AI-friendly markdown view of the latest briefing.\n\nSame content as the page — same briefing markdown + the JSON-shaped\nheadline numbers — but as plain text/markdown so AI consumers can\nparse it without HTML noise. Includes a header with iso_week +\ngeneration timestamp + citations as a numbered reference list.\n\nWhen no briefing has shipped yet, returns a short placeholder so\ncrawlers always get a meaningful payload.","operationId":"state_of_agent_economy_md_reports_state_of_agent_economy_md_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/reports/state-of-agent-economy/archive.md":{"get":{"summary":"State Of Agent Economy Archive Md","description":"Markdown view of the briefing archive — every issue with its\npermalink, generation date, citation count. AI-friendly index of\neverything we've published.","operationId":"state_of_agent_economy_archive_md_reports_state_of_agent_economy_archive_md_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/reports/state-of-agent-economy/{iso_week}.md":{"get":{"summary":"State Of Agent Economy Single Week Md","description":"Markdown view of ONE specific week's briefing. AI-friendly\npermalink that survives across reads (the row never moves).","operationId":"state_of_agent_economy_single_week_md_reports_state_of_agent_economy__iso_week__md_get","parameters":[{"name":"iso_week","in":"path","required":true,"schema":{"type":"string","title":"Iso Week"}}],"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports/state-of-agent-economy/{iso_week}":{"get":{"summary":"State Of Agent Economy Single Week","description":"Permalink to one specific week's briefing. Pattern: ``2026-W21``.\n\nRenders the page with that week's frozen briefing — useful for\nsharing a specific issue without ambiguity over which week is\ncurrently published.","operationId":"state_of_agent_economy_single_week_reports_state_of_agent_economy__iso_week__get","parameters":[{"name":"iso_week","in":"path","required":true,"schema":{"type":"string","title":"Iso Week"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports/state-of-agent-economy.json":{"get":{"summary":"State Of Agent Economy Json","description":"Machine-readable copy of the report. Same payload as the page.","operationId":"state_of_agent_economy_json_reports_state_of_agent_economy_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/reports/state-of-agent-economy.csv":{"get":{"summary":"State Of Agent Economy Csv","description":"Flat-CSV download of the headline figures + the daily growth\nseries. Designed to drop into pandas / Excel without further\nmunging.","operationId":"state_of_agent_economy_csv_reports_state_of_agent_economy_csv_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/economy/categories":{"get":{"summary":"Economy Categories Html","description":"Category heatmap — supply / live-rate / 30d calls / 30d revenue\n/ new-agent growth, one row per Agent.category. Coloured cells\nencode each metric's relative intensity.","operationId":"economy_categories_html_economy_categories_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/economy/categories.json":{"get":{"summary":"Economy Categories Json","operationId":"economy_categories_json_economy_categories_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/economy/gaps":{"get":{"summary":"Economy Supply Gaps Html","description":"Demand-supply gap ranking — every canonical skill ordered by\nimpressions-per-agent. Surfaces \"47 searches / 3 agents\" headlines\nso builders can spot underserved markets at a glance.","operationId":"economy_supply_gaps_html_economy_gaps_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/economy/gaps.json":{"get":{"summary":"Economy Supply Gaps Json","operationId":"economy_supply_gaps_json_economy_gaps_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/economy/cohorts":{"get":{"summary":"Economy Cohorts Html","description":"Birth-week cohort survival + activation. Each row = the agents\nindexed in one ISO-week, with % still live + % earning + median\ntime-to-first-call. The growth-quality signal.","operationId":"economy_cohorts_html_economy_cohorts_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/economy/cohorts.json":{"get":{"summary":"Economy Cohorts Json","operationId":"economy_cohorts_json_economy_cohorts_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/leaderboards":{"get":{"summary":"Leaderboards Index","description":"Curated leaderboard hub — links into the per-cut leaderboards\nthat already exist (``/leaderboard/earnings``, the protocol-mix\ncharts on ``/flows``) plus the new live-callable + uptime cuts\ncomputed below.","operationId":"leaderboards_index_leaderboards_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/intel/{domain}.md":{"get":{"summary":"Intel Page Md","description":"Markdown twin of the HTML page, for AI consumers + the\nStainless-pattern ``.md`` discoverability convention used across\nthe rest of the site (``/blog.md``, ``/agents.md``, etc.).\n\nWe render the same data as compact prose + bullet points; the\npaywall tiles render as ``🔒 …`` lines so an AI client sees the\nsame locked-vs-free split a human visitor sees in the browser.","operationId":"intel_page_md_intel__domain__md_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/intel/{domain}":{"get":{"summary":"Intel Page","description":"Public-facing intel page for one indexed agent domain.","operationId":"intel_page_intel__domain__get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/intel":{"get":{"summary":"Intel Index","description":"Index landing — a small explainer plus links to the top-quality\nintel pages so search engines and LLMs have a hub from which to\ndiscover the per-domain leaves. Each indexed domain also lives in\nthe sitemap, so this page is primarily for human readers who\narrive at /intel without a specific domain in mind.","operationId":"intel_index_intel_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/api/agents/{domain}/callers":{"get":{"summary":"Api Agent Callers","description":"Public caller-mix for one agent — Claude Desktop / Cursor /\nChatGPT / OpenAI Responses / Continue / curl / browser / n8n.\n\nFree tier: aggregate only (no per-day time-series, no\ncaller_agent_domain enumeration). Both of those live behind the\npaid ``agent_callers`` skill at higher granularity. This endpoint\nis the public showcase of the data — enough to convince a reader\nthe data is real without giving away the time-series + peer\nenumeration that the paid product sells.","operationId":"api_agent_callers_api_agents__domain__callers_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/intents/trending":{"get":{"summary":"Api Trending Intents","description":"Top intent_tokens (normalised search queries) over the window.\n\n``intent_token`` is the first 80 chars of the user's task text\nafter normalisation in ``app/call_log.py``. Excludes empty\nintents (probe traffic) and self-origin lookups.","operationId":"api_trending_intents_api_intents_trending_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":30,"minimum":1,"default":7,"title":"Days"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/intents/gaps":{"get":{"summary":"Api Intent Gaps","description":"Searches that returned zero results — the \"skill gap\" feed.\n\nDrives \"what should I build?\" for agent operators + signals to us\nwhere the canonical-skill taxonomy is missing entries.","operationId":"api_intent_gaps_api_intents_gaps_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":30,"minimum":1,"default":7,"title":"Days"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":30,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agents/{domain}/card-changes":{"get":{"summary":"Api Agent Card Changes","description":"Per-agent card-change history with structured diffs.\n\nEach entry: ``{captured_at, card_hash, diff: {skills_added,\nskills_removed, skills_changed, fields_changed, human_summary}}``.\nSkipping is_empty entries because identical raw_card bodies still\nsometimes generate a new snapshot via probe-replay; we don't want\nto surface those as user-facing \"changes\".","operationId":"api_agent_card_changes_api_agents__domain__card_changes_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/feed/drift.jsonl":{"get":{"summary":"Feed Drift Jsonl","description":"Streaming NDJSON of every card change in the trailing window.\n\nOne JSON object per line, newest first:\n    {\"captured_at\": ISO, \"domain\": \"...\", \"diff\": {...}}\n\nIntended for RSS-style subscribers (scripts that tail this file\nhourly) + AI-crawlers ingesting the agent-web changelog. Free.","operationId":"feed_drift_jsonl_feed_drift_jsonl_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":30,"minimum":1,"default":7,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/transparency/daily-root.json":{"get":{"summary":"Api Transparency Latest","description":"Latest published transparency root + the algorithm reference.","operationId":"api_transparency_latest_api_transparency_daily_root_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/transparency/{date}.json":{"get":{"summary":"Api Transparency For Date","description":"Per-date transparency root lookup. ``date`` is ISO YYYY-MM-DD.","operationId":"api_transparency_for_date_api_transparency__date__json_get","parameters":[{"name":"date","in":"path","required":true,"schema":{"type":"string","title":"Date"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/transparency":{"get":{"summary":"Transparency Page","description":"Human-readable explainer + the running root history table.\n\nConscious: this is a SHOW-OUR-WORK page. Search engines + AI\ncrawlers landing here learn that we publish reproducible hashes\nover historical measurements — which is the trust positioning we\nwant.","operationId":"transparency_page_transparency_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/api/schemas/conformance.json":{"get":{"summary":"Api Schema Conformance","operationId":"api_schema_conformance_api_schemas_conformance_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/schemas/skill-taxonomy.json":{"get":{"summary":"Api Schema Skill Taxonomy","description":"Versioned canonical-skill taxonomy as a machine-readable\nschema. Each skill includes its URN — ``urn:agenstry:skill:<id>``\n— so external systems can reference our taxonomy without copying\nit. URNs are stable: the ``id`` column on ``CanonicalSkill`` is\nthe source of truth and never changes.","operationId":"api_schema_skill_taxonomy_api_schemas_skill_taxonomy_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/marketplace":{"get":{"summary":"Skills Marketplace","description":"Browseable catalogue of every paid skill — price + example +\ncopy-paste curl snippet. Two failure modes the page fixes:\n\n1. ``/pricing`` describes paid skills in prose but the call shape\n   isn't anywhere a developer can paste from.\n2. ``/api/v1/skills/<id>`` returns 402 for paid skills with the\n   paywall body, but a caller who hasn't called the endpoint yet\n   has no way to discover the skill exists.\n\nThe page renders every PAID_SKILLS entry from\n``app/skill_catalog.py`` plus the matching FREE_SKILLS so the\ncatalogue is the single browseable view of the entire skill\nsurface. Both REST + JSON-RPC invocation paths are shown.","operationId":"skills_marketplace_marketplace_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/onboard":{"get":{"summary":"Onboard Page","operationId":"onboard_page_onboard_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/onboard/chat":{"post":{"summary":"Onboard Chat","description":"HTMX endpoint — accepts a user message, advances the wizard, returns\nthe new chat fragment (user bubble + assistant bubble + state hidden field).","operationId":"onboard_chat_onboard_chat_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_onboard_chat_onboard_chat_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/onboard/preview/{session_token}":{"get":{"summary":"Onboard Preview","operationId":"onboard_preview_onboard_preview__session_token__get","parameters":[{"name":"session_token","in":"path","required":true,"schema":{"type":"string","title":"Session Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/onboard/finalise":{"post":{"summary":"Onboard Finalise","description":"Commit the wizard. Requires:\n  - Logged-in user\n  - Verified ownership of `domain`\n  - At least one of: business_name OR business_type collected\n\nIdempotent on (user, domain) — repeated finalisation just refreshes the\ncard and MCP list rather than creating a second managed agent.","operationId":"onboard_finalise_onboard_finalise_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_onboard_finalise_onboard_finalise_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/onboard/start-verification":{"post":{"summary":"Onboard Start Verification","description":"Helper that the wizard can use to kick off DNS verification without\nbouncing the user out to /account. Reuses the same AgentVerification row\nflow.","operationId":"onboard_start_verification_onboard_start_verification_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_onboard_start_verification_onboard_start_verification_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/agents/{domain}/agent-card.json":{"get":{"summary":"Hosted Card","description":"Public AgentCard endpoint. Returns 404 when the agent is in\ndraft state (``published_at IS NULL``) — operators can preview\ntheir card via /account before flipping the publish switch.","operationId":"hosted_card_agents__domain__agent_card_json_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/agents/{domain}/jwks.json":{"get":{"summary":"Hosted Jwks","description":"Per-domain JWKS. Like the AgentCard endpoint, gated on\n``published_at IS NOT NULL`` — a draft agent's signing key\nshouldn't leak via the well-known path, since the agent card\nisn't public yet.","operationId":"hosted_jwks_agents__domain__jwks_json_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/agents/{domain}/a2a":{"post":{"summary":"Hosted A2A","description":"JSON-RPC entry. Reuses the global a2a.py error envelope shape so\ncounterparties can talk to the global meta-agent and a per-domain\nmanaged agent with the same client code.","operationId":"hosted_a2a_agents__domain__a2a_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/agents/{domain}/manage":{"get":{"summary":"Managed Dashboard","operationId":"managed_dashboard_agents__domain__manage_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/managed/{domain}/mcp":{"post":{"summary":"Managed Mcp Upsert","description":"Add or update one MCP config. Token is encrypted before persistence.","operationId":"managed_mcp_upsert_account_managed__domain__mcp_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_managed_mcp_upsert_account_managed__domain__mcp_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/managed/{domain}/mcp/delete":{"post":{"summary":"Managed Mcp Delete","operationId":"managed_mcp_delete_account_managed__domain__mcp_delete_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_managed_mcp_delete_account_managed__domain__mcp_delete_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/managed/{domain}/prompt":{"post":{"summary":"Managed Prompt Update","description":"Replace the agent's system prompt. Empty string resets to the runtime default.","operationId":"managed_prompt_update_account_managed__domain__prompt_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_managed_prompt_update_account_managed__domain__prompt_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/managed/{domain}/wallet":{"post":{"summary":"Managed Wallet Attach","description":"Re-attach (or detach) the wallet that callers pay into.\n\n``wallet_id`` = \"\" or \"none\" → detach the wallet entirely (agent becomes\nfree-to-call). Any other value must be a UserWallet.id owned by the\ncurrent user.","operationId":"managed_wallet_attach_account_managed__domain__wallet_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_managed_wallet_attach_account_managed__domain__wallet_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/managed/{domain}/try":{"post":{"summary":"Managed Try","description":"Run a test prompt through dispatch_query. Returns a small result page\nwith the agent's reply + latency so the owner can verify end-to-end\nbehaviour before sharing the A2A endpoint with counterparties.","operationId":"managed_try_account_managed__domain__try_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_managed_try_account_managed__domain__try_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/managed/{domain}/publish":{"post":{"summary":"Managed Publish","description":"Owner-only: flip a draft managed agent to published. Idempotent —\nre-publishing a published agent preserves the original timestamp.\n\nAfter this fires:\n  * /agents/<d>/agent-card.json serves the signed card publicly\n  * /agents/<d>/jwks.json serves the public key\n  * /agents/<d>/a2a accepts external SendMessage calls\n  * /agents/<d> doc page is reachable\n  * The Agent row is upserted so /search + federation feed\n    pick it up on the next crawl tick (~5 min)\n\nThe owner can hit /account/managed/<d>/unpublish to flip back to\ndraft without losing the configuration or signing key.","operationId":"managed_publish_account_managed__domain__publish_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/managed/{domain}/unpublish":{"post":{"summary":"Managed Unpublish","description":"Owner-only: flip a published managed agent back to draft.\nPublic surfaces immediately stop serving; the configuration +\nsigning key + card JSON stay intact so a re-publish is one\nclick away.","operationId":"managed_unpublish_account_managed__domain__unpublish_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/managed/{domain}/delete":{"post":{"summary":"Managed Delete","operationId":"managed_delete_account_managed__domain__delete_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/managed/{domain}/payouts/stripe/connect":{"post":{"summary":"Managed Payouts Stripe Connect","description":"Kick off (or resume) Stripe Connect onboarding. Idempotent —\nif the agent already has an ``acct_…`` we re-use it. Persists the\naccount ID BEFORE generating the link so a network failure between\ncreate + link doesn't orphan the Stripe row.","operationId":"managed_payouts_stripe_connect_account_managed__domain__payouts_stripe_connect_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/managed/{domain}/payouts/stripe/return":{"get":{"summary":"Managed Payouts Stripe Return","description":"Stripe redirects the SMB here on onboarding finish. We don't\ntrust the redirect for status — the ``account.updated`` webhook\nis the authoritative source. Just bounce to manage page.","operationId":"managed_payouts_stripe_return_account_managed__domain__payouts_stripe_return_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/managed/{domain}/payouts/stripe/refresh":{"get":{"summary":"Managed Payouts Stripe Refresh","description":"Stripe redirects here when the Account Link expires before\nthe SMB completes onboarding. Mint a fresh link + bounce in.","operationId":"managed_payouts_stripe_refresh_account_managed__domain__payouts_stripe_refresh_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/managed/{domain}/payouts/stripe/disconnect":{"post":{"summary":"Managed Payouts Stripe Disconnect","description":"Owner pulls the rail. Best-effort delete on Stripe, always\nclear our column, fall preference back (\"stripe\"→\"none\",\n\"both\"→\"x402\").","operationId":"managed_payouts_stripe_disconnect_account_managed__domain__payouts_stripe_disconnect_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/account/managed/{domain}/payouts/preference":{"post":{"summary":"Managed Payouts Preference","description":"Owner picks which rails the AgentCard advertises. Server-side\nvalidates that ``stripe`` / ``both`` require an ACTIVE Stripe\naccount — the UI hides those options when not, but a hand-crafted\nPOST shouldn't be able to push the card into \"accepts stripe\"\nwith no working Stripe rail behind it.","operationId":"managed_payouts_preference_account_managed__domain__payouts_preference_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_managed_payouts_preference_account_managed__domain__payouts_preference_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/quality":{"get":{"tags":["quality"],"summary":"Quality Dashboard","operationId":"quality_dashboard_api_quality_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Quality Dashboard Api Quality Get"}}}}}}},"/api/pricing":{"get":{"tags":["pricing"],"summary":"Pricing Summary","operationId":"pricing_summary_api_pricing_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Pricing Summary Api Pricing Get"}}}}}}},"/api/wallets":{"get":{"summary":"List Wallets","operationId":"list_wallets_api_wallets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"summary":"Add Wallet","operationId":"add_wallet_api_wallets_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/wallets/{wallet_id}/primary":{"post":{"summary":"Set Primary","operationId":"set_primary_api_wallets__wallet_id__primary_post","parameters":[{"name":"wallet_id","in":"path","required":true,"schema":{"type":"integer","title":"Wallet Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/wallets/{wallet_id}/paid-calls":{"get":{"summary":"List Paid Calls For Wallet","description":"Return recent paid-call ledger entries attributed to a user's wallet.\n\nFilters ``paid_calls`` by ``user_id`` (because settlement-ref attribution\nisn't 1:1 with a single wallet — the same Stripe customer can pay from\ndifferent cards, the same on-chain user can sign from multiple wallets,\nand the ledger normalises to *who got billed*). The wallet_id is\nvalidated to belong to the caller so the path component still scopes\nthe response to that operator.\n\nPagination: cursor on ``created_at``. ``before`` is an ISO-8601\ntimestamp; we return rows strictly older than that. ``limit`` is clamped\nto [1, 200] so a 47k-row ledger can't be dumped in one request.\n\nMirrors AgentCallLog's listing pattern (see app/api/managed_routes.py)\nso a downstream UI / SDK can use the same paging code for both surfaces.","operationId":"list_paid_calls_for_wallet_api_wallets__wallet_id__paid_calls_get","parameters":[{"name":"wallet_id","in":"path","required":true,"schema":{"type":"integer","title":"Wallet Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"before","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Before"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/wallets/{wallet_id}":{"delete":{"summary":"Delete Wallet","operationId":"delete_wallet_api_wallets__wallet_id__delete","parameters":[{"name":"wallet_id","in":"path","required":true,"schema":{"type":"integer","title":"Wallet Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/stripe/create-intent":{"post":{"summary":"Create Per Call Intent","description":"Create a Stripe PaymentIntent for ONE call to one of our paid skills.\n\nThe caller hits this once with ``{\"skill_id\":\"compose\"}``, gets back a\n``client_secret`` to confirm payment client-side (or via Stripe Hosted\nPayment Page), then attaches the resulting PaymentIntent id to their\nA2A request via ``X-Stripe-PaymentIntent: <id>``. The skill dispatcher\nconfirms the PI succeeded for at least the expected amount before\nrunning the skill.\n\nNo subscription, no customer required — anonymous one-shot purchases\nwork fine. We do stamp the user id when the caller is signed in so the\npaid_calls ledger is attributable.","operationId":"create_per_call_intent_billing_stripe_create_intent_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/wallets/stripe/balance":{"get":{"summary":"Get Stripe Balance","description":"Current prepaid balance for the signed-in user. Zero-balance returns\na row with balance_usd=0 so the UI doesn't have to special-case \"never\ntopped up\".\n\nAlways ``Cache-Control: private, no-store`` because the body is the\nrequesting user's personal balance + lifetime spend numbers — these\nmust never land in a shared CDN cache or an intermediary's bytes-\nof-the-day buffer. Hardening against future-cache-config drift.","operationId":"get_stripe_balance_api_wallets_stripe_balance_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/wallets/stripe/topup":{"post":{"summary":"Create Stripe Topup Session","description":"Create a Stripe Checkout session for a one-time $5/$10/$25 top-up.\n\nReturns ``{\"checkout_url\": \"...\"}``. The caller opens that in a browser,\ncompletes payment, and is redirected to ``/account?topup=ok``. Behind\nthe scenes Stripe fires ``checkout.session.completed`` to our webhook\n(``POST /webhooks/stripe/topup``), which credits the balance.\n\nWe use ``price_data`` ad-hoc instead of a pre-configured Price object so\na new top-up amount needs no Stripe Dashboard edit — change\n``TOPUP_AMOUNTS_USD`` and the new amount works immediately.","operationId":"create_stripe_topup_session_api_wallets_stripe_topup_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/wallets/stripe/options":{"get":{"summary":"List Topup Options","description":"Public list of top-up amounts + disclosed net credit per option.\n\nNo auth — the UI can render the disclosure even for signed-out callers\nwho are looking at /pricing. Mirrors what\n/api/wallets/stripe/topup will actually credit, so the user can compare\nbefore clicking. Marketing surfaces (pricing page, account widget) read\nfrom here instead of hard-coding the 2.9%+$0.30 schedule.","operationId":"list_topup_options_api_wallets_stripe_options_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/webhooks/stripe/topup":{"post":{"summary":"Stripe Topup Webhook","description":"Stripe webhook for the prepaid-wallet top-up flow.\n\nValidates the ``stripe-signature`` header against\n``settings.stripe_webhook_secret`` (rejects bad sig with 400 — Stripe\ntreats anything outside 200-299 as a delivery failure and retries with\nexponential backoff up to 3 days). On ``checkout.session.completed``\nwith the right metadata, credits the balance.\n\nReplay protection: reuses ``ProcessedStripeEvent`` so a duplicate event\nid (Stripe retries on transient failure, attackers can replay a\ncaptured signed payload) short-circuits and returns 200 without\nre-crediting. Same scheme as ``/webhooks/stripe`` for subscription\nevents so both paths share the same audit table.\n\nWe DON'T forward unrelated events (subscription.updated, invoice.paid,\n…) to the subscription handler — those have their own dedicated\nendpoint at ``/webhooks/stripe``. If an operator points the wallet\nwebhook at the wrong URL we'd rather silently no-op than double-write.","operationId":"stripe_topup_webhook_webhooks_stripe_topup_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/admin/reindex":{"post":{"summary":"Trigger Reindex","description":"Kick off a background reindex pass. Returns 202 immediately; poll\n``/admin/reindex/status`` to track completion. Refuses to start a second\npass while one is already running (the underlying SQL is idempotent —\nDELETE+INSERT per row — but two concurrent embedders just waste CPU).\n\n``batch`` clamped to [1, 256]; ``throttle_s`` to [0.0, 10.0]. The\ndefaults (batch=16, throttle=0.5s) are tuned for the 2-vCPU prod box —\nkeeps healthcheck responsive while still completing a full agents+mcps\npass in roughly 30–45 min.\n\n``kind`` scopes the pass to one of ``all`` | ``agents`` | ``mcps`` |\n``skills``. The skills-only path (~411 rows) finishes in ~20 min and\ngets the /api/route \"match-to-canonical-skill\" feature working as\nsoon as a deploy drops the canonical_skills_vec table, without having\nto wait for the multi-hour full agents pass.","operationId":"trigger_reindex_admin_reindex_post","parameters":[{"name":"batch","in":"query","required":false,"schema":{"type":"integer","default":16,"title":"Batch"}},{"name":"throttle_s","in":"query","required":false,"schema":{"type":"number","default":0.5,"title":"Throttle S"}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","default":"all","title":"Kind"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/reindex/status":{"get":{"summary":"Reindex Status","operationId":"reindex_status_admin_reindex_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/admin/snapshot-now":{"post":{"summary":"Trigger Revenue Snapshot","description":"Force an immediate on-chain revenue refresh + daily snapshot pass.\n\nThe scheduler runs this every 24h (REVENUE_REFRESH_INTERVAL_S). This\nendpoint exists for: smoke-testing the snapshot pipeline after a\ndeploy, filling a missing day if a tick was skipped during a rolling\ndeploy, manually catching up after disabling the scheduler.","operationId":"trigger_revenue_snapshot_admin_snapshot_now_post","parameters":[{"name":"max_wallets","in":"query","required":false,"schema":{"type":"integer","default":200,"title":"Max Wallets"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/economy-briefing/regenerate":{"post":{"summary":"Regenerate Economy Briefing","description":"Manually regenerate the weekly State-of-the-Agent-Economy briefing.\n\nUsed for: (a) the very first run (kick off before the Monday tick\narrives), (b) re-running after a bad LLM output, (c) testing after\ndeploying briefing-prompt tweaks.\n\nArgs (query string):\n  iso_week: ``YYYY-Www`` override; defaults to the current ISO week.\n  send_email: when True (default) AND a real broadcast hasn't gone\n    out yet, mail the subscriber list immediately after generation.\n    Set False for \"regenerate the text only, don't broadcast\".\n  dry_run_email: when True, log who WOULD be emailed but don't call\n    Resend. Lets the operator verify the recipient list + subject\n    line before the real send. Implies ``send_email=true``.\n  force: when True, regenerate even if a published row exists.\n    Without this flag, a re-run skips a week that already has a\n    published briefing (idempotency safeguard).","operationId":"regenerate_economy_briefing_admin_economy_briefing_regenerate_post","parameters":[{"name":"iso_week","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Iso Week"}},{"name":"send_email","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Send Email"}},{"name":"dry_run_email","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Dry Run Email"}},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Force"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/economy-briefing/email-only":{"post":{"summary":"Email Only Economy Briefing","description":"Broadcast a published briefing to subscribers WITHOUT regenerating.\n\nUsed when the generation already happened (e.g. via the weekly\nscheduler tick) but we need to fire the email manually — first run\nafter seeding subscribers, or after a transient Resend outage.\n\n``force_resend=true`` overrides the \"already sent this week\"\nidempotency guard; without it, a row whose ``last_email_sent_at``\nis non-NULL is skipped.\n\n``dry_run=true`` logs the recipient list + subject line without\ncalling Resend.","operationId":"email_only_economy_briefing_admin_economy_briefing_email_only_post","parameters":[{"name":"iso_week","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Iso Week"}},{"name":"force_resend","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Force Resend"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Dry Run"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/oasf-crosswalk":{"post":{"summary":"Trigger Oasf Crosswalk","description":"Re-compute the OASF taxonomy crosswalk for every canonical skill.\n\nFederates Agenstry's 411+ canonical skills onto the AGNTCY/Cisco\nOASF taxonomy via embedding cosine similarity. Each canonical row\ngets ``(oasf_id, oasf_confidence)`` written; only matches above\n``oasf_taxonomy.MIN_PUBLISH_CONFIDENCE`` (0.70) appear in the\n/.well-known/oasf.json emission.\n\nIdempotent: re-running rewrites every row from scratch (handy after\nembedding-model upgrades). Pass ``only_unmapped=true`` to skip rows\nthat already have an oasf_id — useful for incremental top-ups after\nnew canonical skills are auto-discovered.\n\n``limit`` chunks the pass for very large taxonomies; default ``None``\nprocesses everything in one transaction.","operationId":"trigger_oasf_crosswalk_admin_oasf_crosswalk_post","parameters":[{"name":"only_unmapped","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Only Unmapped"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/skills":{"get":{"tags":["skills"],"summary":"List Skills","description":"Discovery surface: every skill, with price + REST path + intent\naliases. Lets a downstream caller programmatically learn what we\noffer without scraping the agent card or pricing page.","operationId":"list_skills_api_v1_skills_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/skills/{skill_id}":{"get":{"tags":["skills"],"summary":"Run Skill","description":"Run a single skill via REST.\n\nFor paid skills, the same x402 / Stripe paywall as the JSON-RPC endpoint\napplies — when the caller hasn't supplied a valid payment header we\nreturn HTTP 402 with the ``paymentRequirements`` body that an x402\nclient knows how to settle.\n\nIdempotency: ``X-Payment`` headers carrying the same on-chain authoriza-\ntion nonce hit the same ``paid_calls`` row and short-circuit to\n\"already paid\" — safe to retry.","operationId":"run_skill_api_v1_skills__skill_id__get","parameters":[{"name":"skill_id","in":"path","required":true,"schema":{"type":"string","title":"Skill Id"}},{"name":"arg","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Skill argument (see /api/v1/skills)","title":"Arg"},"description":"Skill argument (see /api/v1/skills)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/subscribe":{"post":{"summary":"Subscribe","operationId":"subscribe_api_subscribe_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_subscribe_api_subscribe_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/unsubscribe":{"get":{"summary":"Unsubscribe","operationId":"unsubscribe_unsubscribe_get","parameters":[{"name":"t","in":"query","required":true,"schema":{"type":"string","minLength":20,"maxLength":128,"title":"T"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/subscribe/health":{"get":{"summary":"Subscribe Health","operationId":"subscribe_health_api_subscribe_health_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/contact":{"get":{"summary":"Contact Form","description":"Render the contact form. Issues a signed timestamp embedded in a\nhidden field that the POST handler validates — provides both the\nHMAC-integrity check AND the min-time-to-submit gate.","operationId":"contact_form_contact_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"summary":"Contact Submit","operationId":"contact_submit_contact_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_contact_submit_contact_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/widget.js":{"get":{"summary":"Widget Js","description":"Serve the embeddable chat widget JS.\n\nThe ``agent`` query param identifies WHICH managed agent the widget\ntalks to. We bake it (and our canonical base URL) into the JS so\nthe embedding site doesn't need to configure anything beyond the\n``<script src=…>`` tag.\n\nValidates the agent exists + is active before serving — prevents\ncustomers from embedding widgets for typo'd / deleted agents.","operationId":"widget_js_widget_js_get","parameters":[{"name":"agent","in":"query","required":true,"schema":{"type":"string","maxLength":255,"description":"Managed-agent domain","title":"Agent"},"description":"Managed-agent domain"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/widget/{domain}/message":{"options":{"summary":"Widget Message Preflight","description":"CORS preflight for the widget message endpoint. Open to any origin\n(embed is the whole point) but only POST + Content-Type allowed.","operationId":"widget_message_preflight_widget__domain__message_options","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Widget Message","description":"Single-turn chat endpoint for the embeddable widget.\n\nTranslates the simple ``{message, taskId?}`` widget shape into an\nA2A ``SendMessage`` call against the managed agent, returns the\nassistant's first text-part as plain ``{reply, taskId}``.\n\nRate-limited per IP (60/hour by default) — generous for genuine\ncustomer use but tight enough to make ill-intentioned scraping\nexpensive. The agent's own quota (``ManagedAgent.call_quota_daily``)\nis the second line of defense.","operationId":"widget_message_widget__domain__message_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/.well-known/x402":{"get":{"summary":"Well Known X402","operationId":"well_known_x402__well_known_x402_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/ap2":{"get":{"summary":"Well Known Ap2","description":"AP2 v1 discovery document.\n\nReturns ``status: \"advertised\"`` until the merchant-role\nimplementation lands. AP2 spec doesn't standardise this URL today;\nwe mirror the ``/.well-known/x402`` convention so crawlers that\nalready speak well-known well also probe us under AP2.","operationId":"well_known_ap2__well_known_ap2_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/ap2/mandates/payment":{"post":{"summary":"Ap2 Mandates Not Implemented","description":"Honest 501 from every advertised AP2 mandate path.\n\nThe 5 routes registered on this handler are the union of (a) what\nthe AP2 v1 reference implementation expects (``/mandates/cart``,\n``/mandates/payment``) and (b) what AP2-aware A2A clients have been\nseen probing in the wild (``/mandates`` root, ``/mandates/intent``).\nAll five collapse to the same explanation so a client doesn't see\ninconsistent behaviour by URL.\n\nStatus code 501 (Not Implemented) is the right surface for a route\nthat exists at the spec'd path but lacks the server-side logic —\ndistinct from 404 (path doesn't exist) and 200 (silently accepted).","operationId":"ap2_mandates_not_implemented_ap2_mandates_payment_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/ap2/mandates/cart":{"post":{"summary":"Ap2 Mandates Not Implemented","description":"Honest 501 from every advertised AP2 mandate path.\n\nThe 5 routes registered on this handler are the union of (a) what\nthe AP2 v1 reference implementation expects (``/mandates/cart``,\n``/mandates/payment``) and (b) what AP2-aware A2A clients have been\nseen probing in the wild (``/mandates`` root, ``/mandates/intent``).\nAll five collapse to the same explanation so a client doesn't see\ninconsistent behaviour by URL.\n\nStatus code 501 (Not Implemented) is the right surface for a route\nthat exists at the spec'd path but lacks the server-side logic —\ndistinct from 404 (path doesn't exist) and 200 (silently accepted).","operationId":"ap2_mandates_not_implemented_ap2_mandates_cart_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/ap2/mandates/intent":{"post":{"summary":"Ap2 Mandates Not Implemented","description":"Honest 501 from every advertised AP2 mandate path.\n\nThe 5 routes registered on this handler are the union of (a) what\nthe AP2 v1 reference implementation expects (``/mandates/cart``,\n``/mandates/payment``) and (b) what AP2-aware A2A clients have been\nseen probing in the wild (``/mandates`` root, ``/mandates/intent``).\nAll five collapse to the same explanation so a client doesn't see\ninconsistent behaviour by URL.\n\nStatus code 501 (Not Implemented) is the right surface for a route\nthat exists at the spec'd path but lacks the server-side logic —\ndistinct from 404 (path doesn't exist) and 200 (silently accepted).","operationId":"ap2_mandates_not_implemented_ap2_mandates_intent_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/ap2/mandates":{"get":{"summary":"Ap2 Mandates Not Implemented","description":"Honest 501 from every advertised AP2 mandate path.\n\nThe 5 routes registered on this handler are the union of (a) what\nthe AP2 v1 reference implementation expects (``/mandates/cart``,\n``/mandates/payment``) and (b) what AP2-aware A2A clients have been\nseen probing in the wild (``/mandates`` root, ``/mandates/intent``).\nAll five collapse to the same explanation so a client doesn't see\ninconsistent behaviour by URL.\n\nStatus code 501 (Not Implemented) is the right surface for a route\nthat exists at the spec'd path but lacks the server-side logic —\ndistinct from 404 (path doesn't exist) and 200 (silently accepted).","operationId":"ap2_mandates_not_implemented_ap2_mandates_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"summary":"Ap2 Mandates Not Implemented","description":"Honest 501 from every advertised AP2 mandate path.\n\nThe 5 routes registered on this handler are the union of (a) what\nthe AP2 v1 reference implementation expects (``/mandates/cart``,\n``/mandates/payment``) and (b) what AP2-aware A2A clients have been\nseen probing in the wild (``/mandates`` root, ``/mandates/intent``).\nAll five collapse to the same explanation so a client doesn't see\ninconsistent behaviour by URL.\n\nStatus code 501 (Not Implemented) is the right surface for a route\nthat exists at the spec'd path but lacks the server-side logic —\ndistinct from 404 (path doesn't exist) and 200 (silently accepted).","operationId":"ap2_mandates_not_implemented_ap2_mandates_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/playground":{"get":{"summary":"Playground Page","description":"Render the chat UI. Anonymous users get redirected to /login with\n``?next=/playground`` so they bounce straight back after auth.","operationId":"playground_page_playground_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/playground/ask":{"post":{"summary":"Playground Ask","description":"Forward ``message`` to our own ``/a2a`` as a JSON-RPC ``message/send``.\n\nWe construct the JSON-RPC envelope ourselves and invoke the existing\nhandler in-process — same code path as a remote A2A peer, just no\nextra HTTP hop. The agent's reply (``result.parts[0].text``) is\nreturned to the browser so the page can render it.","operationId":"playground_ask_playground_ask_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_playground_ask_playground_ask_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/staff/":{"get":{"summary":"Staff Overview","operationId":"staff_overview_staff__get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/staff":{"get":{"summary":"Staff Overview","operationId":"staff_overview_staff_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/staff/users":{"get":{"summary":"Staff Users","operationId":"staff_users_staff_users_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Q"}},{"name":"plan","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Plan"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/staff/activity":{"get":{"summary":"Staff Activity","operationId":"staff_activity_staff_activity_get","parameters":[{"name":"surface","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":16},{"type":"null"}],"title":"Surface"}},{"name":"event_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Event Type"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(ok|err)?$"},{"type":"null"}],"title":"Status"}},{"name":"domain","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Domain"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":200,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/staff/revenue":{"get":{"summary":"Staff Revenue","operationId":"staff_revenue_staff_revenue_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/staff/endpoints":{"get":{"summary":"Staff Endpoints","description":"Per-surface + per-event breakdown of OUR endpoints. Tells us which\nrails (REST / A2A / MCP / web / managed-runtime / try-proxy) get the\nmost usage, what the error rate is per surface, what the median latency\nis, and how many distinct callers each surface has.","operationId":"staff_endpoints_staff_endpoints_get","parameters":[{"name":"window","in":"query","required":false,"schema":{"type":"string","pattern":"^(24h|7d|30d)$","default":"7d","title":"Window"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/staff/callers":{"get":{"summary":"Staff Callers","description":"Who is using OUR service. Two complementary views:\n\n1. ``caller_agent_domain`` — when another A2A peer calls our /a2a endpoint.\n   These are agents in the wild that have wired Agenstry into their loop.\n2. ``caller_kind`` — Claude Desktop, Cursor, ChatGPT, OpenAI Responses, n8n,\n   browser, curl. UA-classified host. Tells us which integrations get the\n   most reach.","operationId":"staff_callers_staff_callers_get","parameters":[{"name":"window","in":"query","required":false,"schema":{"type":"string","pattern":"^(24h|7d|30d)$","default":"7d","title":"Window"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/staff/intents":{"get":{"summary":"Staff Intents","description":"What people are TRYING TO DO when they hit our search / compose / route\nendpoints. ``intent_token`` is the first 80 chars of a user's task text,\nnormalised in call_log.py — drives the \"top searches\" view.\n\nMost actionable: queries that returned zero matches (we know what people\nwant that we DON'T have).","operationId":"staff_intents_staff_intents_get","parameters":[{"name":"window","in":"query","required":false,"schema":{"type":"string","pattern":"^(24h|7d|30d)$","default":"7d","title":"Window"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/staff/api/summary.json":{"get":{"summary":"Staff Api Summary","operationId":"staff_api_summary_staff_api_summary_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/staff/visitors":{"get":{"summary":"Staff Visitors","description":"Visitor analytics — distinct visitors, sessions, top countries,\ntop referrers, hour-of-day × day-of-week heatmap. Reads from\n``AgentCallLog`` rows with ``event_type='page_view'`` (web traffic)\nand ``surface='web'`` (the page-view middleware writes these).\n\nAbove the existing panels we now show a \"traffic quality\"\nbreakdown that splits raw unique-IP counts into four buckets:\nreal humans, AI-tool users (ChatGPT-User / Claude-User / Gemini /\nPerplexity / Grok), suspected scrapers (browsers wearing a fake or\noutdated UA, or part of an identical-UA cluster), and bouncers\n(browsers we can't classify either way). The split lives in\n:mod:`app.staff_bi` — see that module for the heuristic + tests.","operationId":"staff_visitors_staff_visitors_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":7,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/staff/funnel":{"get":{"summary":"Staff Funnel","description":"Conversion funnel: visit → search → result-click → /pricing →\n/account → paid_call. Each stage is a distinct count of visitors\n(auth users by user_id, anonymous by requester_hash) over the\nlast N days. Drop-off between consecutive stages is the conversion\nrate signal.","operationId":"staff_funnel_staff_funnel_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":180,"minimum":1,"default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/staff/errors":{"get":{"summary":"Staff Errors","description":"Recent errors + performance percentiles. Reads ``ok=False`` rows\n(HTTPException + 500 handler + AI tool errors + paid-call failures)\nplus computes p50/p95/p99 latency per surface from successful\nrows. Use this when something looks slow / off.","operationId":"staff_errors_staff_errors_get","parameters":[{"name":"hours","in":"query","required":false,"schema":{"type":"integer","maximum":720,"minimum":1,"default":72,"title":"Hours"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/staff/ai":{"get":{"summary":"Staff Ai","description":"Enterprise AI agent observability — turn volume + per-tool\nusage + recent prompts. Reads ``event_type='enterprise_ai_turn'``\n(one row per user message) and ``event_type='enterprise_ai_tool'``\n(one row per tool dispatch inside an agent loop).","operationId":"staff_ai_staff_ai_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":14,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/staff/live":{"get":{"summary":"Staff Live","description":"Real-time tail of platform traffic. Renders the last 100 calls\nin the window with caller attribution. Auto-refreshes every 5 s\nvia a meta-refresh (the template handles it) so leaving the tab\nopen works as a low-cost \"watchtower\".","operationId":"staff_live_staff_live_get","parameters":[{"name":"minutes","in":"query","required":false,"schema":{"type":"integer","maximum":180,"minimum":1,"default":15,"title":"Minutes"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/staff/metrics":{"get":{"summary":"Staff Metrics","description":"Founder-facing business dashboard. Designed for the \"10 seconds\nevery morning\" workflow: open this page, scan the four bands\n(signups · funnel · MRR · acquisition · top skills), close it.\n\nWhere this differs from the other /staff tabs:\n\n* ``/staff`` is the general overview (DAU/WAU, calls, plan mix).\n* ``/staff/revenue`` shows paid-skill (x402 + Stripe) revenue\n  broken down by skill / rail. NOT subscription MRR.\n* ``/staff/funnel`` shows browse-stage funnel (visit → search →\n  click → pricing → account → paid call), reading page-view rows.\n* ``/staff/users`` is the per-user explorer.\n\nThis page adds the four things missing from all the above:\n\n1. **MRR**: subscription revenue (pro/platform/enterprise), the\n   commitment-stream that drives the company. Computed from\n   ``User.plan`` × monthly-price-by-plan from settings.\n2. **Churn (30d)**: paying users whose ``subscription_canceled_at``\n   landed in the trailing 30 days. Until the migration's column\n   starts getting written by the Stripe webhook + the /account\n   cancel flow, this shows 0 — that's the documented design.\n3. **Activation funnel** with the four stages the visit-funnel\n   skips: signup → DNS-verify → first paid call → paying\n   subscriber. These are the conversion moments that matter for\n   NRR, not the discovery stages on /staff/funnel.\n4. **Acquisition channel** breakdown — group signups by\n   ``utm_source``, with ``NULL`` rendered as \"direct\" (the\n   no-cookie fallback). 30d window keeps it actionable; longer\n   windows live on /staff/users with filters.\n\nPlus a \"top paid skills today\" panel (last 24h, what users are\nactually paying for right now — distinct from /staff/revenue's\nall-time view).","operationId":"staff_metrics_staff_metrics_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/health":{"get":{"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Health Health Get"}}}}}}},"/.well-known/agent-card.json":{"get":{"summary":"Well Known Card","operationId":"well_known_card__well_known_agent_card_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/oasf.json":{"get":{"summary":"Well Known Oasf","operationId":"well_known_oasf__well_known_oasf_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/jwks.json":{"get":{"summary":"Well Known Jwks","description":"Public key set for verifying our agent card's JWS signature.","operationId":"well_known_jwks__well_known_jwks_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/agent/authenticatedExtendedCard":{"get":{"summary":"Authenticated Extended Card","description":"A2A v1.0 §3.1.11 — authenticated extended card.\n\nReturned to callers who provide a working principal (session\ncookie OR ``Authorization: Bearer ekey_…`` OR legacy af_ API\nkey). Same shape as the public card, but each skill carries an\n``x-agenstry-pricing`` extension stanza with the per-call\nprice + accepted rails — the spec-conformant \"more detail\nbehind auth\" pattern declared by ``capabilities.extendedAgentCard``.\n\nAnonymous callers get 401 with a ``WWW-Authenticate`` header\npointing at the brand inbox so a script-kiddie probing the\nroute gets a clean failure mode + a human escalation path.","operationId":"authenticated_extended_card_agent_authenticatedExtendedCard_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"Body_bind_catalog_account_catalogs_post":{"properties":{"agent_domain":{"type":"string","maxLength":255,"title":"Agent Domain"},"catalog_url":{"type":"string","maxLength":2048,"title":"Catalog Url"}},"type":"object","required":["agent_domain","catalog_url"],"title":"Body_bind_catalog_account_catalogs_post"},"Body_claim_post_claim_post":{"properties":{"business_name":{"type":"string","maxLength":255,"title":"Business Name"},"contact_email":{"type":"string","maxLength":255,"title":"Contact Email"},"website_url":{"type":"string","maxLength":2048,"title":"Website Url","default":""},"country":{"type":"string","maxLength":64,"title":"Country","default":""},"notes":{"type":"string","maxLength":1000,"title":"Notes","default":""}},"type":"object","required":["business_name","contact_email"],"title":"Body_claim_post_claim_post"},"Body_compose_post_compose_post":{"properties":{"task":{"type":"string","maxLength":2000,"minLength":2,"title":"Task"},"verified_only":{"type":"boolean","title":"Verified Only","default":false},"mode":{"type":"string","title":"Mode","default":"deterministic"}},"type":"object","required":["task"],"title":"Body_compose_post_compose_post"},"Body_contact_submit_contact_post":{"properties":{"name":{"type":"string","maxLength":100,"minLength":1,"title":"Name"},"email":{"type":"string","maxLength":255,"minLength":3,"title":"Email"},"subject":{"type":"string","maxLength":200,"minLength":1,"title":"Subject"},"message":{"type":"string","maxLength":5000,"minLength":10,"title":"Message"},"website":{"type":"string","title":"Website","default":""},"ts":{"type":"integer","title":"Ts"},"nonce":{"type":"string","title":"Nonce"}},"type":"object","required":["name","email","subject","message","ts","nonce"],"title":"Body_contact_submit_contact_post"},"Body_create_api_key_account_api_keys_post":{"properties":{"name":{"type":"string","title":"Name","default":""}},"type":"object","title":"Body_create_api_key_account_api_keys_post"},"Body_create_subscription_account_subscriptions_post":{"properties":{"agent_domain":{"type":"string","maxLength":255,"title":"Agent Domain"},"event_type":{"type":"string","maxLength":32,"title":"Event Type","default":"drift"},"channel":{"type":"string","maxLength":16,"title":"Channel","default":"webhook"},"target":{"type":"string","maxLength":512,"title":"Target","default":""}},"type":"object","required":["agent_domain"],"title":"Body_create_subscription_account_subscriptions_post"},"Body_create_verification_account_verifications_post":{"properties":{"agent_domain":{"type":"string","maxLength":255,"title":"Agent Domain"}},"type":"object","required":["agent_domain"],"title":"Body_create_verification_account_verifications_post"},"Body_enterprise_api_key_create_enterprise_api_keys_post":{"properties":{"name":{"type":"string","maxLength":120,"title":"Name"}},"type":"object","required":["name"],"title":"Body_enterprise_api_key_create_enterprise_api_keys_post"},"Body_enterprise_cohort_create_enterprise_cohorts_post":{"properties":{"name":{"type":"string","maxLength":120,"title":"Name"},"description":{"type":"string","title":"Description","default":""},"kind":{"type":"string","title":"Kind","default":"*"},"category":{"type":"string","title":"Category","default":""},"lei_prefix":{"type":"string","title":"Lei Prefix","default":""},"payment_protocol":{"type":"string","title":"Payment Protocol","default":"*"},"payment_network":{"type":"string","title":"Payment Network","default":""},"min_gross_usd_30d":{"type":"number","title":"Min Gross Usd 30D","default":0.0},"signed_only":{"type":"boolean","title":"Signed Only","default":false},"verified_only":{"type":"boolean","title":"Verified Only","default":false},"anomaly_sigma":{"type":"number","title":"Anomaly Sigma","default":0.0},"anomaly_webhook_url":{"type":"string","title":"Anomaly Webhook Url","default":""}},"type":"object","required":["name"],"title":"Body_enterprise_cohort_create_enterprise_cohorts_post"},"Body_enterprise_watchlist_create_enterprise_watchlist_post":{"properties":{"kind":{"type":"string","title":"Kind"},"value":{"type":"string","title":"Value"},"label":{"type":"string","title":"Label","default":""},"webhook_url":{"type":"string","title":"Webhook Url","default":""}},"type":"object","required":["kind","value"],"title":"Body_enterprise_watchlist_create_enterprise_watchlist_post"},"Body_login_submit_login_post":{"properties":{"email":{"type":"string","maxLength":255,"format":"email","title":"Email"}},"type":"object","required":["email"],"title":"Body_login_submit_login_post"},"Body_managed_mcp_delete_account_managed__domain__mcp_delete_post":{"properties":{"name":{"type":"string","maxLength":128,"title":"Name"}},"type":"object","required":["name"],"title":"Body_managed_mcp_delete_account_managed__domain__mcp_delete_post"},"Body_managed_mcp_upsert_account_managed__domain__mcp_post":{"properties":{"label":{"type":"string","maxLength":64,"title":"Label"},"server_url":{"type":"string","maxLength":512,"title":"Server Url"},"oauth_token":{"type":"string","maxLength":4000,"title":"Oauth Token","default":""},"name":{"type":"string","maxLength":128,"title":"Name","default":""}},"type":"object","required":["label","server_url"],"title":"Body_managed_mcp_upsert_account_managed__domain__mcp_post"},"Body_managed_payouts_preference_account_managed__domain__payouts_preference_post":{"properties":{"rail":{"type":"string","title":"Rail","default":"none"}},"type":"object","title":"Body_managed_payouts_preference_account_managed__domain__payouts_preference_post"},"Body_managed_prompt_update_account_managed__domain__prompt_post":{"properties":{"system_prompt":{"type":"string","maxLength":4000,"title":"System Prompt","default":""}},"type":"object","title":"Body_managed_prompt_update_account_managed__domain__prompt_post"},"Body_managed_try_account_managed__domain__try_post":{"properties":{"test_message":{"type":"string","maxLength":2000,"title":"Test Message"}},"type":"object","required":["test_message"],"title":"Body_managed_try_account_managed__domain__try_post"},"Body_managed_wallet_attach_account_managed__domain__wallet_post":{"properties":{"wallet_id":{"type":"string","title":"Wallet Id"}},"type":"object","required":["wallet_id"],"title":"Body_managed_wallet_attach_account_managed__domain__wallet_post"},"Body_onboard_chat_onboard_chat_post":{"properties":{"message":{"type":"string","maxLength":2000,"title":"Message"}},"type":"object","required":["message"],"title":"Body_onboard_chat_onboard_chat_post"},"Body_onboard_finalise_onboard_finalise_post":{"properties":{"domain":{"type":"string","maxLength":255,"title":"Domain"},"selected_mcp_names":{"type":"string","maxLength":4000,"title":"Selected Mcp Names","default":""}},"type":"object","required":["domain"],"title":"Body_onboard_finalise_onboard_finalise_post"},"Body_onboard_start_verification_onboard_start_verification_post":{"properties":{"agent_domain":{"type":"string","maxLength":255,"title":"Agent Domain"}},"type":"object","required":["agent_domain"],"title":"Body_onboard_start_verification_onboard_start_verification_post"},"Body_playground_ask_playground_ask_post":{"properties":{"message":{"type":"string","maxLength":500,"minLength":1,"title":"Message"}},"type":"object","required":["message"],"title":"Body_playground_ask_playground_ask_post"},"Body_start_checkout_account_checkout_post":{"properties":{"tier":{"type":"string","title":"Tier","default":"pro"}},"type":"object","title":"Body_start_checkout_account_checkout_post"},"Body_submit_post_submit_post":{"properties":{"url":{"type":"string","title":"Url","default":""},"input":{"type":"string","title":"Input","default":""},"kind":{"type":"string","title":"Kind","default":"auto"}},"type":"object","title":"Body_submit_post_submit_post"},"Body_subscribe_api_subscribe_post":{"properties":{"email":{"type":"string","maxLength":254,"format":"email","title":"Email"},"source":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Source"},"topic":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Topic","default":"state-of-economy"}},"type":"object","required":["email"],"title":"Body_subscribe_api_subscribe_post"},"Body_try_agent_try__domain__post":{"properties":{"prompt":{"type":"string","maxLength":2000,"title":"Prompt"}},"type":"object","required":["prompt"],"title":"Body_try_agent_try__domain__post"},"Body_unbind_catalog_account_catalogs_unbind_post":{"properties":{"agent_domain":{"type":"string","maxLength":255,"title":"Agent Domain"}},"type":"object","required":["agent_domain"],"title":"Body_unbind_catalog_account_catalogs_unbind_post"},"Body_verify_post_verify_post":{"properties":{"token":{"type":"string","maxLength":200,"minLength":20,"title":"Token"}},"type":"object","required":["token"],"title":"Body_verify_post_verify_post"},"ComposeRequest":{"properties":{"task":{"type":"string","maxLength":2000,"minLength":2,"title":"Task"},"top_skills":{"type":"integer","maximum":10.0,"minimum":1.0,"title":"Top Skills","default":5},"candidates_per_skill":{"type":"integer","maximum":10.0,"minimum":1.0,"title":"Candidates Per Skill","default":3},"min_skill_confidence":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Min Skill Confidence","default":0.3},"min_quality":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Min Quality","default":0.0},"verified_only":{"type":"boolean","title":"Verified Only","default":false},"require_live":{"type":"boolean","title":"Require Live","default":false},"mode":{"type":"string","pattern":"^(deterministic|llm)$","title":"Mode","default":"deterministic"}},"type":"object","required":["task"],"title":"ComposeRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"IdentityBindRequest":{"properties":{"registry_id":{"type":"string","maxLength":64,"minLength":2,"pattern":"^[a-z][a-z0-9_]+$","title":"Registry Id"},"identifier":{"type":"string","maxLength":64,"minLength":3,"title":"Identifier"}},"type":"object","required":["registry_id","identifier"],"title":"IdentityBindRequest","description":"Bind any registry adapter to an agent."},"LeiBindRequest":{"properties":{"lei":{"type":"string","maxLength":20,"minLength":20,"pattern":"^[0-9A-Z]{18}[0-9]{2}$","title":"Lei"}},"type":"object","required":["lei"],"title":"LeiBindRequest"},"RouteComposeRequest":{"properties":{"task":{"type":"string","maxLength":2000,"minLength":2,"title":"Task"},"top_per_step":{"type":"integer","maximum":10.0,"minimum":1.0,"title":"Top Per Step","default":3},"min_quality":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Min Quality","default":0.0},"require_live":{"type":"boolean","title":"Require Live","default":true},"verified_only":{"type":"boolean","title":"Verified Only","default":false},"streaming_preferred":{"type":"boolean","title":"Streaming Preferred","default":false}},"type":"object","required":["task"],"title":"RouteComposeRequest","description":"Pro multi-agent routing — decompose a task into ordered steps,\neach with a top-3 agent pick using the v2 ranker.\n\n``top_per_step`` is intentionally small (default 3) because the\nresponse payload grows linearly with steps × candidates and clients\noverwhelmingly want \"best + 2 alternates\" per step, not a full list."},"RouteRequest":{"properties":{"task":{"type":"string","maxLength":2000,"minLength":2,"title":"Task"},"limit":{"type":"integer","maximum":25.0,"minimum":1.0,"title":"Limit","default":5},"min_quality":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Min Quality","default":0.0},"require_live":{"type":"boolean","title":"Require Live","default":false},"top_skills":{"type":"integer","maximum":10.0,"minimum":1.0,"title":"Top Skills","default":3},"verified_only":{"type":"boolean","title":"Verified Only","default":false},"streaming_preferred":{"type":"boolean","title":"Streaming Preferred","default":false},"max_price_usdc":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Max Price Usdc"},"max_latency_ms":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Max Latency Ms"},"prefer_signed":{"type":"boolean","title":"Prefer Signed","default":false},"prefer_high_revenue":{"type":"boolean","title":"Prefer High Revenue","default":false},"prefer_verified_business":{"type":"boolean","title":"Prefer Verified Business","default":false}},"type":"object","required":["task"],"title":"RouteRequest"},"SubmitRequest":{"properties":{"input":{"anyOf":[{"type":"string","maxLength":2048,"minLength":2},{"type":"null"}],"title":"Input"},"kind":{"anyOf":[{"type":"string","pattern":"^(auto|a2a|mcp|github|npm|pypi|docker)$"},{"type":"null"}],"title":"Kind"},"url":{"anyOf":[{"type":"string","maxLength":2048,"minLength":4},{"type":"null"}],"title":"Url"}},"type":"object","title":"SubmitRequest","description":"Multi-type submission. ``input`` accepts any of:\n\n  * Full URL — ``https://example.com`` → probed as A2A agent + MCP endpoint\n  * GitHub repo — ``https://github.com/owner/repo`` → indexed as\n    metadata-only MCP from the repo metadata\n  * npm package — ``npm:@scope/pkg`` or scoped package name\n  * PyPI package — ``pypi:pkgname``\n  * Docker image — ``docker:owner/image``\n\n``kind`` is optional; we auto-detect when omitted. ``url`` is kept as\na backwards-compat alias for ``input`` so the original\n``{\"url\": \"...\"}`` payload keeps working."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}