Provider intelligence, as a REST API.
RESTful JSON API for programmatic access to dental provider data, territory triggers, market intelligence, license monitoring, and practice scoring. 410,798 providers across all 50 states, 42 states + DC enriched.
Authentication
Include your API key in the Authorization header of every request.
API keys are generated in Settings → API Keys in your dashboard. Keys start with ps_live_. The full key is shown only once at creation, so store it securely.
Dashboard users can also access the API via session cookies (automatic when logged in). API key authentication is required for programmatic access.
No API key? Two alternatives
- Free evaluation tier: four no-auth endpoints (NPI lookup 100/day, Medicaid dental rates 25/day, provider search and territory summary 10/day each, per source IP). Use to evaluate data quality.
- Per-call agent payments (x402): Pay USDC per request on Base. Built for AI agents that don't hold API keys or sign contracts.
Rate Limits
Rate limits are applied per API key using a sliding window algorithm. Exceeding the limit returns HTTP 429 with rate limit headers.
API Starter
60 req/min
$99/mo
API Pro
500 req/min
$299/mo
Team (Dashboard)
200 req/min
$499/mo
Enterprise
1,000 req/min
$1,999+/mo
Response Headers
API Scopes
API keys are issued with specific scopes that control which endpoints they can access. Attempting to access an endpoint without the required scope returns HTTP 403.
Search providers, retrieve profiles, alerts, market intelligence data. Included in all API keys.
Endpoints: All GET endpoints except exports
Bulk data export (CSV and JSON). Required for /api/providers/export and /api/scoring/export.
Endpoints: Export endpoints
Create/update saved searches, profile, preferences. Required for POST/PATCH/DELETE on user data.
Endpoints: Saved searches, profile, preferences, onboarding
Plan tier gating (separate from scopes)
A small number of endpoints require a specific plan tier beyond the scope check. These are flagged with a Team+ badge in the endpoint list below. Rep plan keys receive a 403 when hitting these endpoints with an explanatory error message. The Team+ tier covers Team, Enterprise, and any API plan that bundles Team-level data access.
403 Error Example
Pagination
Two pagination strategies are available:
Offset Pagination
Best for: browsing, UI tables, known page numbers.
Supports custom sort/order. Max per_page: 100 (dashboard), 1000 (API keys).
Cursor Pagination
Best for: bulk export, iterating all results, data pipelines.
Stable iteration: no skipped or duplicate rows. Forces order by NPI. Returns next_cursor in meta.
Cursor Iteration Pattern
Response Convention
Every read endpoint returns a JSON envelope with a stable shape. Success responses always include both data and error keys. Error responses use the same envelope with data: null. Never check !response.data alone — an empty list is a valid success.
Success
Error
Two endpoints add an extra wrapper field beyond the standard envelope: /api/demographics echoes the requested metric param, and /api/whitespace echoes the resolved state. Both still include data and error for consistent client handling.
The /api/preferences endpoints (account settings) and write endpoints that return {success: true} use simpler shapes appropriate to user-settings + mutation domains. Both are documented per-endpoint below.
Endpoints
Providers
/api/providersreadSearch and filter dental providers. Supports full-text search, specialty filters, geography, license status, DSO affiliation, Medicare billing history, Medicaid state-roster enrollment (medicaid=true), practice size, and pagination (offset or cursor-based).
Returns { data, error, meta: { total, page, per_page, total_pages, next_cursor? } }
/api/providers/:npireadRetrieve a complete provider profile by NPI number. Includes co-located providers at the same address and any resolved practice-level entities.
Returns { data: { ...provider, co_located: [...], practice_entities: [...] }, error }
/api/providers/mapreadMap-rendering endpoint: returns geocoded provider points within a bounding box, with enough fields to render clusters and popups. Capped at 30,000 results per request.
Returns { data: [{ npi, last_name, first_name, specialty, latitude, longitude, license_status, license_expiration_date, has_disciplinary_action, is_federally_excluded, co_located_count, inferred_practice_name, graduation_year, date_of_birth, is_dso, dso_detection, dso_signals, is_sole_proprietor, organization_name, entity_type_code, ... }], error }
Export
/api/providers/exportexportBulk export provider data as CSV or JSON. Every filter parameter on /api/providers is also accepted here, including excluded, has_email, has_fax, sedation_permit, retirement_risk, and include_suppressed. JSON format supports cursor-based pagination for iterating through large datasets.
Trial behavior: Trial users are capped at 25 rows per export. Paid tiers get up to 5,000 rows (10,000 for API keys).
CSV: file download. JSON: { data, error, meta: { total, count, per_page, next_cursor } }
/api/scoring/exportexportExport practice scores as CSV or JSON, with the score breakdown and, on request, the score_version, transition_likelihood and transition_probability columns. Every filter parameter on /api/providers is also accepted here.
Trial behavior: Trial users are capped at 25 rows per export. Paid tiers capped at 5,000 rows (10,000 for API keys). No cursor pagination on this endpoint — use /api/providers/export with sort=score if you need to iterate beyond the cap.
CSV: file download. JSON: { data: [{ ...provider, score, score_factors, score_version }], error, meta: { total, count } }. JSON has no next_cursor — pagination is offset-only here.
/api/alerts/rates/exportexportOne state's detected Medicaid dental fee-schedule changes as CSV: every schedule and every change, largest move first. The same filters as /api/alerts/rates narrow it (locality, type, q, sort, min_pct, significant_only, which defaults to false here) and the file is then named -view. Columns: State, Schedule, Schedule (as published), CDT code, Procedure (ProviderSignal's own label), Family, Change, Old rate, New rate, Change %, Effective quarter, Detected.
Trial behavior: Trial users get a 50-row sample, three sample files per trial, on the same budget as the fee-schedule file. Paid plans get the complete file.
CSV: file download named medicaid-dental-rate-changes-<state>-<quarter>.csv.
Scoring
/api/scoringreadPractice scoring. Returns individual providers ranked by the acquisition score. Since 2026-10-19 the score is the dentist's transition likelihood (a weekly model's percentile, within the state, of how likely the dentist is to leave practice; in a backtest over March to October 2026 its top tenth left practice at about 4 times the base rate) times an acquisition fit (ownership, independence, size, record, license health). 70 or more is roughly the top 5% of a state's dentists. The score and score_factors field names did not change; their meaning did, and score_version says which formula a row carries: 3 where the likelihood applies, 2 for hygienists and assistants on the older six-factor formula. Rows also carry transition_likelihood and transition_probability. API-key calls default to dentists when provider_type is absent (send provider_type=all for every individual); the dashboard sends its own. Each response row also includes a confidence score and (when applicable) Medicare Part B aggregates. Reps use the score to prioritize call lists; DSO biz-dev teams use the same score for acquisition target ranking.
Returns { data: [{ ...provider, score, score_factors, score_version, transition_likelihood, transition_probability, confidence, cms_medicare? }], error, meta }
Market Intelligence
/api/whitespacereadMarket whitespace analysis. Returns geographic areas scored by population-to-provider ratio, HPSA designation, and demographic factors. Supports state-wide or geo-scoped (ZIP+radius, city) queries.
Returns { data: [{ zip, provider_count, population, whitespace_score, ... }], error }
/api/reimbursementreadMedicaid fee schedule rates by CDT code and geography.
/api/demographicsreadZIP-level demographics from Census ACS data. Supports state-wide or geo-scoped queries. Returns 400 if `metric` is not one of the listed enum values.
Returns { data: [{ zip, ...demographic_fields }], error, metric }. The extra `metric` field echoes the requested sort metric so callers running parallel queries with different metrics can disambiguate responses without tracking request URLs.
/api/npdbreadAggregate NPDB malpractice payment and adverse action trends by state and year. Anonymized, no individual provider data.
/api/reports/marketreadMarket summary report: total providers, specialty breakdown, license status distribution, top organizations, DSO share, practice-size distribution, retirement-age count, HPSA designations. Supports state-wide and geo-scoped (city, ZIP+radius) queries.
Trial behavior: Trial users are capped at 1 downloaded PDF brief per trial. Previews (page loads without for_brief=1) are unlimited.
/api/hpsa/mapreadHRSA Health Professional Shortage Area designations for dental care, deduplicated by county and enriched with county centroid coordinates for map overlays.
Returns { data: [{ hpsa_id, designation_type, hpsa_score, county_name, county_fips, latitude, longitude }], error }
/api/cms/mapreadTeam+Dental providers with CMS Medicare Part B billing history, geocoded for map overlay rendering. Returns lifetime billing aggregates per NPI (~3,000 providers nationally).
Plan requirement: Team tier or higher. Rep plan receives 403.
Returns { data: [{ npi, first_name, last_name, specialty, latitude, longitude, total_paid_lifetime, total_paid_latest_year, latest_year, years_active }], error }
Triggers
/api/triggers/summaryreadTrigger feed summary for the dashboard home card. Returns a count-by-trigger-type breakdown for the requested state and lookback window. Includes all trigger sources by default (opt-out via include_backfill=0). Use this for territory-level rollups; use /api/alerts/events for the underlying license-event detail.
Returns { data: { total, days, state, byType: { dso_acquisition, new_associate, new_specialist, new_practice, practice_opened_new_location, provider_moved, provider_departed, practice_moved, practice_closed, license_renewal_window }, types: [string] } }. Field name is camelCase byType, not snake_case.
Alerts
/api/alerts/eventsreadLicense change events: expirations, status changes, new registrations, NPI deactivations, and disciplinary actions. Paginated.
Returns { data, error, meta: { total, page, per_page, total_pages } }
/api/alerts/grantsreadDental-relevant federal grant opportunities from Grants.gov and SAM.gov. Paginated.
/api/alerts/ratesreadDetected changes to a state's published Medicaid dental fee schedules: rate increases and decreases, codes added and codes removed, from the snapshot diff of each published schedule since June 2026. One schedule at a time (the state's default unless locality says otherwise), largest move first. The response meta carries the resolved schedule and the state's change summary (codes moved, the median move, the largest moves, codes added and removed, the schedules that carry events, the last detection date).
Plan requirement: Every paid plan including Rates; the API plans too.
Returns { data: [{ id, cpt_cdt_code, code_description, state, locality, event_type, old_rate, new_rate, rate_change_pct, is_significant, effective_quarter, created_at }], error, meta: { total, page, per_page, total_pages, locality, summary } }
/api/alerts/npdbreadTeam+NPDB malpractice trend anomaly events by state. Surfaces states whose latest-year adverse action count exceeds the 3-year rolling average by >20%.
Plan requirement: Team tier or higher. Rep plan receives 403.
Account
/api/profilereadRetrieve the authenticated user's profile (role, territory, company).
/api/profilewriteUpdate profile fields: role, display_name, company_name, territory_states, territory_zips, territory_metros.
/api/saved-searchesreadList the authenticated user's saved searches.
/api/saved-searcheswriteCreate a saved search. Body: { name, filters, notify_email }. Plan limits apply (Rep: 10, Team: unlimited).
/api/saved-searches/:idwriteDelete a saved search by ID. Ownership is verified.
/api/saved-providersreadList the authenticated user's bookmarked providers (Save + Set alert from the triage slideout). Each row carries enrichment fields (specialty, license status, practice context) joined client-side from the providers table.
Returns { data: [{ id, npi, notify_on_change, created_at, ...enrichment }], error }
/api/saved-providerswriteBookmark a provider. Idempotent on (user_id, npi); calling twice toggles or refreshes the row instead of duplicating. Body: { npi, notify_on_change?: boolean }.
Plan requirement: Rep tier capped at 10 saved providers; Team and Enterprise uncapped.
/api/saved-providerswriteRemove a saved provider. Pass ?npi=XYZ as a query parameter.
/api/preferencesreadRead digest email frequency preference.
/api/preferenceswriteUpdate digest frequency. Body: { digest_frequency: 'off' | 'weekly' | 'daily' }.
Plan requirement: digest_frequency='daily' requires Team tier or higher. 'off' and 'weekly' are available on all plans.
System
/api/healthnoneHealth check. Returns database connectivity status and latency. No authentication required.
/api/statsnonePublic statistics: provider counts, expiring licenses, DSO-flagged, solo practitioners, retirement-age providers, disciplinary actions, HPSA designations, active grants, enriched state counts. Cached 5 minutes. No authentication required.
/api/data-statusreadData source freshness status for all pipeline sources.
Error Codes
All error responses follow a consistent format:
Code Examples
cURL
Python
JavaScript
Example Response
GET /api/providers?state=TX&sole_prop=true&per_page=1
Get API access
API keys are available on all paid plans. Subscribe to generate your first key.
Start Free Trial