API Documentation
Programmatic access to UQLI™ US Edition data. All endpoints return JSON. API keys are available on Analyst plan and above.
Authentication
All authenticated endpoints require a Bearer token in the Authorization header. API keys are issued from your Dashboard → API Keys page (Analyst plan required).
Authorization: Bearer uqli_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxKeys are prefixed uqli_live_ for production. Test keys use uqli_test_. Keep your key private — rotate it from the dashboard if compromised.
Base URL
All endpoints below are relative to this base URL. HTTPS is required; HTTP requests are not accepted.
Rate Limits
| Plan | Monthly Requests | Notes |
|---|---|---|
| Analyst | 5,000 / month | Per API key |
| City | 25,000 / month | Per API key |
| Enterprise | Unlimited | SLA available |
Exceeding your monthly limit returns HTTP 429. Check your current usage at GET /api/user/usage or in the Dashboard → Usage page.
Endpoints
The UQLI™ API exposes eight endpoints. Public endpoints require no authentication. All responses include a meta object with version and timestamp.
/api/rankingsPublic / Analyst+ for full listReturns paginated city rankings for a given data cycle year. Free-tier callers receive the top 10 cities; Analyst+ receive all 1,852.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| year | integer | Data cycle year. Default: 2025. |
| page | integer | Page number. Default: 1. |
| per_page | integer | Rows per page, max 100. Default: 50. |
| population_tier | string | Filter by Mega, Large, Medium, or Small. Analyst+ only. |
Response Shape
{
"data": [
{
"rank": 1,
"global_rank": 1,
"composite_score": 72.4,
"confidence_rating": "High",
"delta_rank": null,
"city": {
"city_id": "42",
"name": "Ann Arbor",
"slug": "ann-arbor-mi",
"population_tier": "Medium"
}
}
],
"meta": {
"version": "v2.0-us",
"total": 1852,
"page": 1,
"per_page": 50,
"total_pages": 38
}
}curl
curl -H "Authorization: Bearer $UQLI_KEY" \
"https://www.universalqli.com/api/rankings?year=2025&page=1"Python
import requests
resp = requests.get(
"https://www.universalqli.com/api/rankings",
params={"year": 2025, "page": 1},
headers={"Authorization": f"Bearer {api_key}"},
)
data = resp.json()["data"]/api/cities/:slugAuth requiredAnalyst+ for indicatorsReturns the full city profile including composite score, dimension breakdown, and — for Analyst+ — all 19 individual indicator values with raw data, normalized scores, imputation status, and data source attribution.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| slug | string | City slug, e.g. ann-arbor-mi. Part of the URL path. |
Response Shape
{
"data": {
"city_id": "42",
"name": "Ann Arbor",
"slug": "ann-arbor-mi",
"population_tier": "Medium",
"latest_score": {
"composite_score": 72.4,
"global_rank": 1,
"confidence_rating": "High",
"confidence_interval": 1.2
},
"dimension_scores": [ ... ],
"indicators": [
{
"indicator_id": "7",
"slug": "life-expectancy",
"name": "Life Expectancy",
"unit": "years",
"direction": "higher_better",
"dimension_slug": "health",
"source_name": "CDC WONDER",
"normalized_score": 81.3,
"imputation_method": null,
"raw_value": 79.2,
"vintage_year": 2022,
"data_quality_flag": null
}
]
}
}curl
curl -H "Authorization: Bearer $UQLI_KEY" \
"https://www.universalqli.com/api/cities/ann-arbor-mi"Python
resp = requests.get(
"https://www.universalqli.com/api/cities/ann-arbor-mi",
headers={"Authorization": f"Bearer {api_key}"},
)
profile = resp.json()["data"]
indicators = profile.get("indicators", [])/api/compareAuth requiredAnalyst+Returns full profiles for two cities side by side. Useful for building custom comparison views. Requires Analyst plan.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| slugs | string | Comma-separated pair of city slugs, e.g. ann-arbor-mi,boulder-co. |
Response Shape
{
"data": [
{ /* CityProfile for city A */ },
{ /* CityProfile for city B */ }
],
"meta": { "version": "v2.0-us", "timestamp": "..." }
}curl
curl -H "Authorization: Bearer $UQLI_KEY" \
"https://www.universalqli.com/api/compare?slugs=ann-arbor-mi,boulder-co"Python
resp = requests.get(
"https://www.universalqli.com/api/compare",
params={"slugs": "ann-arbor-mi,boulder-co"},
headers={"Authorization": f"Bearer {api_key}"},
)
city_a, city_b = resp.json()["data"]/api/simulateAuth requiredCity+Recalculates a city's composite score after overriding one or more dimension scores. Useful for policy scenario modeling. Requires City plan.
Request Body (JSON)
| Parameter | Type | Description |
|---|---|---|
| city_slug | string | Slug of the city to simulate. |
| dimension_overrides | object | Map of dimension_slug → new_score (0–100). Only overridden dimensions affect the result. |
Response Shape
{
"data": {
"city_slug": "ann-arbor-mi",
"original_score": 72.4,
"simulated_score": 75.1,
"delta": 2.7,
"dimension_scores": [ ... ]
}
}curl
curl -X POST \
-H "Authorization: Bearer $UQLI_KEY" \
-H "Content-Type: application/json" \
-d '{"city_slug":"ann-arbor-mi","dimension_overrides":{"transit":90}}' \
"https://www.universalqli.com/api/simulate"Python
resp = requests.post(
"https://www.universalqli.com/api/simulate",
json={"city_slug": "ann-arbor-mi", "dimension_overrides": {"transit": 90}},
headers={"Authorization": f"Bearer {api_key}"},
)
result = resp.json()["data"]
print(f"Delta: {result['delta']:+.1f} pts")/api/search/citiesPublicCity name autocomplete. Returns up to 10 matching cities. No authentication required.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| q | string | Partial city name to search, e.g. ann. |
Response Shape
{
"data": {
"cities": [
{
"city_id": "42",
"name": "Ann Arbor",
"slug": "ann-arbor-mi",
"population_tier": "Medium"
}
]
}
}curl
curl "https://www.universalqli.com/api/search/cities?q=ann"Python
resp = requests.get(
"https://www.universalqli.com/api/search/cities",
params={"q": "ann"},
)
cities = resp.json()["data"]["cities"]/api/methodologyPublicReturns dimension definitions, weights, normalization method, and current methodology version. No authentication required.
Response Shape
{
"data": {
"version": "v1.0",
"release_date": "2025-01-01",
"normalization_method": "min-max",
"composite_method": "weighted-geometric-mean",
"dimensions": [
{
"dimension_id": "1",
"slug": "health",
"name": "Health",
"weight": 0.12,
"description": "...",
"indicator_count": 3
}
]
}
}curl
curl "https://www.universalqli.com/api/methodology"Python
resp = requests.get("https://www.universalqli.com/api/methodology")
methodology = resp.json()["data"]
for dim in methodology["dimensions"]:
print(f"{dim['name']}: {dim['weight']:.0%}")/api/user/usageAuth requiredAnalyst+Returns the authenticated user's current API usage statistics for the billing period.
Response Shape
{
"data": {
"user_id": "123",
"email": "researcher@university.edu",
"tier": "analyst",
"monthly_api_calls": 142,
"monthly_reset_at": "2025-06-01T00:00:00Z",
"created_at": "2025-01-15T12:00:00Z"
}
}curl
curl -H "Authorization: Bearer $UQLI_KEY" \
"https://www.universalqli.com/api/user/usage"Python
resp = requests.get(
"https://www.universalqli.com/api/user/usage",
headers={"Authorization": f"Bearer {api_key}"},
)
usage = resp.json()["data"]
print(f"{usage['monthly_api_calls']} API calls this month")/api/export/rankingsAuth requiredAnalyst+Downloads complete rankings as a CSV file. Returns all cities (up to tier cap). Requires Analyst plan.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| year | integer | Data cycle year. Default: 2025. |
| population_tier | string | Optional filter: Mega, Large, Medium, or Small. |
Response Shape
rank,city,slug,population_tier,composite_score,confidence_rating
1,Ann Arbor,ann-arbor-mi,Medium,72.40,High
2,Boulder,boulder-co,Medium,71.85,High
...curl
curl -H "Authorization: Bearer $UQLI_KEY" \
-o uqli-rankings-2025.csv \
"https://www.universalqli.com/api/export/rankings?year=2025"Python
import pandas as pd
resp = requests.get(
"https://www.universalqli.com/api/export/rankings",
params={"year": 2025},
headers={"Authorization": f"Bearer {api_key}"},
)
from io import StringIO
df = pd.read_csv(StringIO(resp.text))
print(df.head())Error Codes
| Status | Code | Meaning |
|---|---|---|
| 400 | Bad Request | Missing or invalid query parameters. |
| 401 | Unauthorized | No Authorization header or invalid API key. |
| 403 | Forbidden | Valid key but insufficient plan tier for this endpoint. |
| 404 | Not Found | The requested resource (city slug, etc.) does not exist. |
| 429 | Too Many Requests | Monthly rate limit exceeded. Retry after X-RateLimit-Reset. |
| 500 | Internal Server Error | Unexpected server error. Contact support if persistent. |
{"error": "message", "detail": "optional detail"}