{
  "openapi": "3.1.0",
  "info": {
    "title": "ProFix Directory API",
    "description": "Public, machine-readable API for the ProFix Directory — Ohio's most comprehensive home-services directory. Every endpoint is free to use; please cite ProFix Directory in any derived work.",
    "version": "1.0.0",
    "contact": {
      "name": "ProFix Directory",
      "url": "https://profixdirectory.com",
      "email": "contact@profixdirectory.com"
    },
    "license": {
      "name": "CC-BY-4.0",
      "url": "https://creativecommons.org/licenses/by/4.0/"
    },
    "x-methodology-url": "https://profixdirectory.com/methodology",
    "x-algorithm-url": "https://profixdirectory.com/algorithm"
  },
  "servers": [
    {
      "url": "https://profixdirectory.com",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/mcp": {
      "get": {
        "summary": "Model Context Protocol server",
        "description": "Streamable HTTP MCP server exposing 16 tools for AI agents (Claude, ChatGPT, Perplexity): find_pros, find_pros_by_neighborhood, get_pro, list_taxonomy, get_emergency_contacts, get_cost_estimate, list_cost_guides, list_guides, get_guide, triage_symptom, get_methodology, get_active_storm_events, get_verification_feed, get_county_coverage_stats, find_emergency_pros, get_trade_pricing. Use when your agent supports MCP; otherwise prefer the REST endpoints.",
        "tags": [
          "agents"
        ],
        "responses": {
          "200": {
            "description": "MCP handshake"
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "summary": "Liveness + dependency probe",
        "description": "Returns directory load status (pro count, county count) plus presence flags for Stripe, Supabase, PostHog, Resend env vars. Public — useful for monitors and partner status pages.",
        "tags": [
          "data"
        ],
        "responses": {
          "200": {
            "description": "Service healthy"
          },
          "503": {
            "description": "Directory load failed (hard dependency)"
          }
        }
      }
    },
    "/api/verification-feed.json": {
      "get": {
        "summary": "Verification deltas feed",
        "description": "Live JSON feed of license-status changes, new permits, and audit deltas. Refreshed hourly.",
        "tags": [
          "data"
        ],
        "responses": {
          "200": {
            "description": "Verification feed JSON",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/api/lead-feed.json": {
      "get": {
        "summary": "Lead volume + quality-tier aggregate feed",
        "description": "30-day rolling aggregate of homeowner lead submissions, grouped by trade, quality tier (premium/standard/low/needs_review), urgency, and counties with active demand. Zero PII. Refreshes hourly. Useful for sizing local home-services market or summarizing demand signals.",
        "tags": [
          "data"
        ],
        "responses": {
          "200": {
            "description": "Lead feed JSON"
          },
          "503": {
            "description": "Supabase not configured"
          }
        }
      }
    },
    "/api/quality-stats.json": {
      "get": {
        "summary": "Lead-quality score histogram + median per trade",
        "description": "90-day rolling aggregate of lead-quality scores — histogram by 20-point buckets, tier breakdown, overall median, and median per trade (requires ≥3 scored leads per trade to avoid noise). Zero PII. Refreshes hourly. Companion to /api/lead-feed.json.",
        "tags": [
          "data"
        ],
        "responses": {
          "200": {
            "description": "Quality stats JSON"
          },
          "503": {
            "description": "Supabase not configured"
          }
        }
      }
    },
    "/api/coverage-stats.json": {
      "get": {
        "summary": "Coverage snapshot — pro counts by county / region / trade",
        "description": "Static aggregate of verified contractor counts grouped by Ohio county, region (Cleveland/Columbus/Cincinnati/Dayton/Toledo/Findlay/etc.), and trade. Completes the public-data trio (lead-feed + quality-stats + coverage-stats). 1h cache, CC-BY-4.0.",
        "tags": [
          "data"
        ],
        "responses": {
          "200": {
            "description": "Coverage stats JSON"
          }
        }
      }
    },
    "/api/permit-leaderboard.json": {
      "get": {
        "summary": "Permit-pull leaderboard — pro rankings by verified building permits",
        "description": "Ranks Ohio contractors by VERIFIED public building permits pulled in the last 365 days (proof of work, not stars). Per-trade, per-county leaderboards across Lucas / Cuyahoga / Franklin / Hamilton counties. Filter via query params: `?trade=<slug>&county=<slug>|ohio&window=<days>&top=<n>`. Use `county=ohio` for statewide aggregates. CC-BY-4.0. 1h cache.",
        "tags": [
          "data"
        ],
        "parameters": [
          {
            "name": "trade",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter to a single trade slug (plumber, hvac, etc.)"
          },
          {
            "name": "county",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter to a single county slug, or `ohio` for statewide aggregates"
          },
          {
            "name": "window",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 365
            },
            "description": "Days back to count permits (max 1095)"
          },
          {
            "name": "top",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 10
            },
            "description": "Top N entries per leaderboard (max 100)"
          }
        ],
        "responses": {
          "200": {
            "description": "Permit leaderboard JSON"
          }
        }
      }
    },
    "/api/embed/{slug}.json": {
      "get": {
        "summary": "Partner embed feed — top 5 pros for a trade × city pair",
        "description": "Returns the top 5 verified pros for a `{trade}-{city}` slug pair (e.g. `plumber-toledo`, `hvac-cleveland`). Designed for one-line third-party embeds — blogs, newsletters, HOA sites. Includes name, phone, rating, verification tier, and permit count. CC-BY-4.0. 1h cache.",
        "tags": [
          "data"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Slug format `{trade}-{city}` (e.g. plumber-toledo)"
          }
        ],
        "responses": {
          "200": {
            "description": "Embed JSON"
          },
          "404": {
            "description": "Invalid trade-city slug"
          }
        }
      }
    },
    "/api/permit-leaderboard.csv": {
      "get": {
        "summary": "Permit-pull leaderboard — CSV companion to /api/permit-leaderboard.json",
        "description": "RFC 4180 CSV mirror of the permit leaderboard JSON feed. Same query-param filtering (`?trade=&county=&window=&top=`). One row per leaderboard entry. CC-BY-4.0.",
        "tags": [
          "data"
        ],
        "parameters": [
          {
            "name": "trade",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "county",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "window",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 365
            }
          },
          {
            "name": "top",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Permit leaderboard CSV"
          }
        }
      }
    },
    "/api/coverage-stats.csv": {
      "get": {
        "summary": "Coverage snapshot — CSV companion to /api/coverage-stats.json",
        "description": "RFC 4180 CSV with one row per Ohio county (slug, name, region, pro_count). CC-BY-4.0.",
        "tags": [
          "data"
        ],
        "responses": {
          "200": {
            "description": "Coverage stats CSV"
          }
        }
      }
    },
    "/api/lead-feed.csv": {
      "get": {
        "summary": "Lead feed — CSV companion to /api/lead-feed.json",
        "description": "Long-format CSV (window_days, bucket, key, value) for lead aggregate metrics — pivot-friendly. Zero PII. CC-BY-4.0.",
        "tags": [
          "data"
        ],
        "responses": {
          "200": {
            "description": "Lead feed CSV"
          },
          "503": {
            "description": "Supabase not configured"
          }
        }
      }
    },
    "/api/changelog.json": {
      "get": {
        "summary": "Newsroom changelog — machine-readable",
        "description": "JSON companion to /newsroom. Every entry has date, type (research/feature/data/api/design), headline, body, optional url. Sorted newest-first. CC-BY-4.0.",
        "tags": [
          "agents"
        ],
        "responses": {
          "200": {
            "description": "Changelog JSON"
          }
        }
      }
    },
    "/api/newsroom.rss": {
      "get": {
        "summary": "Newsroom RSS 2.0 feed",
        "description": "RSS feed combining changelog entries + published research articles. Subscribe in any RSS reader to track ProFix's product + editorial milestones. CC-BY-4.0.",
        "tags": [
          "agents"
        ],
        "responses": {
          "200": {
            "description": "RSS XML"
          }
        }
      }
    },
    "/api/recently-verified.json": {
      "get": {
        "summary": "Recently-verified pros — rolling 30-day feed",
        "description": "Feed of pros whose verifiedAt timestamp falls within the last 30 days. Includes verification tier, permit-verified flag, and trust score. Useful for 'what's new' surfaces + partner freshness checks. CC-BY-4.0. 1h cache.",
        "tags": [
          "data"
        ],
        "responses": {
          "200": {
            "description": "Recently-verified pros JSON"
          }
        }
      }
    },
    "/api/trust-scores.json": {
      "get": {
        "summary": "ProFix Trust Score aggregate — every pro's composite 0-100 score + tier",
        "description": "Bulk feed of every pro's ProFix Trust Score (0-100) and tier (elite/solid/starter/minimal). Composite of verification tier, license status, rating × review count, photos/hours/specialties/tenure, permit-verified flag. Methodology at /methodology. Zero PII. CC-BY-4.0. 1h cache.",
        "tags": [
          "data"
        ],
        "responses": {
          "200": {
            "description": "Trust scores JSON"
          }
        }
      }
    },
    "/api/pro/{slug}.json": {
      "get": {
        "summary": "Per-pro JSON dossier",
        "description": "Canonical per-contractor dossier as JSON. Returns name, location, license + verification details, source URLs, permit count + verified status, ratings. Zero PII beyond what /pro/{slug} already shows publicly. CC-BY-4.0. 1h cache.",
        "tags": [
          "data"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Pro slug (see /api/jsonld/local-business-index for the canonical list)"
          }
        ],
        "responses": {
          "200": {
            "description": "Pro JSON dossier"
          },
          "404": {
            "description": "Pro not found"
          }
        }
      }
    },
    "/api/jsonld/{type}": {
      "get": {
        "summary": "Open JSON-LD feeds — full Schema.org graphs by type",
        "description": "First-class structured-data feeds for AI engines, partners, and structured-data tooling. Supported types: `pros` (LocalBusiness graph for every pro), `cost-guides` (Article graph), `faq` (combined FAQPage), `organization` (ProFix Directory entity), `local-business-index` (top-100 ItemList), `faq-trade-{trade}` (per-trade FAQPage), `breadcrumb-coverage` (BreadcrumbList for /coverage). No auth, 1h CDN cache + 1d stale-while-revalidate.",
        "tags": [
          "agents"
        ],
        "parameters": [
          {
            "name": "type",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "JSON-LD feed identifier (see description for valid values)"
          }
        ],
        "responses": {
          "200": {
            "description": "JSON-LD graph"
          },
          "404": {
            "description": "Unknown feed type"
          }
        }
      }
    },
    "/api/cities.json": {
      "get": {
        "summary": "All covered Ohio cities",
        "description": "Every Ohio city ProFix covers, with ZIP codes, county, metro, and population.",
        "tags": [
          "geo"
        ],
        "responses": {
          "200": {
            "description": "Cities JSON"
          }
        }
      }
    },
    "/api/city-taxonomy.json": {
      "get": {
        "summary": "City taxonomy",
        "tags": [
          "geo"
        ],
        "responses": {
          "200": {
            "description": "City taxonomy JSON"
          }
        }
      }
    },
    "/api/permits.json": {
      "get": {
        "summary": "Permit office directory (Toledo + Findlay metros)",
        "description": "Permit-issuing offices with phone, hours, and per-trade guidance. Currently scoped to Toledo + Findlay metros (other Ohio metros forthcoming).",
        "tags": [
          "data"
        ],
        "responses": {
          "200": {
            "description": "Permits JSON"
          }
        }
      }
    },
    "/api/cost-report.json": {
      "get": {
        "summary": "Cost guide aggregate (Toledo + Findlay 2026 research)",
        "description": "Aggregate Toledo + Findlay home-services cost benchmarks from the 2026 NW Ohio cost research — 60 cost benchmarks across 8 trades with median + range + Findlay-vs-Toledo variance. CC-BY-4.0. CSV mirror at /api/cost-report.csv.",
        "tags": [
          "data"
        ],
        "responses": {
          "200": {
            "description": "Cost report JSON"
          }
        }
      }
    },
    "/api/license-evidence.json": {
      "get": {
        "summary": "License evidence index",
        "description": "Per-pro license evidence: license number, source URL, last verified.",
        "tags": [
          "verification"
        ],
        "responses": {
          "200": {
            "description": "License evidence JSON"
          }
        }
      }
    },
    "/api/outage-status": {
      "get": {
        "summary": "Active utility outage status",
        "description": "Real-time-ish outage status for major Ohio utilities serving NW Ohio.",
        "tags": [
          "data"
        ],
        "responses": {
          "200": {
            "description": "Outage status JSON"
          }
        }
      }
    },
    "/api/pro-card/{slug}": {
      "get": {
        "summary": "Generated pro card SVG",
        "tags": [
          "assets"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "SVG image"
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "summary": "LLM content map (llmstxt.org spec)",
        "tags": [
          "agents"
        ],
        "responses": {
          "200": {
            "description": "Plain-text content map"
          }
        }
      }
    },
    "/llms-full.txt": {
      "get": {
        "summary": "Full LLM content dump",
        "tags": [
          "agents"
        ],
        "responses": {
          "200": {
            "description": "Plain-text full content map"
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "agents",
      "description": "Endpoints for AI agents (MCP, llms.txt, OpenAPI itself)"
    },
    {
      "name": "data",
      "description": "Live data feeds: permits, costs, outages"
    },
    {
      "name": "geo",
      "description": "Geographic + city taxonomy data"
    },
    {
      "name": "verification",
      "description": "Authoritative source cross-checks"
    },
    {
      "name": "assets",
      "description": "Generated media (SVG cards, OG images)"
    }
  ],
  "x-mcp-server-url": "https://profixdirectory.com/api/mcp",
  "x-data-sources-url": "https://profixdirectory.com/data-sources"
}