Skip to main content
REST API · v2.0-us

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_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Keys are prefixed uqli_live_ for production. Test keys use uqli_test_. Keep your key private — rotate it from the dashboard if compromised.

Base URL

https://www.universalqli.com

All endpoints below are relative to this base URL. HTTPS is required; HTTP requests are not accepted.

Rate Limits

PlanMonthly RequestsNotes
Analyst5,000 / monthPer API key
City25,000 / monthPer API key
EnterpriseUnlimitedSLA 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.

GET/api/rankingsPublic / Analyst+ for full list

Returns paginated city rankings for a given data cycle year. Free-tier callers receive the top 10 cities; Analyst+ receive all 1,852.

Query Parameters

ParameterTypeDescription
yearintegerData cycle year. Default: 2025.
pageintegerPage number. Default: 1.
per_pageintegerRows per page, max 100. Default: 50.
population_tierstringFilter 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"]
GET/api/cities/:slugAuth requiredAnalyst+ for indicators

Returns 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

ParameterTypeDescription
slugstringCity 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", [])
GET/api/compareAuth requiredAnalyst+

Returns full profiles for two cities side by side. Useful for building custom comparison views. Requires Analyst plan.

Query Parameters

ParameterTypeDescription
slugsstringComma-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"]
POST/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)

ParameterTypeDescription
city_slugstringSlug of the city to simulate.
dimension_overridesobjectMap 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")
GET/api/methodologyPublic

Returns 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%}")
GET/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")
GET/api/export/rankingsAuth requiredAnalyst+

Downloads complete rankings as a CSV file. Returns all cities (up to tier cap). Requires Analyst plan.

Query Parameters

ParameterTypeDescription
yearintegerData cycle year. Default: 2025.
population_tierstringOptional 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

StatusCodeMeaning
400Bad RequestMissing or invalid query parameters.
401UnauthorizedNo Authorization header or invalid API key.
403ForbiddenValid key but insufficient plan tier for this endpoint.
404Not FoundThe requested resource (city slug, etc.) does not exist.
429Too Many RequestsMonthly rate limit exceeded. Retry after X-RateLimit-Reset.
500Internal Server ErrorUnexpected server error. Contact support if persistent.
Error responses always include a JSON body: {"error": "message", "detail": "optional detail"}
Need API access? API keys are included with Analyst, City, and Enterprise plans. View pricing → or contact sales for Enterprise.