Field reference

Every field, with a stability promise.

ProviderSignal returns the same field names today, in 6 months, and after the next API revision. This page is the contract: definitions, types, stability tiers, and the deprecation policy that protects integrations you've already built.

Stability tiers

Every field below carries one of three stability tiers. The tier sets your expectation for how durable the field name and value space are. Read this once before integrating.

  • Stable

    v1 contract. Renames or removals get a 6-month deprecation window minimum.

  • Beta

    Available in v1 but the type or value space may change before lock-in.

  • Internal

    Returned in responses but not part of v1. May change without notice.

v1 commitment. Fields tagged stable do not change types or names without a 6-month deprecation window and an explicit changelog entry. Breaking changes ship as /api/v2/* routes; the v1 surface stays live until the deprecation window closes.

Adding a field is always non-breaking. Always validate response shapes permissively (allow unknown keys) so adding a column doesn't break your integration.

CI guard. ProviderSignal's test suite runs a snapshot check on every customer-facing column list. Any rename or removal that reaches production has been intentional and reviewed.

Identity

Provider identity. NPI is the universal key — every other dataset (state boards, CMS, OIG, NPDB) cross-references via NPI.

npi#string (10 digits)
Stable

National Provider Identifier. The federal universal key. Always 10 digits, zero-padded. Use as the primary join key against any external dataset.

Example:1234567890
first_name#string | null
Stable

Given name as filed with NPPES. Title-cased. Null on entity-type=2 (organization) NPIs.

Example:Sarah
last_name#string | null
Stable

Surname as filed with NPPES. Title-cased.

Example:Patel
credential_type#string | null
Stable

DDS / DMD / RDH / etc. Source: NPPES taxonomy code → human-readable mapping.

Example:DDS
specialty#string | null
Stable

Primary dental specialty mapped from the NPPES primary taxonomy code.

Example:General Practice Dentistry
secondary_specialties#string[] | null
Beta

Additional taxonomy codes a provider has self-reported. Mostly populated for multi-specialty practitioners.

entity_type_code#1 | 2 | null
Stable

1 = Individual, 2 = Organization. Use to filter person-rows from practice-entity-rows in the same table.

enumeration_date#date (ISO) | null
Stable

Date NPPES first issued the NPI. Earliest reliable proxy for years-in-practice when graduation_year is missing.

Example:2003-08-15

Practice & Location

Practice attribution and geography. `inferred_practice_name` is the practice-identity column for individuals; `parent_organization_name` is always NULL for individuals.

practice_address#string | null
Stable

Primary practice street address. UPPER-cased; USPS suffixes abbreviated (ST/AVE/BLVD/RD/DR).

Example:123 MAIN ST STE 200
city#string | null
Stable

Practice city. UPPER-cased. May differ from mailing_city.

Example:AUSTIN
state#string (2-letter) | null
Stable

Two-letter USPS state code for the practice address.

Example:TX
zip#string | null
Stable

ZIP or ZIP+4 (5 or 10 chars). Includes territories (PR/VI/etc).

Example:78701
phone#string | null
Stable

Practice phone in (XXX) XXX-XXXX format. Placeholders (000s, all-same-digit, area code 0XX) are NULL'd.

Example:(512) 555-0123
latitude#number | null
Stable

Geocoded latitude (WGS84). Populated by the geocode pipeline.

longitude#number | null
Stable

Geocoded longitude (WGS84).

organization_name#string | null
Stable

NPPES employer/organization name when filed. Often NULL on individuals — use `inferred_practice_name` for practice attribution.

Stable

Parent corporate entity. ALWAYS NULL for individuals — use `inferred_practice_name` for practice identity on type-1 NPIs.

Stable

Practice identity for individual providers. Populated by the derived-fields refresh: prefers a co-located organization name at the same address+ZIP, falls back to parent_organization_name. The canonical practice-identity column for type-1 NPIs.

Example:AUSTIN FAMILY DENTAL
Stable

Distinct provider count at this practice address. Used to bucket Solo (1) / Small (2-4) / Group (5-9) / Large (10+).

Example:3
is_sole_proprietor#boolean | null
Stable

NPPES self-attested sole-proprietor flag. Independent practice-owner signal — strongest acquisition target indicator alongside `co_located_count <= 4`.

mailing_address#string | null
Beta

Mailing address when published separately from practice address (FL+CA). Useful for owner-residence inference.

Stable

NPPES authorized official — the business contact filed with the organization NPI. Often the practice owner or office manager; the right outreach contact for ownership-change conversations.

Licensing

State-board enrichment fields. Coverage varies by state — see /api-docs#state-coverage for per-state availability.

license_number#string | null
Stable

Primary state-board license number for the provider's practice state. Joins to state-specific verification portals.

state_license_numbers#Record<string, string>
Stable

Per-state license numbers as a JSONB object. Lets a single NPI carry multiple state credentials.

Example:{"TX": "12345", "CA": "67890"}
license_status#string | null
Beta

Raw per-state license status (130+ distinct values across all states). For UI filters use `license_status_normalized` instead.

Stable

License expiration date. Powers retirement-age and lapsing-license filters.

Stable

First-issue date. Used as the practice-vintage signal in states that don't publish graduation year (CO/OK/AR/LA/CA).

graduation_year#number | null
Stable

Year of dental school graduation. Drives retirement-risk scoring for TX. FL uses age_range instead.

age_range#string | null
Beta

FL-style 10-year age bucket (e.g. "60 - 70"). Used as the retirement-risk proxy in states without graduation-year data.

anesthesia_level#1 | 2 | 3 | 4 | null
Beta

Highest anesthesia permit level (TX/MN). Higher levels = larger surgical practice.

sedation_permits#string[] | null
Beta

Array of state-specific permit names (FL: Moderate Sedation, MN: 10 named permits, CA: 4 codes). Permit-rich providers correlate with higher procedure volume.

Compliance

Disciplinary action and federal exclusion flags. Bifurcated 2026-04-25: current vs historical discipline are separate columns to avoid muting active-discipline signals.

Current/active disciplinary action on the license. Surfaces as the red 'Disciplinary' pill.

Stable

Past discipline that has been resolved. Surfaces as amber 'Historical Discipline' pill. NULL on states not yet bifurcated.

Listed on the HHS OIG List of Excluded Individuals/Entities (LEIE). Federal Medicare/Medicaid exclusion. Score multiplier × 0.1 sinks excluded providers in acquisition views.

DSO Identification

Dental Service Organization affiliation flags. The pipeline runs four signals — name match, multi-location org, shared phone billing, address co-location cascade — and stores per-signal evidence in `dso_signals`.

is_dso#boolean | null
Stable

TRUE when at least one DSO signal fires for this provider. Drives the DSO badge across all provider surfaces.

dso_label#string | null
Stable

Canonical brand label (e.g. "Heartland Dental"). Aliases collapse legal-entity variants to a single public-facing name.

dso_detection#string | null
Stable

Strongest single signal: name_match | multi_location_org | shared_phone_org | address_cascade. For full per-signal evidence use `dso_signals`.

dso_signals#JSONB | null
Beta

Per-signal provenance vector with confidence and supporting evidence per fired signal. NULL on rows the pipeline hasn't backfilled yet (legacy DSO flags pre-migration-00132). Promoted to stable after one full nationwide pipeline run validates the schema against external consumers.

Example:{"name_match": {"fired": true, "confidence": 1.0, "matched_brand": "Heartland Dental"}}
dso_confidence#number | null
Beta

User-feedback-adjusted confidence (0.0-1.0). NULL = no feedback (treated as trusted). Drops by 0.15 per false-positive vote; clears `is_dso` below 0.3.

Acquisition Scoring

Six-factor acquisition target score. Single source of truth: src/lib/scoring.ts. Factor weights are stable v1; the algorithm itself is intentionally transparent so buyers can audit it.

score#number (0-100)
Stable

Composite acquisition score. 100 = highest-priority acquisition target. Computed live, never stored — the formula is open in src/lib/scoring.ts.

Example:84

S1 (25% weight). True independents (sole proprietors with co_located_count <= 4 and no parent org) score 1.0; large groups score 0.

S2 (15% weight). Years-in-practice estimated from graduation_year, age_range midpoint, or license_issue_date. Older = higher score.

S3 (20% weight). Estimated current age. 55+ scores high. confirmed_retired feedback maxes the factor.

S4 (15% weight). Smaller practices are easier acquisitions. Solo = 1.0; 10+ co-located = near 0.

Stable

S5 (10% weight). No disciplinary action = 1.0; any current discipline = 0.

S6 (15% weight). Active license = 1.0; expired/suspended/retired = 0.

scoring_confidence#number | null
Beta

User-feedback multiplier (0.0-1.0). NULL = no feedback (treated as 1.0). Pushes user-disagreed-with rows down without changing the underlying factor breakdown.

User Feedback (Moat #1)

User-rollup-derived state, set ONLY by /api/feedback/rollup. Pipelines do not touch these. Most rows are NULL (no feedback yet) — read sites COALESCE NULL → trusted.

acquisition_status#'acquired' | 'not_a_target' | null
Beta

User has reported this practice was already acquired, or is not a viable target. Filters this row out of active acquisition queries.

practice_status#'closed' | null
Beta

User has reported this practice closed. Filters out of all active prospect queries.

retirement_status#'confirmed_retired' | null
Beta

Three or more users confirmed retirement. Maxes S3 (retirement_risk) regardless of age data.

Temporal Tracking (Moat #2)

Per-provider event history accumulated since we started tracking. Available via /api/providers/[npi] history endpoint and rendered as a timeline on /provider/[npi]. The compound moat: every weekly NPPES delta adds rows a new entrant cannot backfill.

Event category. Examples: phone_change, address_change, status_change, expiration_approaching, disciplinary_action, org_name_change, parent_org_change, new_npi, new_license, provider_deactivated.

When the event occurred (or was first observed). Nullable on legacy rows.

Stable

Previous value. Empty for emergence-style events (new_license).

Stable

New value at the time of the event.

Internal

Pipeline that observed the event (e.g. ingest_tx_dental). Internal use; not part of v1 contract.

Looking for HTTP shape, parameters, error codes, or rate limits? See the API reference. This page documents field semantics; that page documents the wire protocol.

Spotted a field that's missing or out of date? Tell us. The glossary is the canonical reference, so we keep it current.