ToxFinder

For AI agents and developers

Everything on this site is available as structured data: 1754 priced clinics across 26 markets, each price traced to the page it came from. No key, no scraping. Version 1.0.0.

Entry points

MCP endpointhttps://toxfinder.com/api/mcpStreamable HTTP, stateless, no authentication
JSON APIhttps://toxfinder.com/api/v1Versioned, read-only, RFC 9457 errors
OpenAPIhttps://toxfinder.com/api/v1/openapi.jsonEvery route, parameter and schema
llms.txthttps://toxfinder.com/llms.txtThe short version of this page
Server cardhttps://toxfinder.com/.well-known/mcp/server-card.jsonMCP discovery metadata (draft SEP-2127)
Static exporthttps://toxfinder.com/data/v1/…The JSON the site is built from

Read this before quoting a number

Every clinic has one headline, pricing.normalized_price, in US dollars per Botox-equivalent unit. It is ToxFinder’s normalization of what the clinic published, never a price the clinic advertised: Dysport units convert at 2.5 to 1, per-area prices are divided by a typical dose. The clinic’s own words and figures are only ever in evidence rows under advertised.

pricing.basis_source must travel with the price. stated is a standing per-unit or per-package rate published on the clinic’s site; member/promo is a member-only or promotional rate, real but conditional; derived is an estimate from a flat per-area price with reduced confidence. A headline is the median of a clinic’s prices in its best tier; tiers are never blended.

confidence (0 to 1) multiplies extraction certainty by conversion certainty. Every row carries observed_at; sites are re-read periodically, roughly quarterly. Tell people to confirm with the clinic before booking. See the method for the reasoning.

MCP tools

Protocol revision 2026-07-28; older revisions still work on the same endpoint. Six read-only, idempotent tools, all returning structured content with an output schema, plus two resources (toxfinder://methodology, toxfinder://products).

list_marketsEvery market with clinic count and median
get_marketmarketQuartiles, histogram, per-city medians, basis and product breakdown, coverage, freshness
compare_marketsmarkets[]Two to six markets side by side, with deltas relative to the first
search_clinicsquery, market, city, state, near, latitude, longitude, radius_miles, product, basis_source, min_price, max_price, min_confidence, observed_after, sort, limit, offsetDeterministic filters on the normalized headline; radius search; summary of the whole match set
get_clinicidOne clinic with every price row, provenance, market rank and nearby clinics
get_price_evidenceobservation_id or clinic_idAdvertised vs normalized vs provenance for one observation or one clinic

Client configuration, for hosts that take a URL:

{
  "mcpServers": {
    "toxfinder": {
      "url": "https://toxfinder.com/api/mcp"
    }
  }
}

One raw call, as the transport sends it:

POST /api/mcp HTTP/1.1
Host: toxfinder.com
Content-Type: application/json
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search_clinics

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "search_clinics",
    "arguments": {
      "near": "Houston",
      "max_price": 12,
      "basis_source": "stated"
    },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": {
        "name": "example-client",
        "version": "1.0"
      },
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}

JSON API

GET /marketsEvery market
GET /markets/{market}One market's statistics
GET /markets/comparemarkets=a,bComparison
GET /clinicssame names as search_clinicsSearch; page with limit (1–100) and offset; paging.next_offset
GET /clinics/{id}One clinic with evidence
GET /clinics/{id}/evidenceEvidence rows only
GET /evidence/{observation_id}One observation's provenance
GET /productsProduct vocabulary with conversion ratios
GET /methodologyBasis, confidence and normalization semantics as data

Examples, all relative to https://toxfinder.com/api/v1:

/clinics?near=Houston&max_price=12&basis_source=stated
/clinics?latitude=29.790408799999998&longitude=-95.77855679999999&radius_miles=20&product=dysport&sort=price
/clinics?market=houston&city=katy&basis_source=stated
/markets/houston
/markets/compare?markets=houston,phoenix
/clinics/nakedmd-med-spa-katy
/clinics/nakedmd-med-spa-katy/evidence

A price row, the shape both surfaces share. Three objects, kept apart on purpose:

{
  "clinic": {
    "id": "nakedmd-med-spa-katy",
    "name": "NakedMD Med Spa Katy",
    "market": "houston",
    "url": "https://toxfinder.com/houston/nakedmd-med-spa-katy/"
  },
  "advertised": {
    "text": "Dysport $4.70 per unit",
    "product": "dysport",
    "basis": "per_unit",
    "price_min": 4.7,
    "price_max": 4.7,
    "currency": "USD",
    "is_promotional": false
  },
  "normalized": {
    "price_per_botox_equivalent_unit": 11.75,
    "normalized_unit": "usd_per_botox_equivalent_unit",
    "conversion_path": "perunit:dysportx2.5",
    "confidence": 0.92,
    "in_headline": true,
    "conversion_version": "n1/1.2.0/1.1.0"
  },
  "provenance": {
    "observation_id": "…64 hex…",
    "source_url": "https://clinic.example/pricing",
    "observed_at": "2026-10-19T12:23:06.6005279+00:00",
    "extractor": "llm",
    "corroborations": 2
  }
}

Identifiers, limits, errors

Clinic ids are URL slugs, issued once and never recomputed; the corpus provider id is also accepted. Market ids are metro keys (houston, phoenix, miami, dfw, boston, san_diego, tampa, new_york, chicago, washington_dc, austin, atlanta, los_angeles, seattle, bay_area, north_jersey, san_antonio, nashville, twin_cities, charlotte, baltimore, rhode_island, new_orleans, honolulu, memphis, maui). Observation ids are 64-character hashes, stable across re-crawls.

Rate limit: 60 requests a minute per caller with a burst of 60, shared between the API and MCP; a 429 carries Retry-After. Page size 1 to 100, radius up to 500 miles, requests time out at 10 seconds. Successful answers are cacheable for five minutes and any origin may read them.

A bad filter is a 400 problem document listing every offending field (or an MCP tool result with isError and the same text); an unknown id is a 404 that says where ids come from. Please attribute ToxFinder and link the clinic page when you quote a figure. Questions: support@apextechnologygroup.io.