{"openapi":"3.1.0","info":{"title":"xcircl Data API","version":"1.0.0","description":"Source-linked, timestamped facts about regulated-care providers. EVERY provider call requires an API key — free keys are issued instantly by email at https://xcircl.com/developers/signup (500 calls/mo, identity fields, evaluation & non-commercial use). Paid plans add verified compliance signals, price and verification timestamps, plus a commercial-use licence. On the free tier the paid fields are returned as locked placeholders: {\"locked\":true,\"unlock\":\"...\"} — locked marks a PAID field, never a claim that the provider is verified. Every number on the site is served live from GET /api/v1/coverage/.","contact":{"name":"xcircl","email":"info@xcircl.com","url":"https://xcircl.com/contact/"},"license":{"name":"Proprietary — see Terms of use","url":"https://xcircl.com/terms-of-use/"}},"servers":[{"url":"https://xcircl.com/api/v1","description":"Production"}],"security":[{"bearerAuth":[]},{"apiKeyHeader":[]},{"apiKeyQuery":[]}],"tags":[{"name":"Providers","description":"Query and fetch provider records."},{"name":"Coverage","description":"Public aggregate — what the dataset holds right now."},{"name":"Sample","description":"Public, full-schema sample rows."}],"paths":{"/providers":{"get":{"tags":["Providers"],"summary":"List providers","description":"Tiered, filterable, paginated list. Two paths: pass `vertical` for the verified vertical layer (default delivery = verified/published tier); or pass `taxonomy` (an NUCC code) with no vertical for the free L0 identity layer (NPPES, all specialties — identity fields only, each row layer:\"identity\"). Free-tier callers may pass include=tracked (JSON only) for the tracked transparency view. Metered (Builder/Developer) responses carry X-RateLimit-* headers.","operationId":"listProviders","parameters":[{"name":"vertical","in":"query","schema":{"type":"string","enum":["glp1","pet_health","medspa","ivf","dental","senior"]},"description":"Availability: glp1 is verified today; pet_health & medspa are loading; dental & senior queued. Non-live verticals are reserved in the enum but return no data yet — don’t integrate against them until announced. A Builder key is bound to a single vertical."},{"name":"taxonomy","in":"query","schema":{"type":"string"},"description":"L0 identity layer: an NUCC taxonomy code (e.g. 122300000X = Dentist). When given WITHOUT vertical, queries the free NPPES identity layer across all specialties — identity fields only, every row layer:\"identity\", source:\"NPPES\". Combine with state/city + limit/offset. Ignored if vertical is also present."},{"name":"state","in":"query","schema":{"type":"string"},"description":"Two-letter state code, e.g. CA. Case-insensitive."},{"name":"city","in":"query","schema":{"type":"string"},"description":"City name. Case-insensitive."},{"name":"business_mode","in":"query","schema":{"type":"string","enum":["online","physical","both"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":1000,"default":50}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}},{"name":"format","in":"query","schema":{"type":"string","enum":["json","csv"],"default":"json"},"description":"csv returns an attachment with the tier-appropriate column set."},{"name":"include","in":"query","schema":{"type":"string","enum":["tracked"]},"description":"Free tier + JSON only: return the full tracked set instead of the verified delivery set."}],"responses":{"200":{"description":"A page of providers — ProviderListResponse for the vertical path, or IdentityListResponse (layer:\"identity\") for the L0 taxonomy path.","headers":{"X-RateLimit-Limit":{"description":"Your plan’s monthly call quota. Present on metered (Builder/Developer) responses only.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left in the current UTC month.","schema":{"type":"integer"}},"X-RateLimit-Used":{"description":"Calls used so far this month, including this one.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the quota resets (00:00 UTC on the 1st of next month).","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProviderListResponse"},{"$ref":"#/components/schemas/IdentityListResponse"}]}},"text/csv":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/providers/{id}":{"get":{"tags":["Providers"],"summary":"Get one provider","description":"Fetch a single provider by entity_id or slug. Tiered identically to the list route.","operationId":"getProvider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"entity_id or slug."},{"name":"include","in":"query","schema":{"type":"string","enum":["tracked"]},"description":"Free tier only: allow a tracked-set record."}],"responses":{"200":{"description":"The provider.","headers":{"X-RateLimit-Limit":{"description":"Your plan’s monthly call quota. Present on metered (Builder/Developer) responses only.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left in the current UTC month.","schema":{"type":"integer"}},"X-RateLimit-Used":{"description":"Calls used so far this month, including this one.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the quota resets (00:00 UTC on the 1st of next month).","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderDetailResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/coverage":{"get":{"tags":["Coverage"],"summary":"Coverage aggregate","description":"Public, ungated proof endpoint. Dual-boundary counts — tracked (transparency) and verified (delivery) — computed from the database and refreshed hourly. This is the single source of truth for every figure the site displays.","operationId":"getCoverage","security":[{}],"responses":{"200":{"description":"Coverage stats.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverageStats"}}}},"500":{"$ref":"#/components/responses/ServerError"}}}},"/sample":{"get":{"tags":["Sample"],"summary":"Sample rows","description":"Public, ungated proof endpoint. A fixed 50-row sample in the full (paid) schema, so you can see data quality and field shape before getting a key.","operationId":"getSample","security":[{}],"parameters":[{"name":"format","in":"query","schema":{"type":"string","enum":["json","csv"],"default":"json"}}],"responses":{"200":{"description":"The sample.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SampleResponse"}},"text/csv":{"schema":{"type":"string"}}}},"500":{"$ref":"#/components/responses/ServerError"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Authorization: Bearer <API_KEY>"},"apiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key"},"apiKeyQuery":{"type":"apiKey","in":"query","name":"key","description":"Discouraged: keys in query strings are easily logged. Prefer a header."}},"schemas":{"SourcedSignal":{"type":"object","description":"A single compliance signal with its provenance. Paid tier only.","properties":{"status":{"type":"string","enum":["verified","clear","flagged","reported","unverified","not_screened"],"description":"verified = positive fact with source + date; clear = a negative screen we ran; flagged = adverse finding on file; reported = self-reported, not independently verified; unverified = not yet checked; not_screened = screen not yet run."},"source":{"type":["string","null"],"description":"Human name of the official source."},"source_url":{"type":["string","null"],"format":"uri"},"verified_at":{"type":["string","null"],"format":"date-time","description":"ISO 8601, or null."}},"required":["status","source","verified_at"]},"ProviderPrice":{"type":"object","description":"Commercial price band. Paid tier only.","properties":{"range":{"type":["string","null"],"description":"Human-readable band, e.g. \"$200–$400/mo\"."},"monthly_min":{"type":["number","null"]},"monthly_max":{"type":["number","null"]},"source":{"type":["string","null"]},"verified_at":{"type":["string","null"],"format":"date-time"}}},"Provider":{"type":"object","description":"Unified provider record. Free-tier responses include only the identity fields; the legitscript/license/fda/price objects are present on the paid tier.","properties":{"entity_id":{"type":"string"},"slug":{"type":"string"},"vertical":{"type":"string","enum":["glp1","pet_health","medspa","ivf","dental","senior"],"description":"glp1 is the verified vertical today; pet_health & medspa are loading, dental & senior queued. Non-live verticals return no data yet."},"publish_tier":{"type":"string","enum":["verified","internal_only"],"description":"Present only in include=tracked responses (self-declaration)."},"name":{"type":"string"},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"business_mode":{"type":"string","enum":["online","physical","both"]},"latitude":{"type":["number","null"]},"longitude":{"type":["number","null"]},"npi":{"type":["string","null"],"description":"NPPES National Provider Identifier, if matched."},"legitscript":{"oneOf":[{"$ref":"#/components/schemas/SourcedSignal"},{"$ref":"#/components/schemas/LockedField"}],"description":"SourcedSignal on a paid key; LockedField on a free key."},"license":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/SourcedSignal"},{"type":"object","properties":{"states_count":{"type":"integer"}}}]},{"$ref":"#/components/schemas/LockedField"}]},"fda":{"oneOf":[{"$ref":"#/components/schemas/SourcedSignal"},{"$ref":"#/components/schemas/LockedField"}]},"oig":{"$ref":"#/components/schemas/OigField"},"price":{"oneOf":[{"$ref":"#/components/schemas/ProviderPrice"},{"$ref":"#/components/schemas/LockedField"}]}},"required":["entity_id","slug","vertical","name","business_mode"]},"LockedField":{"type":"object","description":"A paid field as returned to a FREE key: visible but locked. \"locked\" marks a PAID field — it is NEVER a statement that the provider is verified. Upgrade and the field returns in its real state (verified / clear / flagged / reported / unverified) with source + check date.","properties":{"locked":{"type":"boolean","enum":[true]},"unlock":{"type":"string","description":"How to unlock the field."}},"required":["locked","unlock"]},"OigField":{"oneOf":[{"type":"object","description":"An OIG LEIE exclusion matched by NPI.","properties":{"excluded":{"type":"boolean","enum":[true]},"type":{"type":["string","null"],"description":"LEIE exclusion type, e.g. 1128b8."},"date":{"type":["string","null"],"format":"date"},"source":{"type":"string","example":"oig_leie"},"checked_at":{"type":["string","null"],"format":"date-time"}},"required":["excluded"]},{"type":"object","description":"No NPI-keyed match. NOT a clearance: the LEIE NPI-keys only ~10.5% of its records, so absence of a match says nothing about whether the provider is excluded.","properties":{"npi_match":{"type":"string","enum":["none"]},"note":{"type":"string"}},"required":["npi_match","note"]}]},"IdentityProvider":{"type":"object","description":"L0 identity-layer row (NPPES, all specialties). Identity + free OIG screening. It never carries a verified compliance signal; the vertical fields are returned as locked placeholders. Never read this as the verified tier.","properties":{"npi":{"type":"string"},"name":{"type":"string"},"taxonomy_code":{"type":["string","null"],"description":"NUCC taxonomy code."},"taxonomy_display":{"type":["string","null"],"description":"Human-readable specialty from identity.taxonomy_map (e.g. \"Family Medicine\")."},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"layer":{"type":"string","enum":["identity"]},"source":{"type":"string","enum":["NPPES"]},"checked_at":{"type":["string","null"],"format":"date","description":"NPPES last-update date."},"oig":{"$ref":"#/components/schemas/OigField"},"legitscript":{"$ref":"#/components/schemas/LockedField"},"license":{"$ref":"#/components/schemas/LockedField"},"fda":{"$ref":"#/components/schemas/LockedField"},"price":{"$ref":"#/components/schemas/LockedField"}},"required":["npi","name","layer","source","oig"]},"IdentityListResponse":{"type":"object","description":"Response for the L0 taxonomy path. `layer` is always \"identity\".","properties":{"tier":{"type":"string","enum":["free","paid"]},"plan":{"type":"string","enum":["free","builder","developer","enterprise"]},"layer":{"type":"string","enum":["identity"]},"usage":{"$ref":"#/components/schemas/Usage"},"notice":{"type":"string"},"pagination":{"$ref":"#/components/schemas/Pagination"},"filters":{"type":"object"},"data":{"type":"array","items":{"$ref":"#/components/schemas/IdentityProvider"}}},"required":["layer","pagination","data"]},"Usage":{"type":"object","description":"Present on metered (Builder/Developer) responses only.","properties":{"used":{"type":"integer"},"quota":{"type":"integer"}}},"Pagination":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"returned":{"type":"integer"}}},"ProviderListResponse":{"type":"object","properties":{"tier":{"type":"string","enum":["free","paid"]},"plan":{"type":"string","enum":["free","builder","developer","enterprise"]},"publish_boundary":{"type":"string","enum":["verified","tracked"]},"usage":{"$ref":"#/components/schemas/Usage"},"notice":{"type":"string"},"pagination":{"$ref":"#/components/schemas/Pagination"},"filters":{"type":"object"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Provider"}}},"required":["tier","plan","publish_boundary","pagination","data"]},"ProviderDetailResponse":{"type":"object","properties":{"tier":{"type":"string","enum":["free","paid"]},"plan":{"type":"string","enum":["free","builder","developer","enterprise"]},"publish_boundary":{"type":"string","enum":["verified","tracked"]},"usage":{"$ref":"#/components/schemas/Usage"},"notice":{"type":"string"},"data":{"$ref":"#/components/schemas/Provider"}},"required":["tier","plan","publish_boundary","data"]},"SampleResponse":{"type":"object","properties":{"sample":{"type":"boolean"},"size":{"type":"integer"},"schema":{"type":"string","enum":["paid"]},"publish_boundary":{"type":"string","enum":["verified"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Provider"}}}},"SignalCounts":{"type":"object","properties":{"legitscript_verified":{"type":"integer"},"license_on_file":{"type":"integer"},"fda_screened":{"type":"integer"},"npi_present":{"type":"integer"},"price_published":{"type":"integer"}}},"CoverageSlice":{"type":"object","properties":{"total":{"type":"integer"},"states":{"type":"integer"},"cities":{"type":"integer"},"business_mode":{"type":"object","properties":{"online":{"type":"integer"},"physical":{"type":"integer"},"both":{"type":"integer"}}},"by_state":{"type":"array","items":{"type":"object","properties":{"state":{"type":"string"},"count":{"type":"integer"}}}},"signals":{"$ref":"#/components/schemas/SignalCounts"}}},"CoverageStats":{"type":"object","properties":{"tracked":{"$ref":"#/components/schemas/CoverageSlice"},"verified":{"$ref":"#/components/schemas/CoverageSlice"},"identity_layer":{"type":"object","description":"L0 horizontal identity layer (NPPES, all specialties). Present when available. Counts grow as the nationwide roll-out proceeds.","properties":{"total":{"type":"integer"},"states":{"type":"integer"},"taxonomies":{"type":"integer"}}},"verticals_live":{"type":"integer"},"generated_at":{"type":"string","format":"date-time","description":"Snapshot time — cite this as \"data as of\"."}},"required":["tracked","verified","generated_at"]},"Error":{"type":"object","description":"Uniform error envelope. `code` is a stable machine-readable identifier; `error` is the human message. 5xx responses always use code \"internal_error\" and never leak internal detail.","properties":{"error":{"type":"string","description":"Human-readable message."},"code":{"type":"string","description":"Stable error code: key_required, invalid_key, invalid_vertical, invalid_business_mode, invalid_limit, invalid_offset, vertical_not_permitted, quota_exceeded, not_found, internal_error."},"hint":{"type":"string"},"upgrade":{"type":"string"},"plan":{"type":"string"},"usage":{"$ref":"#/components/schemas/Usage"}},"required":["error","code"]}},"responses":{"BadRequest":{"description":"Invalid parameter — codes: invalid_vertical, invalid_business_mode, invalid_limit, invalid_offset (a non-integer/negative offset, or one beyond the result set).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"code \"key_required\": no key was supplied — every provider call needs one; get a free key in 30 seconds at /developers/signup. code \"invalid_key\": the key is not recognised (rotated/revoked).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Your plan does not permit this (e.g. a Builder key requesting a vertical it is not bound to).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"No active provider matches.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Monthly call quota reached. Retry after the reset, or upgrade.","headers":{"X-RateLimit-Limit":{"description":"Your plan’s monthly call quota. Present on metered (Builder/Developer) responses only.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left in the current UTC month.","schema":{"type":"integer"}},"X-RateLimit-Used":{"description":"Calls used so far this month, including this one.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the quota resets (00:00 UTC on the 1st of next month).","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds until the monthly quota resets (00:00 UTC on the 1st).","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"ServerError":{"description":"Query failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}