ProFix Editorial Team

ProFix Directory API documentation — 73 endpoints, 15 schemas, CC-BY-4.0

Partner-facing reference documentation for every public endpoint in the ProFix Directory OpenAPI 3.1 spec — grouped by tag (agents, data, geo, verification, assets), with parameters, example responses, and copy-paste curl / JavaScript / Python snippets for every endpoint. No API key. CC-BY-4.0.

No API keyOpenAPI 3.1.084 endpoints18 schemasCC-BY-4.0
TL;DR

Five things to know before you call the API

  • 84 public endpoints grouped under 5 tags — agents, data, geo, verification, assets.
  • No auth for reads. Every JSON / CSV / SVG / feed endpoint is open and CORS-enabled. The only authenticated surfaces are Stripe checkout (/api/checkout) and webhooks (/api/stripe-webhook).
  • OpenAPI 3.1 + MCP. Spec at /api/openapi.json and /api/openapi.yaml. Agent-native MCP server with 16+ tools at /api/mcp.
  • CC-BY-4.0. Attribute "ProFix Directory" and ship — commercial use welcomed.
  • 18 schemas defined in components.schemas — Pro, ProList, City, State, CostGuide, LicenseGuide, BuyerGuide, FAQ, SearchResponse, CorrectionSubmission, ErrorResponse, ProDossier, ProPhotos, MatchResponse, ProPermits.

API conventions

Authentication

