Skip to main content

GET /api/activity-heatmap

National activity feed aggregated to H3 resolution-5 hexagons. Returns a GeoJSON FeatureCollection of geocoded events from the last 90 days, weighted by event count per cell. Use this to power map-based heatmap visualizations of where activity is happening across the country, without scoping to a single metro. The response is cached at the edge for 1 hour (s-maxage=3600, stale-while-revalidate=86400), so it’s safe to fetch once on map mount instead of refetching as the viewport changes. There are no query parameters — the window and resolution are fixed. Event counts per cell are long-tailed (p50 ≈ 22, p99 ≈ 270, max in the thousands). The weight field is the raw count; apply your own log or interpolation curve when styling heatmap layers so dense metros don’t saturate the legend. Example
curl "https://axiomlocus.io/api/activity-heatmap"
Mapbox GL example
const res = await fetch("https://axiomlocus.io/api/activity-heatmap");
const fc = await res.json();

map.addSource("activity", { type: "geojson", data: fc });
map.addLayer({
  id: "activity-heatmap",
  type: "heatmap",
  source: "activity",
  paint: {
    "heatmap-weight": [
      "interpolate", ["linear"], ["get", "weight"],
      0, 0, 25, 0.2, 75, 0.45, 200, 0.75, 500, 1,
    ],
  },
});
Response
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": { "type": "Point", "coordinates": [-122.4194, 37.7749] },
      "properties": { "weight": 287, "h3": "852830fffffffff" }
    }
  ],
  "meta": {
    "window_days": 90,
    "parent_res": 5,
    "hex_count": 412
  }
}
FieldTypeDescription
features[].geometry.coordinates[lng, lat]Center of the H3 res-5 hexagon.
features[].properties.weightintNumber of events that occurred in this hex over the window.
features[].properties.h3stringH3 res-5 cell index.
meta.window_daysintLookback window in days (currently 90).
meta.parent_resintH3 resolution of the aggregation (currently 5).
meta.hex_countintNumber of hexes with at least one event.

GET /api/permits/hotspots

H3-aggregated building permit hotspots for a metro, ranked by permit density and total estimated cost. Query parameters
NameTypeRequiredDefaultDescription
metro_slugstringMetro slug (e.g. sf, nyc, chi, la).
daysint90Lookback period in days.
limitint25Max hotspot cells to return.
Example
curl "https://axiomlocus.io/api/permits/hotspots?metro_slug=sf&days=90&limit=10"
Response
{
  "metro": "sf",
  "days": 90,
  "hotspots": [
    {
      "h3_index": "882a100d63fffff",
      "center_lat": 37.7749,
      "center_lng": -122.4194,
      "permit_count": 47,
      "total_value": 12500000,
      "avg_value": 265957,
      "top_type": "new_construction"
    },
    {
      "h3_index": "882a100d65fffff",
      "center_lat": 37.7851,
      "center_lng": -122.4094,
      "permit_count": 32,
      "total_value": 8700000,
      "avg_value": 271875,
      "top_type": "renovation"
    }
  ]
}
FieldTypeDescription
hotspotsarrayH3 cells ranked by permit activity.
hotspots[].permit_countintTotal permits in the lookback window.
hotspots[].total_valuefloatSum of estimated costs.
hotspots[].top_typestringMost common permit type in this cell.

GET /api/crime/hotspots

Crime incident hotspots aggregated by H3 cell for a metro area. Query parameters
NameTypeRequiredDefaultDescription
metro_slugstringMetro slug.
daysint90Lookback period in days.
categorystringFilter by crime category: property, violent, other.
limitint25Max cells to return.
Example
curl "https://axiomlocus.io/api/crime/hotspots?metro_slug=sf&days=30&category=property"
Response
{
  "metro": "sf",
  "days": 30,
  "total_incidents": 1243,
  "hotspots": [
    {
      "h3_index": "882a100d63fffff",
      "incident_count": 89,
      "top_category": "property",
      "per_capita_rate": 12.4,
      "trend": "declining"
    }
  ]
}
FieldTypeDescription
total_incidentsintTotal incidents across all cells in the lookback window.
hotspots[].incident_countintNumber of incidents in this H3 cell.
hotspots[].per_capita_ratefloatIncidents per 1,000 residents.
hotspots[].trendstringTrend vs prior period: increasing, stable, declining.

GET /api/commuter-flows

