{"openapi":"3.1.0","info":{"title":"GeoHealth Context API","summary":"Census-tract-level geographic health intelligence","description":"Census-tract-level geographic health intelligence API.\n\nGiven a street address or lat/lng coordinates, returns **demographics**,\n**CDC/ATSDR Social Vulnerability Index (SVI) themes**,\n**CDC PLACES health outcome measures**, and an optional\n**AI-generated narrative** for the surrounding census tract.\n\n### Data resolution\n\nAll data is resolved to the **census tract** level (~4,000 residents per\ntract on average). Coordinates are matched to tracts via PostGIS spatial\nqueries or FIPS-code lookups from the Census Bureau geocoder.\n\n### Authentication\n\nMost endpoints require an API key passed via the `X-API-Key` header.\nSee the *Authentication* section in the README for details on key\nmanagement and SHA-256 pre-hashing.\n\n### Rate limiting\n\nRequests are rate-limited per API key using a sliding window.\nEvery response includes `X-RateLimit-Limit`, `X-RateLimit-Remaining`,\nand `X-RateLimit-Reset` headers.\n","contact":{"name":"GeoHealth API","url":"https://github.com/RussellStover1983/geohealth-api"},"license":{"name":"MIT","identifier":"MIT"},"version":"0.1.0"},"paths":{"/v1/context":{"get":{"tags":["context"],"summary":"Look up health context for a location","description":"Resolve a street address **or** lat/lng coordinates to the surrounding census tract and return demographics, SVI themes, CDC PLACES health measures, and an optional AI-generated narrative.\n\nSupply **either** `address` **or** both `lat` and `lng`. When an address is provided it is geocoded via the Census Bureau (with Nominatim fallback). Results are cached by coordinates rounded to 4 decimal places (~11 m).","operationId":"get_context_v1_context_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"address","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"description":"Street address to geocode","title":"Address"},"description":"Street address to geocode"},{"name":"lat","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":90,"minimum":-90},{"type":"null"}],"description":"Latitude (if no address)","title":"Lat"},"description":"Latitude (if no address)"},{"name":"lng","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":180,"minimum":-180},{"type":"null"}],"description":"Longitude (if no address)","title":"Lng"},"description":"Longitude (if no address)"},{"name":"narrative","in":"query","required":false,"schema":{"type":"boolean","description":"Generate LLM narrative summary","default":false,"title":"Narrative"},"description":"Generate LLM narrative summary"},{"name":"format","in":"query","required":false,"schema":{"type":"string","description":"Response format","default":"json","title":"Format"},"description":"Response format"},{"name":"context","in":"query","required":false,"schema":{"type":"string","description":"Context sections to include","default":"full","title":"Context"},"description":"Context sections to include"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContextResponse"}}}},"400":{"description":"Missing or invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/stats":{"get":{"tags":["stats"],"summary":"Data loading statistics","description":"Return a paginated summary of loaded census tract data: total states, total tracts, and a per-state breakdown ordered by state FIPS code.","operationId":"get_stats_v1_stats_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of state rows to skip","default":0,"title":"Offset"},"description":"Number of state rows to skip"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"exclusiveMinimum":0,"description":"Max state rows to return","default":50,"title":"Limit"},"description":"Max state rows to return"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatsResponse"}}}},"401":{"description":"Missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/batch":{"post":{"tags":["batch"],"summary":"Batch address lookup","description":"Submit multiple street addresses in a single request and receive per-address census tract data. Each address is geocoded and looked up concurrently. The request counts as **one** rate-limit hit.\n\nThe maximum number of addresses per request is controlled by the `BATCH_MAX_SIZE` setting (default 50).","operationId":"post_batch_v1_batch_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchResponse"}}}},"400":{"description":"Too many addresses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"APIKeyHeader":[]}]}},"/v1/nearby":{"get":{"tags":["nearby"],"summary":"Find nearby census tracts","description":"Return census tracts within a given radius of a point, sorted by distance (nearest first). Uses PostGIS `ST_DWithin` for efficient spatial filtering.\n\nResults are paginated via `offset` and `limit`. The response includes `total` (all matching tracts) and `count` (tracts in the current page).","operationId":"get_nearby_v1_nearby_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"lat","in":"query","required":true,"schema":{"type":"number","maximum":90,"minimum":-90,"description":"Latitude of center point","title":"Lat"},"description":"Latitude of center point"},{"name":"lng","in":"query","required":true,"schema":{"type":"number","maximum":180,"minimum":-180,"description":"Longitude of center point","title":"Lng"},"description":"Longitude of center point"},{"name":"radius","in":"query","required":false,"schema":{"type":"number","maximum":50,"exclusiveMinimum":0,"description":"Radius in miles (max 50)","default":5.0,"title":"Radius"},"description":"Radius in miles (max 50)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"exclusiveMinimum":0,"description":"Max results (max 100)","default":25,"title":"Limit"},"description":"Max results (max 100)"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of rows to skip","default":0,"title":"Offset"},"description":"Number of rows to skip"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NearbyResponse"}}}},"401":{"description":"Missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/compare":{"get":{"tags":["compare"],"summary":"Compare census tracts","description":"Compare two census tracts side-by-side, or compare a single tract against county, state, or national averages.\n\nProvide `geoid1` (required) plus **either** `geoid2` (a second tract) **or** `compare_to` (`county`, `state`, or `national`). The response includes both sides' values and the computed differences (A - B).","operationId":"get_compare_v1_compare_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"geoid1","in":"query","required":true,"schema":{"type":"string","minLength":11,"maxLength":11,"description":"First tract GEOID (11 chars)","title":"Geoid1"},"description":"First tract GEOID (11 chars)"},{"name":"geoid2","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":11,"maxLength":11},{"type":"null"}],"description":"Second tract GEOID (11 chars)","title":"Geoid2"},"description":"Second tract GEOID (11 chars)"},{"name":"compare_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Compare to 'state' or 'national' average","title":"Compare To"},"description":"Compare to 'state' or 'national' average"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompareResponse"}}}},"400":{"description":"Invalid parameter combination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Tract not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/dictionary":{"get":{"tags":["dictionary"],"summary":"Data dictionary — field definitions with clinical context","description":"Returns structured metadata about every data field the API provides, including data type, source, clinical relevance, and interpretation guidance. Use this to understand what the data means before querying.","operationId":"get_dictionary_v1_dictionary_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by category: demographics, vulnerability, health_outcomes, or composite","title":"Category"},"description":"Filter by category: demographics, vulnerability, health_outcomes, or composite"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DictionaryResponse"}}}},"401":{"description":"Missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/trends":{"get":{"tags":["trends"],"summary":"Get historical trends for a tract","description":"Returns historical ACS demographic data for a census tract across multiple years, with computed change metrics.\n\nTrend data must be loaded via the ETL pipeline. If no trend data exists, the response will contain only the current-year snapshot.","operationId":"get_trends_v1_trends_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"geoid","in":"query","required":true,"schema":{"type":"string","minLength":11,"maxLength":11,"description":"11-digit tract GEOID","title":"Geoid"},"description":"11-digit tract GEOID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrendsResponse"}}}},"401":{"description":"Missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Tract not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/demographics/compare":{"get":{"tags":["demographics"],"summary":"Demographic comparison with rankings","description":"Compare a census tract's demographics against county, state, and national averages. Includes percentile rankings showing where the tract falls relative to peers at each geographic level.\n\nPercentiles are computed over all tracts with non-null data for each metric. A percentile of 80 means the tract ranks higher than 80% of tracts in that scope.","operationId":"get_demographic_compare_v1_demographics_compare_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"geoid","in":"query","required":true,"schema":{"type":"string","minLength":11,"maxLength":11,"description":"11-digit tract GEOID","title":"Geoid"},"description":"11-digit tract GEOID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DemographicCompareResponse"}}}},"401":{"description":"Missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Tract not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/webhooks":{"get":{"tags":["webhooks"],"summary":"List webhook subscriptions","description":"List all webhook subscriptions for the authenticated API key.","operationId":"list_webhooks_v1_webhooks_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookListResponse"}}}},"401":{"description":"Missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"APIKeyHeader":[]}]},"post":{"tags":["webhooks"],"summary":"Create a webhook subscription","description":"Register a callback URL to receive notifications when data changes or metric thresholds are exceeded.\n\n**Events**:\n- `data.updated` — fired when ETL refreshes tract data\n- `threshold.exceeded` — fired when a metric crosses a defined threshold\n\n**Filters** (optional):\n- `state_fips` — list of state FIPS codes to monitor\n- `geoids` — list of specific tract GEOIDs\n- `thresholds` — dict of metric thresholds, e.g. `{\"poverty_rate\": {\"operator\": \">\", \"value\": 20}}`","operationId":"create_webhook_v1_webhooks_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid event type or limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]}]}},"/v1/webhooks/{webhook_id}":{"get":{"tags":["webhooks"],"summary":"Get a webhook subscription","description":"Get details of a specific webhook subscription.","operationId":"get_webhook_v1_webhooks__webhook_id__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"webhook_id","in":"path","required":true,"schema":{"type":"integer","description":"Webhook subscription ID","title":"Webhook Id"},"description":"Webhook subscription ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"401":{"description":"Missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["webhooks"],"summary":"Delete a webhook subscription","description":"Permanently delete a webhook subscription.","operationId":"delete_webhook_v1_webhooks__webhook_id__delete","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"webhook_id","in":"path","required":true,"schema":{"type":"integer","description":"Webhook subscription ID","title":"Webhook Id"},"description":"Webhook subscription ID"}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tracts/geojson":{"get":{"tags":["geojson"],"summary":"Tract boundaries as GeoJSON","description":"Return census tract boundaries as a GeoJSON FeatureCollection for map rendering. Each Feature includes the tract polygon geometry and SDOH metrics as properties.\n\nFilter by `state_fips` or by spatial radius around a point (`lat`, `lng`, `radius`). At least one filter is required to avoid returning all tracts.","operationId":"get_tracts_geojson_v1_tracts_geojson_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"state_fips","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"2-digit state FIPS code","title":"State Fips"},"description":"2-digit state FIPS code"},{"name":"lat","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":90,"minimum":-90},{"type":"null"}],"description":"Center latitude (for radius filter)","title":"Lat"},"description":"Center latitude (for radius filter)"},{"name":"lng","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":180,"minimum":-180},{"type":"null"}],"description":"Center longitude (for radius filter)","title":"Lng"},"description":"Center longitude (for radius filter)"},{"name":"radius","in":"query","required":false,"schema":{"type":"number","maximum":50,"exclusiveMinimum":0,"description":"Radius in miles (max 50, used with lat/lng)","default":10.0,"title":"Radius"},"description":"Radius in miles (max 50, used with lat/lng)"},{"name":"simplify","in":"query","required":false,"schema":{"type":"number","maximum":0.01,"minimum":0,"description":"Geometry simplification tolerance (0=full detail, 0.001=moderate)","default":0.0,"title":"Simplify"},"description":"Geometry simplification tolerance (0=full detail, 0.001=moderate)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"exclusiveMinimum":0,"description":"Max tracts to return (max 2000)","default":500,"title":"Limit"},"description":"Max tracts to return (max 2000)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"401":{"description":"Missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/providers/geojson":{"get":{"tags":["providers"],"summary":"NPI providers as GeoJSON","description":"Return NPI providers as a GeoJSON FeatureCollection with Point geometries for map rendering. Filter by bounding box (required) and optionally by provider type.\n\nProvider types: `pcp`, `fqhc`, `urgent_care`, `rural_health_clinic`, `primary_care_clinic`, `community_health_center`, or `all` (default).","operationId":"get_providers_geojson_v1_providers_geojson_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"bbox","in":"query","required":true,"schema":{"type":"string","description":"Bounding box as west,south,east,north (comma-separated)","title":"Bbox"},"description":"Bounding box as west,south,east,north (comma-separated)"},{"name":"provider_type","in":"query","required":false,"schema":{"type":"string","description":"Filter by provider type: all, pcp, fqhc, urgent_care, etc.","default":"all","title":"Provider Type"},"description":"Filter by provider type: all, pcp, fqhc, urgent_care, etc."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"exclusiveMinimum":0,"description":"Max providers (max 2000)","default":500,"title":"Limit"},"description":"Max providers (max 2000)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"}}}},"/v1/providers":{"get":{"tags":["providers"],"summary":"Search NPI providers","description":"Search for NPI providers by radius around a point or by census tract FIPS code. Returns a paginated JSON list with distance when querying by radius.\n\nProvider types: `pcp`, `fqhc`, `urgent_care`, `rural_health_clinic`, `primary_care_clinic`, `community_health_center`, or `all` (default).","operationId":"get_providers_v1_providers_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"lat","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":90,"minimum":-90},{"type":"null"}],"description":"Center latitude","title":"Lat"},"description":"Center latitude"},{"name":"lng","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":180,"minimum":-180},{"type":"null"}],"description":"Center longitude","title":"Lng"},"description":"Center longitude"},{"name":"radius","in":"query","required":false,"schema":{"type":"number","maximum":50,"exclusiveMinimum":0,"description":"Radius in miles (max 50)","default":5.0,"title":"Radius"},"description":"Radius in miles (max 50)"},{"name":"tract_fips","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"11-digit census tract FIPS","title":"Tract Fips"},"description":"11-digit census tract FIPS"},{"name":"provider_type","in":"query","required":false,"schema":{"type":"string","description":"Filter by provider type","default":"all","title":"Provider Type"},"description":"Filter by provider type"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"exclusiveMinimum":0,"description":"Max results (max 500)","default":50,"title":"Limit"},"description":"Max results (max 500)"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Offset for pagination","default":0,"title":"Offset"},"description":"Offset for pagination"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvidersResponse"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"}}}},"/health":{"get":{"tags":["system"],"summary":"Health check","description":"Check API and database connectivity. Returns 200 when healthy, 503 when the database is unreachable.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"503":{"description":"Database unreachable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/metrics":{"get":{"tags":["system"],"summary":"Application metrics","description":"Returns application metrics including request counters, latency percentiles, cache stats, and geocoder/narrative success rates.","operationId":"get_metrics_metrics_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/llms.txt":{"get":{"tags":["system"],"summary":"Agent-readable API overview (llmstxt.org)","description":"Concise plain-text documentation for LLMs and coding agents.","operationId":"llms_txt_llms_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/llms-full.txt":{"get":{"tags":["system"],"summary":"Full agent-readable API reference (llmstxt.org)","description":"Complete plain-text documentation with clinical context, field reference, SDK examples, and MCP setup instructions.","operationId":"llms_full_txt_llms_full_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}}},"components":{"schemas":{"BatchRequest":{"properties":{"addresses":{"items":{"type":"string"},"type":"array","maxItems":100,"minItems":1,"title":"Addresses","description":"List of street addresses to geocode and look up"}},"type":"object","required":["addresses"],"title":"BatchRequest"},"BatchResponse":{"properties":{"total":{"type":"integer","title":"Total","description":"Total number of addresses submitted"},"succeeded":{"type":"integer","title":"Succeeded","description":"Number of addresses successfully resolved"},"failed":{"type":"integer","title":"Failed","description":"Number of addresses that failed"},"results":{"items":{"$ref":"#/components/schemas/BatchResultItem"},"type":"array","title":"Results","description":"Per-address results in submission order"}},"type":"object","required":["total","succeeded","failed","results"],"title":"BatchResponse","description":"Aggregated results for a batch address lookup."},"BatchResultItem":{"properties":{"address":{"type":"string","title":"Address","description":"Original input address"},"status":{"type":"string","title":"Status","description":"Result status: 'ok' or 'error'"},"location":{"anyOf":[{"$ref":"#/components/schemas/BatchResultLocation"},{"type":"null"}],"description":"Geocoded location (null on error)"},"tract":{"anyOf":[{"$ref":"#/components/schemas/TractDataModel"},{"type":"null"}],"description":"Census tract data (null on error)"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Error message (null on success)"}},"type":"object","required":["address","status"],"title":"BatchResultItem","description":"Result for a single address in a batch request."},"BatchResultLocation":{"properties":{"lat":{"type":"number","title":"Lat","description":"Latitude of the matched location"},"lng":{"type":"number","title":"Lng","description":"Longitude of the matched location"},"matched_address":{"type":"string","title":"Matched Address","description":"Address string as matched by the geocoder"}},"type":"object","required":["lat","lng","matched_address"],"title":"BatchResultLocation","description":"Geocoded location for a single batch result."},"CacheHealth":{"properties":{"size":{"type":"integer","title":"Size","description":"Current number of cached entries"},"max_size":{"type":"integer","title":"Max Size","description":"Maximum cache capacity"},"hit_rate":{"type":"number","title":"Hit Rate","description":"Cache hit rate (0.0–1.0)"}},"type":"object","required":["size","max_size","hit_rate"],"title":"CacheHealth","description":"Cache subsystem status."},"CompareDifferences":{"properties":{"total_population":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Population","description":"Population difference (A - B)"},"median_household_income":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median Household Income","description":"Income difference (A - B)"},"poverty_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Poverty Rate","description":"Poverty rate difference (A - B)"},"uninsured_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Uninsured Rate","description":"Uninsured rate difference (A - B)"},"unemployment_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Unemployment Rate","description":"Unemployment rate difference (A - B)"},"median_age":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median Age","description":"Median age difference (A - B)"},"sdoh_index":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Sdoh Index","description":"SDOH index difference (A - B)"}},"type":"object","title":"CompareDifferences","description":"Difference (A minus B) for each compared metric."},"CompareResponse":{"properties":{"a":{"$ref":"#/components/schemas/CompareSide","description":"First entity (the tract)"},"b":{"$ref":"#/components/schemas/CompareSide","description":"Second entity (tract or average)"},"differences":{"$ref":"#/components/schemas/CompareDifferences","description":"A minus B for each metric"}},"type":"object","required":["a","b","differences"],"title":"CompareResponse","description":"Side-by-side comparison of two entities with computed differences."},"CompareSide":{"properties":{"type":{"type":"string","title":"Type","description":"Entity type: 'tract', 'county_average', 'state_average', or 'national_average'"},"geoid":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Geoid","description":"Tract GEOID (null for averages)"},"label":{"type":"string","title":"Label","description":"Human-readable label for this side"},"values":{"$ref":"#/components/schemas/CompareValues","description":"Numeric values for this entity"}},"type":"object","required":["type","label","values"],"title":"CompareSide","description":"One side (A or B) of a comparison."},"CompareValues":{"properties":{"total_population":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Population","description":"Total population (or average)"},"median_household_income":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median Household Income","description":"Median household income in dollars. Below $30,000 = high risk."},"poverty_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Poverty Rate","description":"Poverty rate %. Above 20% = high-poverty area."},"uninsured_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Uninsured Rate","description":"Uninsured rate %. Above 15% = significant access barriers."},"unemployment_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Unemployment Rate","description":"Unemployment rate %. Above 10% = economic distress."},"median_age":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median Age","description":"Median age of the population"},"sdoh_index":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Sdoh Index","description":"Composite SDOH index (0-1). Above 0.6 = high vulnerability."}},"type":"object","title":"CompareValues","description":"Numeric values used in a tract comparison."},"ContextResponse":{"properties":{"location":{"$ref":"#/components/schemas/LocationModel","description":"Geocoded coordinates and matched address"},"tract":{"anyOf":[{"$ref":"#/components/schemas/TractDataModel"},{"type":"null"}],"description":"Census tract profile for the location"},"narrative":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Narrative","description":"AI-generated narrative summary of the tract data (only when narrative=true)"},"data":{"anyOf":[{"$ref":"#/components/schemas/TractDataModel"},{"type":"null"}],"description":"Alias for tract (deprecated, use 'tract' instead)"}},"type":"object","required":["location"],"title":"ContextResponse","description":"Primary response for a geographic health context lookup."},"DemographicAverages":{"properties":{"metric":{"type":"string","title":"Metric","description":"Metric name"},"tract_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Tract Value","description":"This tract's value"},"county_avg":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"County Avg","description":"County average"},"state_avg":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"State Avg","description":"State average"},"national_avg":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"National Avg","description":"National average"}},"type":"object","required":["metric"],"title":"DemographicAverages","description":"Average values at county, state, and national levels."},"DemographicCompareResponse":{"properties":{"geoid":{"type":"string","title":"Geoid","description":"11-digit census tract GEOID"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Tract name"},"state_fips":{"type":"string","title":"State Fips","description":"2-digit state FIPS"},"county_fips":{"type":"string","title":"County Fips","description":"3-digit county FIPS"},"rankings":{"items":{"$ref":"#/components/schemas/DemographicRanking"},"type":"array","title":"Rankings","description":"Percentile rankings at county, state, and national levels"},"averages":{"items":{"$ref":"#/components/schemas/DemographicAverages"},"type":"array","title":"Averages","description":"Tract value vs county, state, and national averages"}},"type":"object","required":["geoid","state_fips","county_fips","rankings","averages"],"title":"DemographicCompareResponse","description":"Comprehensive demographic comparison with rankings and averages."},"DemographicRanking":{"properties":{"metric":{"type":"string","title":"Metric","description":"Metric name"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value","description":"Tract value"},"county_percentile":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"County Percentile","description":"Percentile rank within county (0-100)"},"state_percentile":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"State Percentile","description":"Percentile rank within state (0-100)"},"national_percentile":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"National Percentile","description":"Percentile rank nationally (0-100)"}},"type":"object","required":["metric"],"title":"DemographicRanking","description":"Percentile ranking of a metric within a geographic scope."},"DictionaryCategory":{"properties":{"category":{"type":"string","title":"Category","description":"Category name"},"description":{"type":"string","title":"Description","description":"What this category covers"},"source":{"type":"string","title":"Source","description":"Primary data source for this category"},"fields":{"items":{"$ref":"#/components/schemas/FieldDefinition"},"type":"array","title":"Fields","description":"Fields in this category"}},"type":"object","required":["category","description","source","fields"],"title":"DictionaryCategory","description":"A group of related fields."},"DictionaryResponse":{"properties":{"total_fields":{"type":"integer","title":"Total Fields","description":"Total number of defined fields"},"categories":{"items":{"$ref":"#/components/schemas/DictionaryCategory"},"type":"array","title":"Categories","description":"Fields grouped by category"}},"type":"object","required":["total_fields","categories"],"title":"DictionaryResponse","description":"Complete data dictionary with field definitions and clinical context."},"ErrorResponse":{"properties":{"error":{"type":"boolean","title":"Error","description":"Always true for error responses","default":true},"status_code":{"type":"integer","title":"Status Code","description":"HTTP status code"},"detail":{"type":"string","title":"Detail","description":"Human-readable error message"}},"type":"object","required":["status_code","detail"],"title":"ErrorResponse","description":"Structured error returned by all non-2xx responses."},"FieldDefinition":{"properties":{"name":{"type":"string","title":"Name","description":"Field name as it appears in API responses"},"type":{"type":"string","title":"Type","description":"Data type: float, int, str, dict"},"source":{"type":"string","title":"Source","description":"Data source: ACS, SVI, PLACES, computed, census"},"category":{"type":"string","title":"Category","description":"Category: identity, demographics, vulnerability, health_outcomes, composite"},"description":{"type":"string","title":"Description","description":"What this field measures"},"clinical_relevance":{"type":"string","title":"Clinical Relevance","description":"Why this matters for clinical or public-health decisions"},"unit":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unit","description":"Unit of measurement (%, dollars, years, 0-1 scale)"},"typical_range":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Typical Range","description":"Typical range of values"},"example_value":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}],"title":"Example Value","description":"Example value"}},"type":"object","required":["name","type","source","category","description","clinical_relevance"],"title":"FieldDefinition","description":"Metadata about a single data field returned by the API."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthResponse":{"properties":{"status":{"type":"string","title":"Status","description":"Overall status: 'ok' or 'degraded'"},"database":{"type":"string","title":"Database","description":"Database connectivity: 'connected' or 'unreachable'"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detail","description":"Error detail when database is unreachable"},"cache":{"anyOf":[{"$ref":"#/components/schemas/CacheHealth"},{"type":"null"}],"description":"Cache subsystem health (present when status is ok)"},"rate_limiter":{"anyOf":[{"$ref":"#/components/schemas/RateLimiterHealth"},{"type":"null"}],"description":"Rate limiter health (present when status is ok)"},"uptime_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Uptime Seconds","description":"Seconds since the process started"}},"type":"object","required":["status","database"],"title":"HealthResponse","description":"Health-check result indicating API and database status."},"LocationModel":{"properties":{"lat":{"type":"number","title":"Lat","description":"Latitude of the matched location"},"lng":{"type":"number","title":"Lng","description":"Longitude of the matched location"},"matched_address":{"type":"string","title":"Matched Address","description":"Address string as matched by the geocoder"}},"type":"object","required":["lat","lng","matched_address"],"title":"LocationModel","description":"Geocoded location returned with every context lookup."},"NearbyCenter":{"properties":{"lat":{"type":"number","title":"Lat","description":"Latitude of the center point"},"lng":{"type":"number","title":"Lng","description":"Longitude of the center point"}},"type":"object","required":["lat","lng"],"title":"NearbyCenter","description":"Center point used for the nearby search."},"NearbyResponse":{"properties":{"center":{"$ref":"#/components/schemas/NearbyCenter","description":"Center point of the search"},"radius_miles":{"type":"number","title":"Radius Miles","description":"Search radius in miles"},"count":{"type":"integer","title":"Count","description":"Number of tracts in this page"},"total":{"type":"integer","title":"Total","description":"Total tracts within the radius"},"offset":{"type":"integer","title":"Offset","description":"Number of rows skipped"},"limit":{"type":"integer","title":"Limit","description":"Maximum rows returned per page"},"tracts":{"items":{"$ref":"#/components/schemas/NearbyTract"},"type":"array","title":"Tracts","description":"Tracts sorted by distance (nearest first)"}},"type":"object","required":["center","radius_miles","count","total","offset","limit","tracts"],"title":"NearbyResponse","description":"Paginated list of census tracts within a radius."},"NearbyTract":{"properties":{"geoid":{"type":"string","title":"Geoid","description":"11-digit census tract GEOID"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Human-readable tract name"},"distance_miles":{"type":"number","title":"Distance Miles","description":"Distance from center point in miles"},"total_population":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Population","description":"ACS total population estimate"},"median_household_income":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median Household Income","description":"ACS median household income in dollars. Below $30,000 correlates with higher chronic disease rates."},"poverty_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Poverty Rate","description":"Percentage below federal poverty level (ACS). Above 20% indicates high-poverty area."},"uninsured_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Uninsured Rate","description":"Percentage without health insurance (ACS). Above 15% suggests significant access barriers."},"unemployment_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Unemployment Rate","description":"Percentage of labor force unemployed (ACS). Above 10% indicates economic distress."},"median_age":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median Age","description":"Median age of the population (ACS)"},"sdoh_index":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Sdoh Index","description":"Composite SDOH index (0-1). Above 0.6 indicates high social vulnerability."}},"type":"object","required":["geoid","distance_miles"],"title":"NearbyTract","description":"Census tract within the search radius, with distance."},"ProviderModel":{"properties":{"npi":{"type":"string","title":"Npi","description":"10-digit National Provider Identifier"},"entity_type":{"type":"string","title":"Entity Type","description":"1=individual provider, 2=organization"},"provider_name":{"type":"string","title":"Provider Name","description":"Provider or organization name"},"credential":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Credential","description":"Credential (MD, DO, NP, etc.)"},"gender":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Gender","description":"M or F (individuals only)"},"primary_taxonomy":{"type":"string","title":"Primary Taxonomy","description":"Primary taxonomy code (e.g., 207Q00000X)"},"taxonomy_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Taxonomy Description","description":"Human-readable taxonomy description"},"provider_type":{"type":"string","title":"Provider Type","description":"Classification: pcp, fqhc, urgent_care, rural_health_clinic, etc."},"practice_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Practice Address","description":"Street address"},"practice_city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Practice City","description":"City"},"practice_state":{"type":"string","title":"Practice State","description":"2-letter state code"},"practice_zip":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Practice Zip","description":"5-digit ZIP code"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone","description":"Practice phone number"},"is_fqhc":{"type":"boolean","title":"Is Fqhc","description":"True if provider is a Federally Qualified Health Center"},"tract_fips":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tract Fips","description":"11-digit census tract FIPS code"},"lat":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lat","description":"Latitude"},"lng":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lng","description":"Longitude"},"distance_miles":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Distance Miles","description":"Distance from search center (radius queries only)"}},"type":"object","required":["npi","entity_type","provider_name","primary_taxonomy","provider_type","practice_state","is_fqhc"],"title":"ProviderModel","description":"Individual NPI provider record."},"ProvidersResponse":{"properties":{"count":{"type":"integer","title":"Count","description":"Number of providers in this page"},"total":{"type":"integer","title":"Total","description":"Total matching providers"},"offset":{"type":"integer","title":"Offset","description":"Number of rows skipped"},"limit":{"type":"integer","title":"Limit","description":"Maximum rows per page"},"providers":{"items":{"$ref":"#/components/schemas/ProviderModel"},"type":"array","title":"Providers","description":"Provider records"}},"type":"object","required":["count","total","offset","limit","providers"],"title":"ProvidersResponse","description":"Paginated list of NPI providers."},"RateLimiterHealth":{"properties":{"active_keys":{"type":"integer","title":"Active Keys","description":"Number of tracked API key buckets"}},"type":"object","required":["active_keys"],"title":"RateLimiterHealth","description":"Rate limiter subsystem status."},"StateCount":{"properties":{"state_fips":{"type":"string","title":"State Fips","description":"2-digit state FIPS code"},"tract_count":{"type":"integer","title":"Tract Count","description":"Number of loaded census tracts"}},"type":"object","required":["state_fips","tract_count"],"title":"StateCount","description":"Tract count for a single state."},"StatsResponse":{"properties":{"total_states":{"type":"integer","title":"Total States","description":"Total number of states with loaded data"},"total_tracts":{"type":"integer","title":"Total Tracts","description":"Total number of loaded census tracts across all states"},"offset":{"type":"integer","title":"Offset","description":"Number of state rows skipped"},"limit":{"type":"integer","title":"Limit","description":"Maximum state rows returned per page"},"states":{"items":{"$ref":"#/components/schemas/StateCount"},"type":"array","title":"States","description":"Per-state tract counts"}},"type":"object","required":["total_states","total_tracts","offset","limit","states"],"title":"StatsResponse","description":"Paginated summary of loaded data by state."},"TractDataModel":{"properties":{"geoid":{"type":"string","title":"Geoid","description":"11-digit census tract GEOID (state + county + tract)"},"state_fips":{"type":"string","title":"State Fips","description":"2-digit state FIPS code"},"county_fips":{"type":"string","title":"County Fips","description":"3-digit county FIPS code"},"tract_code":{"type":"string","title":"Tract Code","description":"6-digit census tract code"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Human-readable tract name"},"total_population":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Population","description":"ACS total population estimate. Small populations (under 1,000) produce less reliable rate estimates."},"median_household_income":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median Household Income","description":"ACS median household income in dollars. Incomes below $30,000 correlate with higher chronic disease rates and delayed care-seeking."},"poverty_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Poverty Rate","description":"Percentage of population below the federal poverty level (ACS). Rates above 20% indicate high-poverty areas associated with increased chronic disease burden and reduced healthcare access."},"uninsured_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Uninsured Rate","description":"Percentage of population without health insurance (ACS). Rates above 15% suggest significant access barriers and delayed preventive care."},"unemployment_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Unemployment Rate","description":"Percentage of civilian labor force unemployed (ACS). Rates above 10% indicate economic distress, associated with depression and substance use."},"median_age":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median Age","description":"Median age of the population (ACS). Tracts above 45 may have higher chronic disease prevalence; tracts below 25 may indicate student populations."},"svi_themes":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Svi Themes","description":"CDC/ATSDR Social Vulnerability Index theme percentile rankings (0-1). Keys: rpl_theme1 (socioeconomic), rpl_theme2 (household/disability), rpl_theme3 (minority/language), rpl_theme4 (housing/transportation), rpl_themes (overall). Percentiles above 0.75 indicate high vulnerability relative to all US census tracts."},"places_measures":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Places Measures","description":"CDC PLACES health outcome measures (crude prevalence %). Model-based estimates from BRFSS. Keys: diabetes, obesity, mhlth (mental health), phlth (physical health), bphigh (blood pressure), casthma (asthma), chd (coronary heart disease), csmoking (smoking), access2 (no insurance), checkup, dental, sleep (short sleep), lpa (physical inactivity), binge (binge drinking)."},"sdoh_index":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Sdoh Index","description":"Composite social determinants of health index (0-1 scale). Computed from poverty, uninsured, unemployment rates and SVI. Values above 0.6 indicate high social vulnerability warranting intensive care coordination."},"epa_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Epa Data","description":"EPA EJScreen environmental indicators. Keys may include: pm25 (fine particulate matter ug/m3), ozone (ppb), diesel_pm (ug/m3), air_toxics_cancer_risk (per million), respiratory_hazard_index, traffic_proximity (vehicles/day/distance), lead_paint_pct (% pre-1960 housing), superfund_proximity, rmp_proximity, hazardous_waste_proximity, wastewater_discharge. Higher values indicate greater environmental burden. The _source field indicates data origin: 'ejscreen_api' (real EPA data) or 'estimated' (modeled from SVI/poverty correlation)."}},"additionalProperties":true,"type":"object","required":["geoid","state_fips","county_fips","tract_code"],"title":"TractDataModel","description":"Census tract profile with demographics, SVI themes, and health measures.\n\nFixed ACS columns are always present. JSONB-backed fields (`svi_themes`,\n`places_measures`) contain nested dictionaries whose keys may grow over\ntime without requiring schema changes. The model uses `extra = \"allow\"`\nso new fields flow through automatically.","examples":[{"county_fips":"053","epa_data":{"air_toxics_cancer_risk":28.0,"diesel_pm":0.31,"lead_paint_pct":0.42,"ozone":42.1,"pm25":8.2},"geoid":"27053026200","median_age":34.7,"median_household_income":72500.0,"name":"Census Tract 262, Hennepin County, MN","places_measures":{"binge":18.6,"csmoking":15.1,"diabetes":9.1,"lpa":22.3,"mhlth":14.7,"obesity":28.4,"sleep":35.2},"poverty_rate":11.3,"sdoh_index":0.41,"state_fips":"27","svi_themes":{"rpl_theme1":0.35,"rpl_theme2":0.42,"rpl_theme3":0.61,"rpl_theme4":0.28,"rpl_themes":0.44},"total_population":4521,"tract_code":"026200","unemployment_rate":4.2,"uninsured_rate":5.8}]},"TrendChange":{"properties":{"metric":{"type":"string","title":"Metric","description":"Metric name"},"earliest_year":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Earliest Year","description":"First year with data"},"latest_year":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Latest Year","description":"Last year with data"},"earliest_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Earliest Value","description":"Value in earliest year"},"latest_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latest Value","description":"Value in latest year"},"absolute_change":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Absolute Change","description":"Latest minus earliest"},"percent_change":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Percent Change","description":"Percent change from earliest to latest"}},"type":"object","required":["metric"],"title":"TrendChange","description":"Computed change between earliest and latest data points."},"TrendYearData":{"properties":{"year":{"type":"integer","title":"Year","description":"Data year"},"total_population":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Population","description":"Total population"},"median_household_income":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median Household Income","description":"Median household income ($)"},"poverty_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Poverty Rate","description":"Poverty rate (%)"},"uninsured_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Uninsured Rate","description":"Uninsured rate (%)"},"unemployment_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Unemployment Rate","description":"Unemployment rate (%)"},"median_age":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median Age","description":"Median age (years)"}},"type":"object","required":["year"],"title":"TrendYearData","description":"ACS demographic snapshot for a single year."},"TrendsResponse":{"properties":{"geoid":{"type":"string","title":"Geoid","description":"11-digit census tract GEOID"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Tract name"},"years":{"items":{"$ref":"#/components/schemas/TrendYearData"},"type":"array","title":"Years","description":"ACS data for each available year, sorted ascending"},"changes":{"items":{"$ref":"#/components/schemas/TrendChange"},"type":"array","title":"Changes","description":"Computed changes between earliest and latest data points"}},"type":"object","required":["geoid","years","changes"],"title":"TrendsResponse","description":"Historical trend data for a census tract."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"WebhookCreate":{"properties":{"url":{"type":"string","maxLength":2048,"title":"Url","description":"HTTPS callback URL for webhook delivery"},"events":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Events","description":"Event types to subscribe to. Valid: 'data.updated' (ETL refreshes), 'threshold.exceeded' (metric crosses threshold)"},"filters":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Filters","description":"Optional filters: state_fips (list), geoids (list), thresholds (dict of metric: {operator: '>', value: 20})"},"secret":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Secret","description":"Shared secret for HMAC-SHA256 signature verification (max 64 chars)"}},"type":"object","required":["url","events"],"title":"WebhookCreate","description":"Request body for creating a webhook subscription."},"WebhookListResponse":{"properties":{"total":{"type":"integer","title":"Total","description":"Total subscriptions"},"webhooks":{"items":{"$ref":"#/components/schemas/WebhookResponse"},"type":"array","title":"Webhooks","description":"Subscriptions"}},"type":"object","required":["total","webhooks"],"title":"WebhookListResponse","description":"List of webhook subscriptions for the authenticated key."},"WebhookResponse":{"properties":{"id":{"type":"integer","title":"Id","description":"Subscription ID"},"url":{"type":"string","title":"Url","description":"Callback URL"},"events":{"items":{"type":"string"},"type":"array","title":"Events","description":"Subscribed event types"},"filters":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Filters","description":"Applied filters"},"active":{"type":"boolean","title":"Active","description":"Whether the subscription is active"},"created_at":{"type":"string","title":"Created At","description":"ISO 8601 creation timestamp"}},"type":"object","required":["id","url","events","active","created_at"],"title":"WebhookResponse","description":"A webhook subscription."}},"securitySchemes":{"APIKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key"}}},"tags":[{"name":"system","description":"Health checks and operational endpoints."},{"name":"context","description":"Primary lookup — resolve an address or coordinates to census tract demographics, SVI themes, PLACES measures, and an optional AI narrative."},{"name":"batch","description":"Batch address lookups — submit multiple addresses in a single request and receive per-address results."},{"name":"nearby","description":"Spatial radius search — find census tracts within a given distance of a point, sorted by proximity."},{"name":"compare","description":"Compare two census tracts side-by-side, or compare a tract against state or national averages."},{"name":"stats","description":"Data loading statistics — view total tracts loaded and per-state breakdowns."},{"name":"dictionary","description":"Data dictionary — structured metadata about every field the API returns, including data type, source, clinical relevance, and interpretation guidance."},{"name":"trends","description":"Historical trends — multi-year ACS demographic snapshots for a census tract, with computed change metrics."},{"name":"demographics","description":"Demographic comparison — compare a tract against county, state, and national averages with percentile rankings."},{"name":"webhooks","description":"Webhook subscriptions — register callback URLs for notifications when tract data changes or thresholds are exceeded."},{"name":"providers","description":"NPI provider data — search individual providers by bounding box, radius, or census tract. Returns provider details including taxonomy, address, and FQHC status."}]}