Most endpoints are public. No API key, no OAuth flow. CORS is permissive (Access-Control-Allow-Origin: *). The Stripe checkout and webhook endpoints accept a Stripe-Signature header. Admin surfaces under /api/admin/* require the editor bearer token (set as the Authorization: Bearer header).

Rate limits

No published per-key throttle. Public reads are CDN-cached at the edge — repeat hits cost nothing on either side. The lead-submission, claim, and corrections POST endpoints carry a soft per-IP rate gate (~20 req/min) to deter abuse. Burst above that returns HTTP 429 with Retry-After. Bulk pulls of /api/all.json should cache locally for at least 1 hour.

Cache headers + ETags

Read endpoints set Cache-Control: public, max-age=3600, s-maxage=86400, stale-while-revalidate=604800. Next.js attaches a strong ETag derived from the rendered body — pass it back as If-None-Match on subsequent requests and we answer 304 Not Modified when the snapshot has not changed.

Response envelope

JSON responses share a standard envelope: { ok: true, license: "CC-BY-4.0", generated_at, ...payload }. Error responses are { ok: false, error, message } — see the ErrorResponse schema. CSV responses are RFC 4180 with a header row.

Agent-native discovery

  • MCP server at /api/mcp — streamable HTTP, 16+ typed tools: find_pros, get_pro, triage_symptom, get_cost_estimate, list_guides, get_active_storm_events, and more. The canonical transport for any agent that already speaks Model Context Protocol.
  • ai-plugin manifest at /.well-known/ai-plugin.json — ChatGPT plugin / Anthropic connector manifest pointing at this OpenAPI spec.
  • ai.txt + llms.txt at /.well-known/ai.txt and /llms.txt — plain-text agent-access policy + LLM content map.

Agents & discovery

MCP server, OpenAPI/YAML mirror, ai-plugin manifest, llms.txt, ai.txt — the surfaces an autonomous agent or AI engine reaches for first.

15 endpoints
get/.well-known/ai-plugin.json

ChatGPT plugin manifest

ChatGPT plugin / Anthropic connector manifest pointing at this OpenAPI spec. Schema version `v1`, auth `none`, API type `openapi`.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Plugin manifest JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/.well-known/ai-plugin.json"
javascript
const res = await fetch("https://profixdirectory.com/.well-known/ai-plugin.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/.well-known/ai-plugin.json", timeout=10)
res.raise_for_status()
print(res.json())
get/.well-known/ai.txt

AI agent access policy

Plain-text AI-agent access policy mirroring robots.txt — Spawning.ai ai.txt draft + llmstxt.org convention. Lists allowed agents, disallowed paths, and discovery pointers (llms.txt, MCP, OpenAPI, dataset).

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(ai.txt plain text)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/.well-known/ai.txt"
javascript
const res = await fetch("https://profixdirectory.com/.well-known/ai.txt");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/.well-known/ai.txt", timeout=10)
res.raise_for_status()
print(res.json())
get/api/all

Discovery index — every machine-readable surface in one document

Single-fetch agent-discovery payload aggregating the bulk dataset, every JSON/CSV/RSS/iCal feed (via /api/feeds-index.json), the canonical site graph, and every relevant content map. Useful for AI engines that want one URL to crawl. CC-BY-4.0, 1h cache, CORS-enabled.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Discovery index JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/all"
javascript
const res = await fetch("https://profixdirectory.com/api/all");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/all", timeout=10)
res.raise_for_status()
print(res.json())
get/api/changelog

Git-derived product changelog — paginated JSON (last 90 days)

Paginated, machine-readable feed of every user-facing change (feat/fix/perf) sourced from the live git log over a rolling 90-day window. 50 entries per page, ETag + Cache-Control, scope-aware url hints, and HEAD support. Personal git authors are dropped — every entry is published under the ProFix Editorial Team banner. Paginate with ?page=1..N. Companion HTML pages: /changelog (EN), /es/registro-cambios (ES). CC-BY-4.0.

Parameters

  • page (query)type: integer
    1-indexed page number. Defaults to 1.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Changelog JSON page)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/changelog"
javascript
const res = await fetch("https://profixdirectory.com/api/changelog");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/changelog", timeout=10)
res.raise_for_status()
print(res.json())
get/api/changelog.json

Newsroom changelog — machine-readable

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.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Changelog JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/changelog.json"
javascript
const res = await fetch("https://profixdirectory.com/api/changelog.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/changelog.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/emergency-playbook/{slug}.json

Emergency playbook JSON companion

Minimal JSON mirror of /emergency/playbooks/{slug}. Returns immediate steps, shutoff guidance, do-not list, who-to-call list, damage mitigation, typical cost band, insurance note, and prevention guidance. CC-BY-4.0. CORS-enabled, 1h cache.

Parameters

  • slug (path)requiredtype: string
    Emergency playbook slug, for example burst-pipe-inside.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Emergency playbook JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/emergency-playbook/miller-plumbing-toledo.json"
javascript
const res = await fetch("https://profixdirectory.com/api/emergency-playbook/miller-plumbing-toledo.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/emergency-playbook/miller-plumbing-toledo.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/jsonld/{type}

Open JSON-LD feeds — full Schema.org graphs by type

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.

Parameters

  • type (path)requiredtype: string
    JSON-LD feed identifier (see description for valid values)

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(JSON-LD graph)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/jsonld/organization"
javascript
const res = await fetch("https://profixdirectory.com/api/jsonld/organization");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/jsonld/organization", timeout=10)
res.raise_for_status()
print(res.json())
get/api/markdown-corpus

Paginated index of every Markdown-exportable route

JSON metadata listing every available `/api/markdown/{slug}` URL grouped by content type. Pages capped at 5000 entries via `?cursor=` (offset). Use `?type=<contentType>` to filter. Every entry is CC-BY-4.0 sourced from the ProFix Editorial Team.

Parameters

  • type (query)type: string
    Optional content type filter.
  • cursor (query)type: integer
    Zero-based offset for pagination.
  • limit (query)type: integer
    Page size. Hard-capped at 5000.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Paginated corpus index JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/markdown-corpus"
javascript
const res = await fetch("https://profixdirectory.com/api/markdown-corpus");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/markdown-corpus", timeout=10)
res.raise_for_status()
print(res.json())
get/api/markdown/{slug}

Markdown export of a single editorial route

Returns CC-BY-4.0 Markdown with YAML frontmatter for any (contentType, slug) pair covered by the corpus. Use `?type=<contentType>` to disambiguate when a slug exists across multiple types; otherwise the route auto-infers. Strong ETag + Cache-Control. Designed for AI training pipelines and content aggregators.

Parameters

  • slug (path)requiredtype: string
    The route slug (e.g. `plumber`, `furnace-tune-up-cost-toledo`).
  • type (query)type: string
    Content type. Optional — auto-inferred from slug when omitted.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Markdown text/plain with YAML frontmatter)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/markdown/miller-plumbing-toledo"
javascript
const res = await fetch("https://profixdirectory.com/api/markdown/miller-plumbing-toledo");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/markdown/miller-plumbing-toledo", timeout=10)
res.raise_for_status()
print(res.json())
get/api/mcp

Model Context Protocol server

Streamable HTTP MCP server exposing 46 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, get_trade_guide, get_trade_faq, list_emergency_playbooks, get_emergency_playbook, estimate_cost, list_research_articles, get_research_article, verify_contractor, and national state/pro/license matching tools. Use when your agent supports MCP; otherwise prefer the REST endpoints.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(MCP handshake)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/mcp"
javascript
const res = await fetch("https://profixdirectory.com/api/mcp");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/mcp", timeout=10)
res.raise_for_status()
print(res.json())
get/api/newsroom.rss

Newsroom RSS 2.0 feed

RSS feed combining changelog entries + published research articles. Subscribe in any RSS reader to track ProFix's product + editorial milestones. CC-BY-4.0.

Example response

json
# RSS XML
# Plain-text feed (RSS / Atom / iCal).

Code examples

curl
curl -sL "https://profixdirectory.com/api/newsroom.rss"
javascript
const res = await fetch("https://profixdirectory.com/api/newsroom.rss");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/newsroom.rss", timeout=10)
res.raise_for_status()
print(res.json())
get/api/trade-guide/{trade}.json

Trade encyclopedia JSON companion

Minimal JSON mirror of /trades/{trade}/guide. Returns the Wave 64 trade encyclopedia entry: troubleshooting, maintenance schedule, cost components, hiring red flags, contract checklist, and warranty norms. CC-BY-4.0. CORS-enabled, 1h cache.

Parameters

  • trade (path)requiredtype: string
    Canonical trade slug, for example plumber, hvac, electrician, roofing.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Trade guide JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/trade-guide/plumber.json"
javascript
const res = await fetch("https://profixdirectory.com/api/trade-guide/plumber.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/trade-guide/plumber.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/voice/{q}

Voice assistant single-question Q&A

GET endpoint for Alexa skills / Google Actions. Takes a URL-encoded natural-language question as a path segment and returns a 25-40 word voice-friendly answer in both English and Spanish, plus the canonical source URL and source type. Deterministic — no LLM call. Reuses the same search-query-expander + voice-answer collapse pipeline that powers /faq and /api/ask. Strong ETag; Cache-Control public max-age=3600, s-maxage=86400. No auth required.

Parameters

  • q (path)requiredtype: string
    URL-encoded natural-language question (e.g. `how%20much%20does%20a%20plumber%20cost`).

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Voice answer JSON.)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/voice/example"
javascript
const res = await fetch("https://profixdirectory.com/api/voice/example");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/voice/example", timeout=10)
res.raise_for_status()
print(res.json())
get/llms-full.txt

Full LLM content dump

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Plain-text full content map)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/llms-full.txt"
javascript
const res = await fetch("https://profixdirectory.com/llms-full.txt");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/llms-full.txt", timeout=10)
res.raise_for_status()
print(res.json())
get/llms.txt

LLM content map (llmstxt.org spec)

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Plain-text content map)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/llms.txt"
javascript
const res = await fetch("https://profixdirectory.com/llms.txt");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/llms.txt", timeout=10)
res.raise_for_status()
print(res.json())

Data feeds

Per-resource JSON / CSV feeds — pros, permits, leads, verification deltas, cost reports, glossary, search, autocomplete, and the deterministic /api/answer retriever.

64 endpoints
post/api/answer

Deterministic ProFix answer retrieval

Accepts a homeowner or agent question and returns top grounded matches from ProFix research, buyer guides, glossary, and cost guides. Pure deterministic text retrieval; no LLM call.

Example request body

json
{
  "question": "How do I find a licensed Toledo plumber with recent permit history?",
  "context": [
    "toledo",
    "plumbing"
  ]
}

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Grounded deterministic matches)"
}

Code examples

curl
curl -X POST "https://profixdirectory.com/api/answer" \
  -H 'Content-Type: application/json' \
  -d '{
  "question": "How do I find a licensed Toledo plumber with recent permit history?",
  "context": [
    "toledo",
    "plumbing"
  ]
}'
javascript
const res = await fetch("https://profixdirectory.com/api/answer", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "question": "How do I find a licensed Toledo plumber with recent permit history?",
    "context": [
      "toledo",
      "plumbing"
    ]
  }),
});
const data = await res.json();
console.log(data);
python
import requests

payload = {
  "question": "How do I find a licensed Toledo plumber with recent permit history?",
  "context": [
    "toledo",
    "plumbing"
  ]
}

res = requests.post("https://profixdirectory.com/api/answer", json=payload, timeout=10)
res.raise_for_status()
print(res.json())
get/api/ask

Natural-language Q&A endpoint

GET version of the answer engine. Accepts a single `q` parameter and returns a structured response with intent detection, a best_answer, related_answers, and related_routes pulled deterministically from FAQs, cost guides, license guides, glossary, buyer guides, and comparison guides. No LLM. Always returns 200 — when no match is found, intent is `unknown` and `match_status` is `no_answer`. Strong ETag; Cache-Control: public, max-age=3600.

Parameters

  • q (query)type: string
    Natural-language question (URL-encoded).

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Structured answer JSON.)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/ask"
javascript
const res = await fetch("https://profixdirectory.com/api/ask");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/ask", timeout=10)
res.raise_for_status()
print(res.json())
get/api/autocomplete

Lightweight typeahead

Typeahead-shaped variant of /api/search — same scoring, smaller payload, strong ETag, designed for header search bars and agent prefix queries.

Parameters

  • q (query)requiredtype: string
  • limit (query)type: integer

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Autocomplete suggestions JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/autocomplete"
javascript
const res = await fetch("https://profixdirectory.com/api/autocomplete");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/autocomplete", timeout=10)
res.raise_for_status()
print(res.json())
get/api/badge/{slug}.svg

Embeddable 'ProFix Verified' trust badge SVG

Per-contractor 240×80 SVG badge displaying current ProFix trust tier (Elite/Solid/Starter/Minimal), 0-100 composite Trust Score, and recent permit count when > 0. Pure inline SVG using system fonts — no external assets. Designed to be embedded with a single `<img>` tag on a contractor's own website, Slack channel, or email signature. CORS-enabled. CC-BY-4.0; keep the wordmark visible. Returns a 404 SVG fallback for unknown slugs. 1h CDN cache.

Parameters

  • slug (path)requiredtype: string
    Pro slug (see /api/jsonld/local-business-index for the canonical list)

Example response

json
<!-- SVG badge -->
<svg xmlns="http://www.w3.org/2000/svg" ...>...</svg>

Code examples

curl
curl -sL "https://profixdirectory.com/api/badge/miller-plumbing-toledo.svg"
javascript
const res = await fetch("https://profixdirectory.com/api/badge/miller-plumbing-toledo.svg");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/badge/miller-plumbing-toledo.svg", timeout=10)
res.raise_for_status()
print(res.json())
get/api/brand-assets.json

Brand assets feed — logo URLs, color palette, fonts, attribution

Programmatic feed of ProFix Directory brand assets — logo SVG + icon SVG URLs, the brand color palette (primary, accent, background, foreground, neutral), font stack, and short/long/HTML attribution strings. Designed for partner integrations (Slack apps, Discord embeds, Zapier templates, widget hosts) that want a branded card. CC-BY-4.0 for editorial use; brand marks remain ProFix Directory LLC trademarks. 1h cache, CORS-enabled.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Brand assets JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/brand-assets.json"
javascript
const res = await fetch("https://profixdirectory.com/api/brand-assets.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/brand-assets.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/buyers-guides.json

Buyer's guide index

Machine-readable index of every ProFix Directory buyer's guide — slug, title, summary, trade, last-reviewed date, and canonical URL. CC-BY-4.0, 1h cache, CORS-enabled.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Buyer's guides JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/buyers-guides.json"
javascript
const res = await fetch("https://profixdirectory.com/api/buyers-guides.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/buyers-guides.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/changelog.atom

Newsroom changelog — Atom 1.0 mirror of /api/newsroom.rss

Atom 1.0 feed of every public ProFix Directory changelog entry. Same data the RSS feed exposes, served in the Atom envelope for readers and AI engines that prefer Atom over RSS. CC-BY-4.0, 1h cache, CORS-enabled.

Example response

json
# Changelog Atom 1.0
# Plain-text feed (RSS / Atom / iCal).

Code examples

curl
curl -sL "https://profixdirectory.com/api/changelog.atom"
javascript
const res = await fetch("https://profixdirectory.com/api/changelog.atom");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/changelog.atom", timeout=10)
res.raise_for_status()
print(res.json())
get/api/changelog.csv

Newsroom changelog — CSV mirror of /api/changelog.json

RFC 4180 CSV mirror of /api/changelog.json. One row per CHANGELOG entry. Columns: `date,type,headline,slug,url`. Use when you want to drop the changelog into Excel/Sheets/pandas. CC-BY-4.0, 1h cache, CORS-enabled.

Example response

json
# CSV response — RFC 4180. First row is the header.
# Changelog CSV
slug,name,city,county,state,phone,verification_tier
miller-plumbing-toledo,Miller Plumbing,Toledo,Lucas,OH,419-555-0144,license-linked

Code examples

curl
curl -sL "https://profixdirectory.com/api/changelog.csv"
javascript
const res = await fetch("https://profixdirectory.com/api/changelog.csv");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/changelog.csv", timeout=10)
res.raise_for_status()
print(res.json())
get/api/changelog.ics

Newsroom changelog — iCal (RFC 5545) calendar feed

iCal subscription of every ProFix Directory changelog milestone as an all-day VEVENT. Subscribe in Apple Calendar, Google Calendar, or Outlook via webcal://profixdirectory.com/api/changelog.ics. Each event carries SUMMARY, DESCRIPTION, URL, CATEGORIES, and a stable UID. CC-BY-4.0, 1h cache, CORS-enabled.

Example response

json
# iCal calendar
# Plain-text feed (RSS / Atom / iCal).

Code examples

curl
curl -sL "https://profixdirectory.com/api/changelog.ics"
javascript
const res = await fetch("https://profixdirectory.com/api/changelog.ics");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/changelog.ics", timeout=10)
res.raise_for_status()
print(res.json())
get/api/compare

Side-by-side contractor comparison

Normalized side-by-side comparison feed for up to three ProFix contractors. Pass `?pros=slug1,slug2,slug3` (comma-separated, ≤3 slugs). Returns each pro's Trust Score + tier, permit count over the last 12 months, license status + license number, rating + review count, insurance-verified flag, tenure, specialties, service area, photo count, featured flag, Spanish-speaking flag, profile URL, evidence-page URL, and last-verified date. Unknown slugs are silently dropped; `requested_slugs` echoes what was asked for. Same JSON shape powers the interactive /compare page. CC-BY-4.0, CORS-enabled, 1h cache.

Parameters

  • pros (query)requiredtype: string
    Comma-separated pro slugs (e.g. `miller-plumbing-toledo,atlas-butler-heating-cooling-columbus`). At most 3 slugs; returns 400 otherwise.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Comparison JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/compare"
javascript
const res = await fetch("https://profixdirectory.com/api/compare");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/compare", timeout=10)
res.raise_for_status()
print(res.json())
get/api/contractors/by-county/{county}.csv

Bulk contractor feed — CSV mirror of /api/contractors/by-county/{county}.json

RFC 4180 CSV mirror of the per-county contractor JSON feed. Same row set, byte-different envelope for spreadsheet + pandas workflows. CC-BY-4.0.

Parameters

  • county (path)requiredtype: string
    One of the 88 ProFix Ohio county slugs

Example response

json
# CSV response — RFC 4180. First row is the header.
# Contractor CSV
slug,name,city,county,state,phone,verification_tier
miller-plumbing-toledo,Miller Plumbing,Toledo,Lucas,OH,419-555-0144,license-linked

Code examples

curl
curl -sL "https://profixdirectory.com/api/contractors/by-county/lucas.csv"
javascript
const res = await fetch("https://profixdirectory.com/api/contractors/by-county/lucas.csv");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/contractors/by-county/lucas.csv", timeout=10)
res.raise_for_status()
print(res.json())
get/api/contractors/by-county/{county}.json

Bulk contractor feed for a single Ohio county

All public ProFix contractors who serve the given county. Pre-rendered for all 88 Ohio county slugs. Each row carries slug, name, trade + trades[], city, county, phone, rating + review_count, trust_score + trust_tier, permit_count_12mo, license_status + license_number, url, and evidence_url. CC-BY-4.0, 1h cache, CORS-enabled.

Parameters

  • county (path)requiredtype: string
    One of the 88 ProFix Ohio county slugs (lucas, cuyahoga, franklin, hamilton, …)

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Contractor feed JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/contractors/by-county/lucas.json"
javascript
const res = await fetch("https://profixdirectory.com/api/contractors/by-county/lucas.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/contractors/by-county/lucas.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/contractors/by-trade/{trade}.csv

Bulk contractor feed — CSV mirror of /api/contractors/by-trade/{trade}.json

RFC 4180 CSV mirror of the per-trade contractor JSON feed. Same row set, byte-different envelope for spreadsheet + pandas workflows. CC-BY-4.0.

Parameters

  • trade (path)requiredtype: string
    One of the 37 ProFix trade slugs

Example response

json
# CSV response — RFC 4180. First row is the header.
# Contractor CSV
slug,name,city,county,state,phone,verification_tier
miller-plumbing-toledo,Miller Plumbing,Toledo,Lucas,OH,419-555-0144,license-linked

Code examples

curl
curl -sL "https://profixdirectory.com/api/contractors/by-trade/plumber.csv"
javascript
const res = await fetch("https://profixdirectory.com/api/contractors/by-trade/plumber.csv");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/contractors/by-trade/plumber.csv", timeout=10)
res.raise_for_status()
print(res.json())
get/api/contractors/by-trade/{trade}.json

Bulk contractor feed for a single trade (statewide)

All public ProFix contractors whose declared trade list includes the given slug, statewide. Pre-rendered for all 37 ProFix trade slugs. Same row shape as /api/contractors/by-county/{county}.json. CC-BY-4.0, 1h cache, CORS-enabled.

Parameters

  • trade (path)requiredtype: string
    One of the 37 ProFix trade slugs (plumber, hvac, electrician, appliance-repair, gas-tech, concrete, roofing, tree-service, restoration, lead-abatement, fire-protection, water-well, septic-system, tech-repair, pest-control, landscaping, painting, foundation-repair, garage-door, deck-builder, patio-installer, pool-installer, fence-contractor, shed-builder, siding-contractor, window-door-installer, gutter-installer, pressure-washing, lawn-care, sealcoat, outdoor-lighting, solar-installer, ev-charger-installer, heat-pump-installer, insulation-contractor, general-contractor, handyman)

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Contractor feed JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/contractors/by-trade/plumber.json"
javascript
const res = await fetch("https://profixdirectory.com/api/contractors/by-trade/plumber.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/contractors/by-trade/plumber.json", timeout=10)
res.raise_for_status()
print(res.json())
post/api/corrections

Submit a correction to the editorial team

Public corrections submission endpoint. Accepts JSON or form-encoded payloads with `pro_slug` (optional), `field`, `correction`, and `evidence_url`. Returns 200 with a thank-you acknowledgement. No PII required.

Example request body

json
{
  "pro_slug": "miller-plumbing-toledo",
  "field": "phone",
  "correction": "Updated business phone after voicemail verification.",
  "evidence_url": "https://example.com/voicemail-screenshot.png",
  "contact_email": "tipster@example.com"
}

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Acknowledged)"
}

Code examples

curl
curl -X POST "https://profixdirectory.com/api/corrections" \
  -H 'Content-Type: application/json' \
  -d '{
  "pro_slug": "miller-plumbing-toledo",
  "field": "phone",
  "correction": "Updated business phone after voicemail verification.",
  "evidence_url": "https://example.com/voicemail-screenshot.png",
  "contact_email": "tipster@example.com"
}'
javascript
const res = await fetch("https://profixdirectory.com/api/corrections", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "pro_slug": "miller-plumbing-toledo",
    "field": "phone",
    "correction": "Updated business phone after voicemail verification.",
    "evidence_url": "https://example.com/voicemail-screenshot.png",
    "contact_email": "tipster@example.com"
  }),
});
const data = await res.json();
console.log(data);
python
import requests

payload = {
  "pro_slug": "miller-plumbing-toledo",
  "field": "phone",
  "correction": "Updated business phone after voicemail verification.",
  "evidence_url": "https://example.com/voicemail-screenshot.png",
  "contact_email": "tipster@example.com"
}

res = requests.post("https://profixdirectory.com/api/corrections", json=payload, timeout=10)
res.raise_for_status()
print(res.json())
get/api/cost-report.csv

Cost guide aggregate — CSV companion to /api/cost-report.json

RFC 4180 CSV mirror of the cost report JSON. One row per benchmark. CC-BY-4.0.

Example response

json
# CSV response — RFC 4180. First row is the header.
# Cost report CSV
slug,name,city,county,state,phone,verification_tier
miller-plumbing-toledo,Miller Plumbing,Toledo,Lucas,OH,419-555-0144,license-linked

Code examples

curl
curl -sL "https://profixdirectory.com/api/cost-report.csv"
javascript
const res = await fetch("https://profixdirectory.com/api/cost-report.csv");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/cost-report.csv", timeout=10)
res.raise_for_status()
print(res.json())
get/api/cost-report.json

Cost guide aggregate (Toledo + Findlay 2026 research)

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.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Cost report JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/cost-report.json"
javascript
const res = await fetch("https://profixdirectory.com/api/cost-report.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/cost-report.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/coverage-stats.csv

Coverage snapshot — CSV companion to /api/coverage-stats.json

RFC 4180 CSV with one row per Ohio county (slug, name, region, pro_count). CC-BY-4.0.

Example response

json
# CSV response — RFC 4180. First row is the header.
# Coverage stats CSV
slug,name,city,county,state,phone,verification_tier
miller-plumbing-toledo,Miller Plumbing,Toledo,Lucas,OH,419-555-0144,license-linked

Code examples

curl
curl -sL "https://profixdirectory.com/api/coverage-stats.csv"
javascript
const res = await fetch("https://profixdirectory.com/api/coverage-stats.csv");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/coverage-stats.csv", timeout=10)
res.raise_for_status()
print(res.json())
get/api/coverage-stats.json

Coverage snapshot — pro counts by county / region / trade

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.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Coverage stats JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/coverage-stats.json"
javascript
const res = await fetch("https://profixdirectory.com/api/coverage-stats.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/coverage-stats.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/data-studies/{slug}.csv

Data study — CSV download

RFC 4180-style CSV companion for a generated ProFix data-study route at /data-studies/{slug}. Uses rowGroup to distinguish primary and secondary row sets. CC-BY-4.0, CORS-enabled.

Parameters

  • slug (path)requiredtype: string
    Data-study slug, for example contractor-density-by-state-2026.

Example response

json
# CSV response — RFC 4180. First row is the header.
# Data-study CSV payload
slug,name,city,county,state,phone,verification_tier
miller-plumbing-toledo,Miller Plumbing,Toledo,Lucas,OH,419-555-0144,license-linked

Code examples

curl
curl -sL "https://profixdirectory.com/api/data-studies/miller-plumbing-toledo.csv"
javascript
const res = await fetch("https://profixdirectory.com/api/data-studies/miller-plumbing-toledo.csv");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/data-studies/miller-plumbing-toledo.csv", timeout=10)
res.raise_for_status()
print(res.json())
get/api/data-studies/{slug}.json

Data study — JSON companion

Machine-readable JSON companion for a generated ProFix data-study route at /data-studies/{slug}. Includes methodology, limitations, source files, primary rows, download URLs, and CC-BY-4.0 attribution.

Parameters

  • slug (path)requiredtype: string
    Data-study slug, for example contractor-density-by-state-2026.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Data-study JSON payload)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/data-studies/miller-plumbing-toledo.json"
javascript
const res = await fetch("https://profixdirectory.com/api/data-studies/miller-plumbing-toledo.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/data-studies/miller-plumbing-toledo.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/embed/{slug}.json

Partner embed feed — top 5 pros for a trade × city pair

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.

Parameters

  • slug (path)requiredtype: string
    Slug format `{trade}-{city}` (e.g. plumber-toledo)

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Embed JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/embed/miller-plumbing-toledo.json"
javascript
const res = await fetch("https://profixdirectory.com/api/embed/miller-plumbing-toledo.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/embed/miller-plumbing-toledo.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/feeds-index.json

Feeds index — catalog of every JSON/CSV/RSS/iCal feed with metadata

Catalog of every public ProFix Directory feed (JSON, CSV, RSS, iCal). Each entry carries `path`, absolute `url`, `format`, `category`, `description`, `license`, `refresh_cadence` (live / hourly / daily / weekly / monthly / static), `cors`, and an optional `openapi_id` cross-reference. Enumerated from the same `PUBLIC_API_FEED_PATHS` list that powers /sitemap.xml — a single fetch tells an agent every machine-readable surface ProFix exposes. CC-BY-4.0, 1h cache, CORS-enabled.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Feeds index JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/feeds-index.json"
javascript
const res = await fetch("https://profixdirectory.com/api/feeds-index.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/feeds-index.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/glossary.json

Bilingual glossary — EN + ES home-services terminology

Programmatic feed of every glossary term in the ProFix bilingual reference: trade jargon, licensing (OCILB, EPA 608), permits, manufacturer certifications, legal terms, and pricing concepts. Each entry has term, slug, English + Spanish definitions, category, and optional related-term cross-refs. CC-BY-4.0. 1h cache. CORS-enabled.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Glossary JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/glossary.json"
javascript
const res = await fetch("https://profixdirectory.com/api/glossary.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/glossary.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/graph/coverage.jsonld

Ohio coverage Schema.org graph

Connected JSON-LD graph for Ohio, covered metros, counties, cities, ProFix Directory as LocalBusiness, and one Service node per trade. Built for Google Dataset Search and AI knowledge graph ingestion.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Coverage JSON-LD)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/graph/coverage.jsonld"
javascript
const res = await fetch("https://profixdirectory.com/api/graph/coverage.jsonld");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/graph/coverage.jsonld", timeout=10)
res.raise_for_status()
print(res.json())
get/api/health

Liveness + dependency probe

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.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Service healthy)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/health"
javascript
const res = await fetch("https://profixdirectory.com/api/health");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/health", timeout=10)
res.raise_for_status()
print(res.json())
get/api/jsonld/dataset

Dataset JSON-LD — Google Dataset Search registration document

Top-level Schema.org Dataset document describing the 21,898-record ProFix Ohio Home-Services Pros dataset. Names creator + publisher (ProFix Directory / ProFix Directory LLC), declares CC-BY-4.0 license, lists three DataDownload distributions (JSON, CSV, Hugging Face), Ohio spatialCoverage as a GeoShape, 2026/.. temporalCoverage, and five variableMeasured PropertyValue entries (license status, permit count, verification tier, trust score, review aggregate). Designed for Google Dataset Search registration + academic-search tooling that crawl JSON-LD Dataset shapes. Daily revalidate. CORS open.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Dataset JSON-LD)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/jsonld/dataset"
javascript
const res = await fetch("https://profixdirectory.com/api/jsonld/dataset");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/jsonld/dataset", timeout=10)
res.raise_for_status()
print(res.json())
get/api/lead-feed.csv

Lead feed — CSV companion to /api/lead-feed.json

Long-format CSV (window_days, bucket, key, value) for lead aggregate metrics — pivot-friendly. Zero PII. CC-BY-4.0.

Example response

json
# CSV response — RFC 4180. First row is the header.
# Lead feed CSV
slug,name,city,county,state,phone,verification_tier
miller-plumbing-toledo,Miller Plumbing,Toledo,Lucas,OH,419-555-0144,license-linked

Code examples

curl
curl -sL "https://profixdirectory.com/api/lead-feed.csv"
javascript
const res = await fetch("https://profixdirectory.com/api/lead-feed.csv");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/lead-feed.csv", timeout=10)
res.raise_for_status()
print(res.json())
get/api/lead-feed.json

Lead volume + quality-tier aggregate feed

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.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Lead feed JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/lead-feed.json"
javascript
const res = await fetch("https://profixdirectory.com/api/lead-feed.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/lead-feed.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/license-revocations.json

Anonymized license-status change patterns

Programmatic feed behind /license-watch. Returns anonymized contractor license, registration, and credential status-change patterns across ProFix trades: id, trade, status_change, pattern, reason_category, date_of_change, county, and homeowner_action. No business names, personal names, license numbers, addresses, or docket numbers. CC-BY-4.0 editorial assembly, 1h cache, CORS-enabled.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(License revocations and suspensions JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/license-revocations.json"
javascript
const res = await fetch("https://profixdirectory.com/api/license-revocations.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/license-revocations.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/match/{trade}/{state}

Agent-native ranked pro matching for (trade, state)

Returns up to 50 gold-tier contractors (combined `national_gold` + `regional_gold` — national gold = confidence ≥ 80 with multi-source aggregation; regional gold = single-source + license + phone-state exact match) for a (trade, state) query, sorted by confidence descending. Same per-pro dossier shape as /api/pro/{slug} — no PII beyond what's on the public profile. Validates trade against TRADES and state against SUPPORTED_STATES (case-insensitive). 400 on invalid input. 404 when the state isn't supportedByDirectory OR the (trade, state) pool has fewer than 3 pros. Optional filters: `?limit=` (default 10, max 50), `?city=` (case-insensitive), `?emergency=true` (24/7 pros only). Strong ETag covers the full filter set + a pool snapshot hash so deploys that refresh the seed bust the cache. 1h browser / 24h CDN / 7d SWR. CORS-enabled. CC-BY-4.0.

Parameters

  • trade (path)requiredtype: string
    Trade slug (e.g. 'plumber', 'hvac', 'electrician'). See TRADES.
  • state (path)requiredtype: string
    Two-letter postal code (e.g. 'OH'). Case-insensitive.
  • limit (query)type: integer
    Max number of pros to return (1-50, default 10).
  • city (query)type: string
    Filter to a single city (case-insensitive).
  • emergency (query)type: boolean
    When true, only return pros flagged emergency24h.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Ranked match payload)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/match/plumber/OH"
javascript
const res = await fetch("https://profixdirectory.com/api/match/plumber/OH");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/match/plumber/OH", timeout=10)
res.raise_for_status()
print(res.json())
get/api/metrics.json

Directory growth metrics — totals, per-trade, per-metro

Machine-readable mirror of /metrics. Build-time aggregate of total contractors, license-linked share, permit pulls in the last 12 months, trades / counties / cities covered, research articles, buyer's guides, glossary terms, public API endpoints, data sources, plus per-trade and per-metro rows. CC-BY-4.0, CORS-enabled, 1h cache.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Metrics JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/metrics.json"
javascript
const res = await fetch("https://profixdirectory.com/api/metrics.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/metrics.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/openapi.yaml

OpenAPI 3.1 spec — YAML mirror of /api/openapi.json

YAML serialization of the canonical OpenAPI 3.1 document at /api/openapi.json. Same spec object, byte-different envelope — for partners and AI tooling that prefer YAML over JSON. CC-BY-4.0, 24h cache, CORS-enabled.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(OpenAPI 3.1 YAML)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/openapi.yaml"
javascript
const res = await fetch("https://profixdirectory.com/api/openapi.yaml");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/openapi.yaml", timeout=10)
res.raise_for_status()
print(res.json())
get/api/outage-status

Active utility outage status

Real-time-ish outage status for major Ohio utilities serving NW Ohio.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Outage status JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/outage-status"
javascript
const res = await fetch("https://profixdirectory.com/api/outage-status");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/outage-status", timeout=10)
res.raise_for_status()
print(res.json())
get/api/permit-leaderboard.csv

Permit-pull leaderboard — CSV companion to /api/permit-leaderboard.json

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.

Parameters

  • trade (query)type: string
  • county (query)type: string
  • window (query)type: integer
  • top (query)type: integer

Example response

json
# CSV response — RFC 4180. First row is the header.
# Permit leaderboard CSV
slug,name,city,county,state,phone,verification_tier
miller-plumbing-toledo,Miller Plumbing,Toledo,Lucas,OH,419-555-0144,license-linked

Code examples

curl
curl -sL "https://profixdirectory.com/api/permit-leaderboard.csv"
javascript
const res = await fetch("https://profixdirectory.com/api/permit-leaderboard.csv");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/permit-leaderboard.csv", timeout=10)
res.raise_for_status()
print(res.json())
get/api/permit-leaderboard.json

Permit-pull leaderboard — pro rankings by verified building permits

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.

Parameters

  • trade (query)type: string
    Filter to a single trade slug (plumber, hvac, etc.)
  • county (query)type: string
    Filter to a single county slug, or `ohio` for statewide aggregates
  • window (query)type: integer
    Days back to count permits (max 1095)
  • top (query)type: integer
    Top N entries per leaderboard (max 100)

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Permit leaderboard JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/permit-leaderboard.json"
javascript
const res = await fetch("https://profixdirectory.com/api/permit-leaderboard.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/permit-leaderboard.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/permits.json

Permit office directory (Toledo + Findlay metros)

Permit-issuing offices with phone, hours, and per-trade guidance. Currently scoped to Toledo + Findlay metros (other Ohio metros forthcoming).

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Permits JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/permits.json"
javascript
const res = await fetch("https://profixdirectory.com/api/permits.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/permits.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/permits/by-county/{county}.json

Rolling 365-day permit feed for a single Ohio county

Public building permits over the last 365 days attributed to contractors who serve the given Ohio county. Pre-rendered for all 88 county slugs. Each row carries permit_id, issued_date, contractor_slug, address, trade, value_usd, url. CC-BY-4.0, 1h cache, CORS-enabled.

Parameters

  • county (path)requiredtype: string
    One of the 88 ProFix Ohio county slugs

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Permit feed JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/permits/by-county/lucas.json"
javascript
const res = await fetch("https://profixdirectory.com/api/permits/by-county/lucas.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/permits/by-county/lucas.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/permits/by-trade/{trade}.json

Rolling 365-day permit feed for a single trade (statewide)

Public building permits over the last 365 days attributed to contractors whose declared trade list includes the given slug, statewide. Pre-rendered for all 37 trade slugs. Same row shape as /api/permits/by-county/{county}.json. CC-BY-4.0, 1h cache, CORS-enabled.

Parameters

  • trade (path)requiredtype: string
    One of the 37 ProFix trade slugs

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Permit feed JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/permits/by-trade/plumber.json"
javascript
const res = await fetch("https://profixdirectory.com/api/permits/by-trade/plumber.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/permits/by-trade/plumber.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/pro/{slug}

Structured per-pro dossier (gold-tier, national)

Structured JSON mirror of /state/{state}/pro/{slug} for every gold-tier contractor in the ProFix Directory. Gold-tier is the combined `national_gold` + `regional_gold` set: national gold is confidence >= 80 with multi-source aggregation; regional gold is single-source + license + phone-state exact match (single-source `verified` listings are not exposed here). Returns identity, trades, verification tier, license evidence + verify URL, evidence (confidence score + corroborating source count + program badges), photo manifest entry, permit footprint, and outbound source URLs. Phone is included and tagged as `phone_verification: "directory-verified" | "self-attested"`. No PII beyond what's on the public profile. Strong ETag + 1h browser / 24h CDN / 7d SWR cache. CORS-enabled. CC-BY-4.0.

Parameters

  • slug (path)requiredtype: string
    Gold-tier pro slug

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Pro JSON dossier)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/pro/miller-plumbing-toledo"
javascript
const res = await fetch("https://profixdirectory.com/api/pro/miller-plumbing-toledo");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/pro/miller-plumbing-toledo", timeout=10)
res.raise_for_status()
print(res.json())
get/api/pro/{slug}.json

Per-pro JSON dossier

Canonical per-contractor dossier as JSON. Returns name, location, license + verification details, source URLs, permit count + verified status, the read-only Google Places rating (source: google_places), and a first-party `reviews` block — count, mean, star histogram, and up to 5 recent snippets from APPROVED ProFix-moderated homeowner reviews (source: first_party_moderated). Zero PII beyond what /pro/{slug} already shows publicly. CC-BY-4.0. 1h cache.

Parameters

  • slug (path)requiredtype: string
    Pro slug (see /api/jsonld/local-business-index for the canonical list)

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Pro JSON dossier)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/pro/miller-plumbing-toledo.json"
javascript
const res = await fetch("https://profixdirectory.com/api/pro/miller-plumbing-toledo.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/pro/miller-plumbing-toledo.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/pro/{slug}/permits

Per-pro permit-pull history (rolling 365d)

Targeted child endpoint of /api/pro/{slug}: returns the permit-pull history for the given gold-tier pro. Each row carries issued_date, permit_type, jurisdiction, address, job_value_usd, source_url, and synthetic flag. Includes a summary block with `count_total`, `count_12mo`, and `permit_verified`. Strong ETag + 1h/24h/7d cache. CORS-enabled. CC-BY-4.0.

Parameters

  • slug (path)requiredtype: string
    Gold-tier pro slug

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Permit feed)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/pro/miller-plumbing-toledo/permits"
javascript
const res = await fetch("https://profixdirectory.com/api/pro/miller-plumbing-toledo/permits");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/pro/miller-plumbing-toledo/permits", timeout=10)
res.raise_for_status()
print(res.json())
get/api/pro/{slug}/photos

Per-pro photo manifest entry

Targeted child endpoint of /api/pro/{slug}: returns just the photo manifest entry for the given gold-tier pro (`photo_url`, `thumb_url`, `alt`, `source_type`, `trusted`). Returns `photo: null` (200) when the manifest has no entry. Strong ETag + 1h/24h/7d cache. CORS-enabled. CC-BY-4.0.

Parameters

  • slug (path)requiredtype: string
    Gold-tier pro slug

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Photo manifest entry)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/pro/miller-plumbing-toledo/photos"
javascript
const res = await fetch("https://profixdirectory.com/api/pro/miller-plumbing-toledo/photos");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/pro/miller-plumbing-toledo/photos", timeout=10)
res.raise_for_status()
print(res.json())
get/api/prompts.json

ProFix Prompt Library — copy-paste prompts for AI engines

Machine-readable mirror of the /prompts library. Returns 23 ready-to-ship prompts for ChatGPT, Claude, Perplexity, and Gemini that ground their answers in public ProFix endpoints. Each entry includes id, category (homeowner / developer / press), title, description, the literal prompt text, referenced endpoints, tags, and an anchor URL into /prompts. CC-BY-4.0. 1h cache, CORS-enabled.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Prompt library JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/prompts.json"
javascript
const res = await fetch("https://profixdirectory.com/api/prompts.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/prompts.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/pros.csv

Bulk dataset — every public pro as CSV

RFC 4180 CSV mirror of /api/pros.json. One row per published contractor. Use when you want to drop the dataset into Excel, Sheets, or pandas. CC-BY-4.0.

Example response

json
# CSV response — RFC 4180. First row is the header.
# Pros dataset CSV
slug,name,city,county,state,phone,verification_tier
miller-plumbing-toledo,Miller Plumbing,Toledo,Lucas,OH,419-555-0144,license-linked

Code examples

curl
curl -sL "https://profixdirectory.com/api/pros.csv"
javascript
const res = await fetch("https://profixdirectory.com/api/pros.csv");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/pros.csv", timeout=10)
res.raise_for_status()
print(res.json())
get/api/pros.json

Bulk dataset — every public pro as JSON

Full ProFix Directory pro dataset as one JSON document. One entry per published contractor with the public-surface columns (slug, name, address, phone, trades, license, rating, verification, trust). Mirror of the Hugging Face dataset `Pisces89/ohio-home-services-pros`. CC-BY-4.0, 1h cache, CORS-enabled.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Pros dataset JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/pros.json"
javascript
const res = await fetch("https://profixdirectory.com/api/pros.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/pros.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/quality-stats.json

Lead-quality score histogram + median per trade

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.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Quality stats JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/quality-stats.json"
javascript
const res = await fetch("https://profixdirectory.com/api/quality-stats.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/quality-stats.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/recently-verified.json

Recently-verified pros — rolling 30-day feed

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.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Recently-verified pros JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/recently-verified.json"
javascript
const res = await fetch("https://profixdirectory.com/api/recently-verified.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/recently-verified.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/reports/permits-this-month.json

Monthly recap — last 30 days of Ohio contractor permit activity

Machine-readable mirror of /reports/permits-this-month. Rolling 30-day window over the real matched permit-by-pro dataset (5,004 public permits joined to 554 contractors across 22 county jurisdictions; in Ohio: Cuyahoga, Franklin, Hamilton). Returns generated_at, license, window (start/end/days), top_pros (top 25 by permit count), by_trade (top 3 per trade), by_county (top 3 per county). Real public-record permits only. CC-BY-4.0. Daily refresh.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Permits-this-month recap JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/reports/permits-this-month.json"
javascript
const res = await fetch("https://profixdirectory.com/api/reports/permits-this-month.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/reports/permits-this-month.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/reports/this-week.json

Weekly recap — last 7 days of newsroom changelog + research publications

Machine-readable mirror of /reports/this-week. Rolling 7-day window over the public CHANGELOG and RESEARCH_ARTICLES datasets. Returns generated_at, license, window (start/end/days), changelog_entries (date/type/headline/url), research_published (slug/title/url/publishedAt), and counts. Honest about empty windows. CC-BY-4.0. Daily refresh.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(This-week recap JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/reports/this-week.json"
javascript
const res = await fetch("https://profixdirectory.com/api/reports/this-week.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/reports/this-week.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/research-publications.ics

Research publications — iCal (RFC 5545) calendar feed

iCal subscription of every ProFix Directory research-article publication date as an all-day VEVENT. Subscribe in Apple Calendar, Google Calendar, or Outlook via webcal://profixdirectory.com/api/research-publications.ics. Each event links to the canonical /research/<slug> URL. CC-BY-4.0, 1h cache, CORS-enabled.

Example response

json
# iCal calendar
# Plain-text feed (RSS / Atom / iCal).

Code examples

curl
curl -sL "https://profixdirectory.com/api/research-publications.ics"
javascript
const res = await fetch("https://profixdirectory.com/api/research-publications.ics");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/research-publications.ics", timeout=10)
res.raise_for_status()
print(res.json())
get/api/research.csv

Research articles — CSV mirror of /api/research.json

RFC 4180 CSV mirror of /api/research.json. One row per published research article. Columns: `slug,publishedAt,wordCount,title,summary,keywords,url` where `keywords` is `;`-joined since CSV cannot nest arrays. CC-BY-4.0, 1h cache, CORS-enabled.

Example response

json
# CSV response — RFC 4180. First row is the header.
# Research CSV
slug,name,city,county,state,phone,verification_tier
miller-plumbing-toledo,Miller Plumbing,Toledo,Lucas,OH,419-555-0144,license-linked

Code examples

curl
curl -sL "https://profixdirectory.com/api/research.csv"
javascript
const res = await fetch("https://profixdirectory.com/api/research.csv");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/research.csv", timeout=10)
res.raise_for_status()
print(res.json())
get/api/research.json

Research articles — JSON index

Machine-readable index of authored ProFix Directory research articles. Returns slug, title, publishedAt, wordCount, summary, keywords, and canonical URL for each /research/{slug} article. Generated data-study Markdown entries are exposed through /api/markdown-corpus?type=research when the data-studies seed exists. CC-BY-4.0, 1h cache, CORS-enabled.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Research article JSON index)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/research.json"
javascript
const res = await fetch("https://profixdirectory.com/api/research.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/research.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/reviews/aggregates.json

First-party review aggregates — every reviewed pro

Corpus-wide aggregates of APPROVED, ProFix-moderated homeowner reviews: one row per pro with count, mean rating, star histogram, and newest-review timestamp, plus a corpus summary (rated_pros, total_reviews, volume-weighted corpus_average). Aggregate-only, zero PII. DISTINCT from the read-only Google Places rating the directory surfaces — those are never re-emitted as ProFix aggregates. Per-pro recent review snippets live on /api/pro/{slug}.json. 1h cache, CORS-open, CC-BY-4.0.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(First-party review aggregates JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/reviews/aggregates.json"
javascript
const res = await fetch("https://profixdirectory.com/api/reviews/aggregates.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/reviews/aggregates.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/site-graph.json

Site graph — major sections with their pages + data endpoints

High-level link graph of ProFix Directory grouped into 10 sections (trust, permits, research, buyer's guides, trades, metros, agent-native, transparency, Spanish, tools). Each section bundles canonical HTML hub URLs with their machine-readable data endpoints, plus a top-level `agent_discovery` block pointing at llms.txt, llms-full.txt, OpenAPI, MCP, and the sitemap index. Designed for AI engines and partners that want to understand the site structure without crawling 20K+ pages. CC-BY-4.0, 1h cache, CORS-enabled.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Site graph JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/site-graph.json"
javascript
const res = await fetch("https://profixdirectory.com/api/site-graph.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/site-graph.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/sources.json

Data source registry — provenance index for every external source ProFix uses

Programmatic mirror of /sources. Returns the canonical registry of every external data source ProFix Directory uses to assemble its Ohio home-services contractor directory — licensing (Ohio eLicense, OCILB, ODH, SFM), permits (Lucas, Cuyahoga, Franklin, Hamilton county portals), reviews (Google Business Profiles, BBB), profiles (Google Places API), cost guides (primary research, U.S. BLS), local content (NOAA storm events, county building departments, ARPA lead-line programs), and open data (U.S. Census Geocoder, ACS). Each entry includes id, category, URL, license, optional license URL, refresh cadence, fields used, an explicit 'what we don't pull' list, and a stable /sources anchor. CC-BY-4.0 editorial assembly; underlying sources retain their own licenses. 1h cache, CORS-enabled.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Sources registry JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/sources.json"
javascript
const res = await fetch("https://profixdirectory.com/api/sources.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/sources.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/storm-events.json

Ohio storm events historical feed

Programmatic feed of ProFix's illustrative Ohio storm-event registry for 2020-2026. Returns date, type, severity, affected metros/counties, description, NOAA/NWS source URL, and canonical /storm-history/{slug} URL for each event. Editorial assembly is CC-BY-4.0; NOAA/NWS records retain public-domain source status. 1h cache, CORS-enabled.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Storm events JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/storm-events.json"
javascript
const res = await fetch("https://profixdirectory.com/api/storm-events.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/storm-events.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/trades.json

Trade taxonomy — 37 canonical home-services trades

Public registry of the 37 canonical trades ProFix Directory tracks. Per trade: slug, English + Spanish label, federal NAICS codes that crosswalk to it, CSLB classes (California), the 2-letter state codes where at least one gold-tier pro offers the trade, and the national pro count. Strong ETag. CC-BY-4.0. 1h browser / 24h CDN / 7d SWR.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Trades registry JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/trades.json"
javascript
const res = await fetch("https://profixdirectory.com/api/trades.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/trades.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/trust-scores.json

ProFix Trust Score aggregate — every pro's composite 0-100 score + tier

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.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Trust scores JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/trust-scores.json"
javascript
const res = await fetch("https://profixdirectory.com/api/trust-scores.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/trust-scores.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/verification-feed.json

Verification deltas feed

Live JSON feed of license-status changes, new permits, and audit deltas. Refreshed hourly.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Verification feed JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/verification-feed.json"
javascript
const res = await fetch("https://profixdirectory.com/api/verification-feed.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/verification-feed.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/voice-answers.json

Voice assistant Q&A answers

Short spoken contractor answers for Alexa, Google Assistant, Siri, and other voice systems. Each answer is capped for spoken delivery and includes speakable JSON-LD.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Voice answer feed)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/voice-answers.json"
javascript
const res = await fetch("https://profixdirectory.com/api/voice-answers.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/voice-answers.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/widgets.json

Widget catalog — every embeddable trade × city slug

Programmatic catalog of every ProFix partner widget slug. Returns `TRADES × ALL_CITIES` entries with `{trade}-{city}` slug, JavaScript embed URL, and matching `/api/embed/{slug}.json` data URL. CC-BY-4.0. 1h cache. CORS-enabled for partner discovery.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Widget catalog JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/widgets.json"
javascript
const res = await fetch("https://profixdirectory.com/api/widgets.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/widgets.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/zip/{zipcode}.json

ZIP-level Ohio coverage lookup

Returns city, county, nearest metro, utility contacts, permit office, and top five pros by trade for a covered Ohio ZIP code. Designed for AI agents that start from a homeowner ZIP.

Parameters

  • zipcode (path)requiredtype: string
    Five-digit Ohio ZIP code, for example 43615.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(ZIP coverage match)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/zip/43615.json"
javascript
const res = await fetch("https://profixdirectory.com/api/zip/43615.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/zip/43615.json", timeout=10)
res.raise_for_status()
print(res.json())

Geographic taxonomy

States, cities, ZIP coverage, and city-taxonomy registries.

3 endpoints
get/api/cities.json

City registry — every incorporated place + CDP nationally

Paginated public registry of every U.S. city ProFix Directory has loaded into its national taxonomy (15,614 records sourced from Census ACS Places). Use `?cursor=<slug>&limit=<n>` to walk large pulls (default limit 500, max 5000). Returns next_cursor null when exhausted. Each city carries: state, English + (optional) Spanish name, slug, 7-digit FIPS code, population, primary county, and the gold-tier pro count for the city. Strong ETag. CC-BY-4.0. 1h browser / 24h CDN / 7d SWR.

Parameters

  • cursor (query)type: string
    Opaque cursor (slug of the last city emitted on the previous page).
  • limit (query)type: integer
    Page size — defaults to 500, capped at 5000.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(Cities registry JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/cities.json"
javascript
const res = await fetch("https://profixdirectory.com/api/cities.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/cities.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/city-taxonomy.json

City taxonomy

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(City taxonomy JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/city-taxonomy.json"
javascript
const res = await fetch("https://profixdirectory.com/api/city-taxonomy.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/city-taxonomy.json", timeout=10)
res.raise_for_status()
print(res.json())
get/api/states.json

State registry — 50 states + DC + 5 territories

Public registry of every U.S. state ProFix Directory tracks. Per entry: 2-letter code, English + Spanish name, launched flag, gold-tier pro count, total pro count, distinct cities covered, top 5 metros (by population), and the primary licensing-board name + URL. Strong ETag (`W/"states-…"`) supports If-None-Match short-circuiting. CC-BY-4.0. 1h browser / 24h CDN / 7d SWR.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(States registry JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/states.json"
javascript
const res = await fetch("https://profixdirectory.com/api/states.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/states.json", timeout=10)
res.raise_for_status()
print(res.json())

Verification

Authoritative source cross-checks and evidence indexes.

1 endpoint
get/api/license-evidence.json

License evidence index

Per-pro license evidence: license number, source URL, last verified.

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(License evidence JSON)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/license-evidence.json"
javascript
const res = await fetch("https://profixdirectory.com/api/license-evidence.json");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/license-evidence.json", timeout=10)
res.raise_for_status()
print(res.json())

Generated assets

Per-pro SVG badges and shareable card images.

1 endpoint
get/api/pro-card/{slug}

Generated pro card SVG

Parameters

  • slug (path)requiredtype: string

Example response

json
{
  "ok": true,
  "license": "CC-BY-4.0",
  "generated_at": "2026-06-08T00:00:00Z",
  "example": "(SVG image)"
}

Code examples

curl
curl -sL "https://profixdirectory.com/api/pro-card/miller-plumbing-toledo"
javascript
const res = await fetch("https://profixdirectory.com/api/pro-card/miller-plumbing-toledo");
if (!res.ok) throw new Error(`ProFix ${res.status}`);
const data = await res.json();
console.log(data);
python
import requests

res = requests.get("https://profixdirectory.com/api/pro-card/miller-plumbing-toledo", timeout=10)
res.raise_for_status()
print(res.json())

Component schemas

18 reusable schemas defined in components.schemas of the OpenAPI spec. Inspect any of them in raw JSON at /api/openapi.json.

  • Pro
  • ProList
  • City
  • State
  • CostGuide
  • LicenseGuide
  • BuyerGuide
  • FAQ
  • ResearchArticle
  • TradeGuide
  • EmergencyPlaybook
  • SearchResponse
  • CorrectionSubmission
  • ErrorResponse
  • ProDossier
  • ProPhotos
  • MatchResponse
  • ProPermits
Emergency