LEHD Origin-Destination commuter flow data for a Census tract. Shows where workers live and where residents work. Query parameters
NameTypeRequiredDefaultDescription
tractstringCensus tract GEOID (11 digits).
directionstringbothinbound (workers coming in), outbound (residents leaving), or both.
limitint20Top N connected tracts to return.
Example
curl "https://axiomlocus.io/api/commuter-flows?tract=06075010800&direction=inbound&limit=10"
Response
{
  "tract": "06075010800",
  "inbound": {
    "total_workers": 14200,
    "flows": [
      { "origin_tract": "06081611100", "workers": 890, "pct": 6.3, "origin_name": "Daly City" },
      { "origin_tract": "06001402100", "workers": 720, "pct": 5.1, "origin_name": "Oakland" }
    ]
  },
  "outbound": {
    "total_residents_working": 3400,
    "flows": [
      { "dest_tract": "06075017902", "workers": 210, "pct": 6.2, "dest_name": "SoMa" }
    ]
  }
}
FieldTypeDescription
inbound.total_workersintTotal workers commuting into this tract.
inbound.flowsarrayTop origin tracts with worker counts.
outbound.total_residents_workingintTotal residents who commute out.
outbound.flowsarrayTop destination tracts.

GET /api/v1/spatial-diagnostics

Requires Bearer token.
Identify spatial score outliers using Local Moran’s I (LISA) statistics and topological data analysis. Use this to find cells that behave differently from their neighbors — high-scoring cells surrounded by low scores, or vice versa. Query parameters
NameTypeRequiredDefaultDescription
metro_slugstringFilter by metro area.
typestringSpatial cluster type: HH (High-High), HL (High-Low), LH (Low-High), LL (Low-Low), TDA_DONUT (topological donut pattern).
limitint50Max results (max 500).
Cluster types explained:
TypeMeaningUse case
HHHigh score surrounded by high scoresEstablished strong markets.
HLHigh score surrounded by low scoresPotential anchor locations driving change.
LHLow score surrounded by high scoresUnderperforming cells in strong markets — possible opportunities.
LLLow score surrounded by low scoresWeak market clusters.
TDA_DONUTRing of activity with a hollow centerEmerging development patterns where activity surrounds but hasn’t reached the core.
When no type is specified, the endpoint returns HL and LH outliers — the most analytically interesting patterns. Example
curl "https://axiomlocus.io/api/v1/spatial-diagnostics?metro_slug=sf&type=HL&limit=10" \
  -H "Authorization: Bearer al_your_key_here"
Response
{
  "outliers": [
    {
      "h3_index": "882a100d63fffff",
      "metro_slug": "sf",
      "score_baseline": 72,
      "experimental_composite": 78,
      "spatial_diagnostics": {
        "cluster_type": "HL",
        "local_moran": 2.34
      }
    }
  ]
}
FieldTypeDescription
outliersarrayCells matching the spatial pattern, sorted by statistical significance.
outliers[].score_baselinenumberCurrent composite score.
outliers[].spatial_diagnostics.cluster_typestringLISA cluster classification.
outliers[].spatial_diagnostics.local_morannumberLocal Moran’s I statistic. Higher absolute values indicate stronger spatial outlier behavior.

GET /api/backtest

Requires authentication. Session-based — available through the dashboard.
Validate scoring model accuracy by comparing historical predictions against outcomes. Requires at least 90 days of score history and 5 or more monitored locations. Example
curl "https://axiomlocus.io/api/backtest" \
  -H "Authorization: Bearer al_your_key_here"
Response (ready)
{
  "status": "ready",
  "data_collection_start": "2026-01-15",
  "days_of_data": 94,
  "metrics": {
    "r_squared": 0.82,
    "hit_rate": 0.76,
    "miss_rate": 0.68,
    "sample_size": 12
  }
}
Response (insufficient data)
{
  "status": "insufficient_data",
  "days_until_ready": 42,
  "days_of_data": 48,
  "data_collection_start": "2026-03-01",
  "sample_size": 3
}
FieldTypeDescription
statusstringready or insufficient_data.
metrics.r_squarednumberCorrelation between predicted and actual scores (0–1).
metrics.hit_ratenumberFraction of high-scored locations (above 70) that maintained or improved.
metrics.miss_ratenumberFraction of low-scored locations (below 30) that stayed low or declined.
metrics.sample_sizenumberNumber of location pairs used in the analysis.