{"openapi":"3.1.0","info":{"title":"ProviderSignal API","description":"Healthcare market intelligence API. Unified provider directory + acquisition signals + license-events feed across all 50 US states, derived from NPI + state dental boards + CMS Medicare + OIG LEIE + state Medicaid + HRSA HPSA designations. All responses ship a citation envelope (`meta.envelope_version`, `meta.source_attribution`, `meta.request`) so agents can verify source freshness without out-of-band validation. See [/docs/fields](/docs/fields) for the field glossary and [/llms.txt](/llms.txt) for the LLM crawler index.","version":"1.0.0","contact":{"name":"ProviderSignal Support","email":"support@providersignal.com","url":"https://providersignal.com/contact"},"license":{"name":"Proprietary — Per-call billing rails available via /pricing","url":"https://providersignal.com/pricing"},"termsOfService":"https://providersignal.com/terms"},"servers":[{"url":"https://providersignal.com","description":"Production"}],"security":[{"apiKey":[]},{"sessionCookie":[]}],"tags":[{"name":"Free Tier","description":"Public no-auth evaluation endpoints — Phase 2 free-tier"},{"name":"Stats","description":"Aggregate counts for dashboard + landing page"},{"name":"Providers","description":"Provider directory + scoring"},{"name":"Reimbursement","description":"CMS + state Medicaid fee schedules"},{"name":"Demographics","description":"ZIP-level Census ACS data"},{"name":"NPDB","description":"National Practitioner Data Bank aggregate stats"},{"name":"Geospatial","description":"Map overlays (CMS billing, HPSA shortage areas)"}],"paths":{"/api/v1/free/lookup":{"get":{"summary":"NPI lookup (free tier, no auth)","description":"Public NPI-keyed lookup returning light data only (name, primary practice address, taxonomy, enumeration date). No authentication required. Rate-limited to 100 requests/day per IP (rolling 24h window) with a 10/min burst cap. Excludes DSO affiliation, license events, license status, HPSA, NPDB, CMS Medicare, and confidence scores — those require a paid plan or per-query billing.","tags":["Free Tier"],"security":[],"parameters":[{"name":"npi","in":"query","required":true,"schema":{"type":"string","pattern":"^\\d{10}$"},"description":"10-digit NPI"}],"responses":{"200":{"description":"Light provider data + citation envelope (billing_method='free')"},"400":{"description":"Missing or malformed npi parameter"},"404":{"description":"NPI not found in the dental cohort"},"429":{"description":"Rate limit exceeded. Headers include `Retry-After` in seconds plus standard `X-RateLimit-*`. Body includes upgrade_paths to /pricing and /docs/agent-payments."}}}},"/api/v1/free/health":{"get":{"summary":"Free-tier health probe","description":"Public no-auth health probe for agents validating connectivity. No rate limit. Returns API version + envelope version + canonical doc URLs. Distinct from /api/health (which probes DB + Redis + Stripe).","tags":["Free Tier"],"security":[],"responses":{"200":{"description":"Service reachable"}}}},"/api/stats":{"get":{"summary":"Aggregate provider counts (public)","description":"Headline counts powering the landing page. Returns counts by territory if `states` param provided, or national totals.","tags":["Stats"],"security":[],"parameters":[{"name":"states","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated 2-letter state codes (e.g. `TX,FL,CA`). Omit for national totals."}],"responses":{"200":{"description":"Aggregate stats with citation envelope","content":{"application/json":{"schema":{"allOf":[{"type":"object","required":["data","error"],"properties":{"data":{"description":"Endpoint-specific payload. Type varies per route — see individual path responses."},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/EnvelopeMeta"}}},{"properties":{"data":{"$ref":"#/components/schemas/StatsData"}}}]}}}},"429":{"$ref":"#/components/responses/RateLimit"}}}},"/api/providers":{"get":{"summary":"Provider directory (paginated, filterable)","description":"Paginated provider list with extensive filter support. Each row carries a per-provider `confidence` field (completeness + multi-source + freshness). The full filter catalog is documented in the parameters below.","tags":["Providers"],"parameters":[{"$ref":"#/components/parameters/state"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/per_page"},{"name":"q","in":"query","schema":{"type":"string"},"description":"Free-text search across name, NPI, city, ZIP, organization"},{"name":"city","in":"query","schema":{"type":"string"}},{"name":"zip","in":"query","schema":{"type":"string","pattern":"^\\d{5}$"}},{"name":"specialty","in":"query","schema":{"type":"string"}},{"name":"is_dso","in":"query","schema":{"type":"string","enum":["true","false"]}},{"name":"discipline","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Active OR historical discipline (TN v1.24 bifurcation)"},{"name":"excluded","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"OIG LEIE federal exclusion filter"},{"name":"retirement_risk","in":"query","schema":{"type":"string","enum":["true"]},"description":"State-agnostic retirement-risk via graduation_year, age_range, or license_issue_date"},{"name":"license_status","in":"query","schema":{"type":"string"}},{"name":"exp_months","in":"query","schema":{"type":"integer","minimum":1,"maximum":24}},{"name":"anesthesia_level","in":"query","schema":{"type":"string"}},{"name":"min_practice_size","in":"query","schema":{"type":"integer"}},{"name":"has_cms","in":"query","schema":{"type":"string","enum":["true","false"]}},{"name":"has_email","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"FL provider_email presence"},{"name":"sedation_permit","in":"query","schema":{"type":"string"},"description":"FL sedation_permits filter; pass `__any__` for IS NOT NULL"},{"name":"sole_prop","in":"query","schema":{"type":"string","enum":["true","false"]}},{"name":"independent","in":"query","schema":{"type":"string","enum":["true"]}},{"name":"enriched_only","in":"query","schema":{"type":"string","enum":["true"]}},{"name":"include_suppressed","in":"query","schema":{"type":"string","enum":["true"]},"description":"Include rows users marked as already-acquired (default: excluded)"},{"name":"min_confidence","in":"query","schema":{"type":"integer","minimum":0,"maximum":100}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"NPI of the last result from the prior page (cursor pagination)"}],"responses":{"200":{"description":"Paginated provider list with citation envelope. `meta` carries both pagination fields (total, page, per_page, total_pages, optional next_cursor) and envelope fields (envelope_version, source_attribution, request)."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimit"}}}},"/api/providers/{npi}":{"get":{"summary":"Provider record by NPI","description":"Detail record for a single provider keyed by 10-digit NPI. Returns provider fields + co-located providers + practice entities + CMS Medicare summary + OIG LEIE exclusion (when applicable). NOTE: this endpoint currently returns its legacy non-envelope shape; envelope migration pending dashboard-frontend coordination.","tags":["Providers"],"parameters":[{"name":"npi","in":"path","required":true,"schema":{"type":"string","pattern":"^\\d{10}$"},"description":"10-digit National Provider Identifier"}],"responses":{"200":{"description":"Provider detail (legacy shape — envelope migration pending)"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"NPI not found in the dental cohort"}}}},"/api/scoring":{"get":{"summary":"Scored acquisition leads","description":"Provider list with computed acquisition score (0-100), per-row confidence, and CMS Medicare aggregates. Each row carries `confidence: { score, tier, breakdown }` reflecting completeness + multi-source agreement + freshness for that provider.","tags":["Providers"],"parameters":[{"$ref":"#/components/parameters/state"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/per_page"},{"name":"sort","in":"query","schema":{"type":"string","enum":["score","last_name","city","enumeration_date","license_expiration_date","co_located_count","inferred_practice_name","cms_paid"]},"description":"Sort column. Default `score`."},{"name":"order","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}},{"name":"min_score","in":"query","schema":{"type":"integer","minimum":0,"maximum":100}}],"responses":{"200":{"description":"Paginated scored providers with citation envelope","content":{"application/json":{"schema":{"allOf":[{"type":"object","required":["data","error"],"properties":{"data":{"description":"Endpoint-specific payload. Type varies per route — see individual path responses."},"error":{"type":"null"},"meta":{"$ref":"#/components/schemas/EnvelopeMeta"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimit"}}}},"/api/npdb":{"get":{"summary":"NPDB aggregate stats","description":"Aggregated National Practitioner Data Bank stats by state + year + report category. NPDB is anonymized so individual disciplinary records come from state boards (see /api/alerts/events).","tags":["NPDB"],"parameters":[{"$ref":"#/components/parameters/state"}],"responses":{"200":{"description":"NPDB aggregate stats with citation envelope"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/api/reimbursement":{"get":{"summary":"Fee schedules (CMS + state Medicaid)","description":"CPT/CDT-keyed reimbursement rates from CMS Medicare PFS and state Medicaid programs. Note: CMS dental rates are $0 (Medicare doesn't cover dental); use state Medicaid for actual dental rates.","tags":["Reimbursement"],"parameters":[{"$ref":"#/components/parameters/state"},{"name":"code","in":"query","schema":{"type":"string"},"description":"CPT or CDT code (e.g. `D2150`)"},{"name":"locality","in":"query","schema":{"type":"string"},"description":"State-specific locality identifier"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":2000,"default":20}}],"responses":{"200":{"description":"Reimbursement rates with citation envelope"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/api/demographics":{"get":{"summary":"ZIP-level Census ACS demographics","description":"Census ACS 5-year demographics by ZIP. Supports geo-scoping via ZIP+radius or city centroid.","tags":["Demographics"],"parameters":[{"$ref":"#/components/parameters/state"},{"name":"metric","in":"query","schema":{"type":"string","enum":["total_population","median_household_income","median_age","pct_under_18","pct_65_plus"],"default":"total_population"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500,"default":200}},{"name":"zip","in":"query","schema":{"type":"string","pattern":"^\\d{5}$"},"description":"5-digit ZIP for radius scoping (use with `radius`)"},{"name":"radius","in":"query","schema":{"type":"number"},"description":"Miles around `zip`. Capped at 200."},{"name":"city","in":"query","schema":{"type":"string"},"description":"City name (use with `state`); 25-mile default radius applied"}],"responses":{"200":{"description":"Demographics with citation envelope (echoes `metric` at root for legacy callers)"},"400":{"description":"Invalid metric"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/api/cms/map":{"get":{"summary":"Medicare Part B map overlay (Team+)","description":"Geocoded providers with Medicare Part B billing history, aggregated by NPI. Marker size scales with lifetime payment volume. Pro plan blocked (returns 403); Team plan and higher allowed.","tags":["Geospatial"],"parameters":[{"$ref":"#/components/parameters/state"}],"responses":{"200":{"description":"CMS map entries with citation envelope"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Pro plan — upgrade to Team for CMS overlay"}}}},"/api/hpsa/map":{"get":{"summary":"HRSA HPSA designations map overlay","description":"Health Professional Shortage Area designations by county. One row per county (highest-score designation when multiple).","tags":["Geospatial"],"parameters":[{"$ref":"#/components/parameters/state"}],"responses":{"200":{"description":"HPSA designations with citation envelope"},"401":{"$ref":"#/components/responses/Unauthorized"}}}}},"components":{"schemas":{"EnvelopeMeta":{"type":"object","required":["envelope_version","source_attribution","request"],"description":"Citation envelope. Every agent-callable response carries this so agents can verify provenance + freshness without out-of-band validation.","properties":{"envelope_version":{"type":"string","const":"1.0","description":"Schema version of the envelope itself. Bumped on breaking shape changes; non-breaking additions don't bump."},"source_attribution":{"type":"array","description":"Every source table that contributed to this response, with its own `last_refresh` from the pipeline status table.","items":{"$ref":"#/components/schemas/SourceAttribution"}},"confidence":{"type":"object","description":"Endpoint-specific confidence breakdowns keyed by inference type. Omitted entirely when no inferred fields are returned. For per-row inferences (e.g. /api/scoring's per-provider confidence), the inference appears on each row instead.","additionalProperties":{"$ref":"#/components/schemas/EndpointConfidence"}},"request":{"$ref":"#/components/schemas/RequestMeta"},"total":{"type":"integer"},"page":{"type":"integer"},"per_page":{"type":"integer"},"total_pages":{"type":"integer"},"next_cursor":{"type":["string","null"]}}},"SourceAttribution":{"type":"object","required":["table","last_refresh","schema_version","license"],"properties":{"table":{"type":"string","description":"Logical source name (e.g. `npi`, `tsbde`, `cms_partb`, `hpsa`)"},"last_refresh":{"type":["string","null"],"format":"date-time","description":"ISO 8601 timestamp of the most recent successful pipeline run, or null if never synced (cold-start state)"},"schema_version":{"type":"string","description":"Stable identifier for the data shape we expose. Bumped only on deliberate breaking changes."},"license":{"type":"string","enum":["public-domain","state-public-records","state-fee-schedule"],"description":"Posture string. `public-domain` for federal sources (NPI, OIG LEIE, CMS, HPSA, Census). `state-public-records` for state board rosters. `state-fee-schedule` for state Medicaid fee tables (often carry use-with-attribution restrictions)."}}},"EndpointConfidence":{"type":"object","required":["score","method"],"properties":{"score":{"type":"number","description":"0-100 (provider record confidence) or 0-1 (probability-style scores like DSO affiliation). Endpoint-specific scale; documented in /docs/fields."},"tier":{"type":"string","enum":["High","Medium","Low"],"description":"Optional human-readable bucket. Only meaningful for 0-100 scores."},"method":{"type":"string","description":"Short identifier for the computation method (e.g. `completeness+multi_source+freshness` or `shared_billing_address+phone_clustering+name_match`). Stable across releases — bumps signal a method change."},"breakdown":{"type":"object","additionalProperties":true,"description":"Optional component-level breakdown for callers who want to surface the 'why'."},"evidence_count":{"type":"integer","description":"Optional supporting-row count for evidence-driven inferences (e.g. number of co-located providers backing a DSO inference)."}}},"RequestMeta":{"type":"object","required":["id","endpoint","billed_credits","billing_method"],"properties":{"id":{"type":"string","description":"Stable request id for log correlation. Mirrored to the `X-Request-Id` response header."},"endpoint":{"type":"string"},"billed_credits":{"type":"integer","description":"Credits billed against the caller's bucket. 0 for subscription / admin / free; positive int for per-query (Phase 3 x402 / MPP)."},"billing_method":{"type":"string","enum":["subscription","per_query","free","admin"]}}},"StatsData":{"type":"object","properties":{"provider_count":{"type":"integer"},"active_providers":{"type":"integer"},"dso_flagged":{"type":"integer"},"solo_practitioners":{"type":"integer"},"retirement_age":{"type":"integer"},"inactive_retired_count":{"type":"integer"},"disciplinary_actions":{"type":"integer"},"enriched_count":{"type":"integer"},"expiring_licenses_12mo":{"type":"integer"},"expiring_licenses_24mo":{"type":"integer"},"open_grants":{"type":"integer"},"hpsa_designations":{"type":"integer"}}}},"parameters":{"state":{"name":"state","in":"query","schema":{"type":"string","pattern":"^[A-Z]{2}$"},"description":"2-letter US state code (uppercased automatically)"},"page":{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},"per_page":{"name":"per_page","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}},"responses":{"Unauthorized":{"description":"Missing or invalid auth (no API key, expired session, wrong scope on key)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"null"},"error":{"type":"string"}}}}}},"RateLimit":{"description":"Rate limit exceeded. Headers: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}}},"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"API key auth. Format: `Authorization: Bearer ps_live_<key>`. Provisioned per plan — see /pricing. Phase 3 (Q3 2026) adds x402 / MPP per-query tokens as an alternative auth path."},"sessionCookie":{"type":"apiKey","in":"cookie","name":"sb-access-token","description":"Supabase session cookie (dashboard auth). Not used by external API consumers."}}}}