Arterial publishes a read-only ArcGIS FeatureServer that mirrors the
operational data from the dashboard so your existing GIS stack can
consume it directly. The same layers are also available as a
multi-shapefile zip through the Settings → Workspace → GIS exports
panel.
This is the integration surface for analysts who want hazards, coverage
cells, detections, and the org’s service-area polygon to live alongside
their other reference data.
Service URL
https://app.arterial.us/api/arcgis/arterial/FeatureServer
The service is read-only and authenticated by a long-lived token issued
from the dashboard. Hand the token over via a ?token= query
parameter; ArcGIS clients can paste the URL with the token appended
(...?token=artgis_…) into Add Data → From URL.
The legacy hazards-only path
https://app.arterial.us/api/arcgis/hazards/FeatureServer/0 continues
to work unchanged for clients that already integrated against it.
Layers
The service exposes four parent layers plus seven pre-filtered
sub-layers for clients that prefer to subscribe to a slice rather
than apply a where= clause.
| # | Name | Geometry | Notes |
|---|
| 0 | Hazards | Point | Every hazard owned by your org. |
| 1 | Coverage Cells | Polygon | H3 resolution-9 hexes inside your service area, with read counts. |
| 3 | Detections | Point | Raw detections (pre-rollup) inside your service area. |
| 4 | Service Area | Polygon | Your org’s boundary as a single polygon. |
| 5 | Hazards — Active | Point | Hazards whose work order is unfiled or scheduled. |
| 6 | Hazards — Resolved | Point | Hazards whose work order is complete. |
| 7 | Coverage Cells — Fresh (≤7d) | Polygon | Cells last visited within seven days. |
| 8 | Coverage Cells — Stale (>30d) | Polygon | Cells whose last visit is older than thirty days. |
| 9 | Coverage Cells — Gap (never) | Polygon | Cells inside the service area never visited in the lookback window. |
| 10 | Detections — Rolled Up | Point | Detections that already belong to a hazard. |
| 11 | Detections — Orphan | Point | Detections inside the service area that aren’t yet associated with any hazard. |
Service manifest
GET /api/arcgis/arterial/FeatureServer?f=json&token=...
Returns the service descriptor — every client uses this to learn the
layer set. Each entry includes its numeric id, parentLayerId
(-1 for top-level layers), and the canonical layer URL.
Layer descriptor
GET /api/arcgis/arterial/FeatureServer/{layerId}?f=json&token=...
Returns the field schema, geometry type, and pagination caps for one
layer. Field metadata uses the standard esriFieldType* identifiers
(esriFieldTypeOID, esriFieldTypeString, esriFieldTypeInteger,
esriFieldTypeDouble, esriFieldTypeSmallInteger).
Querying features
GET /api/arcgis/arterial/FeatureServer/{layerId}/query
?f=json
&where=1%3D1
&outFields=*
&resultOffset=0
&resultRecordCount=1000
&returnGeometry=true
&token=...
Supported parameters:
f — json (default), pjson, or geojson. Use geojson to
pull the layer straight into QGIS or a Mapbox style.
where — must be 1=1. Custom predicates are not supported on
this read-only mirror; subscribe to a sub-layer instead.
outFields — * for all attributes, or a comma-separated list
of field names.
objectIds — comma-separated list of OBJECTID values to fetch.
resultOffset / resultRecordCount — pagination. The maximum
page size is 1000 records.
returnGeometry — set false to omit geometry (handy for
attribute-only joins).
returnCountOnly — returns { count: N } and skips the
feature payload.
returnIdsOnly — returns the array of OBJECTID values only.
Attribute schemas
Hazards (/0, /5, /6)
| Field | Type | Notes |
|---|
OBJECTID | OID | |
hazard_uuid | String | Stable UUID. |
type | String | Hazard category (pothole, crack, …). |
priority | Double | Priority score. |
status | String | unfiled / scheduled / complete. |
last_detected_at | String | ISO 8601. |
detection_count | Integer | Detections rolled into this hazard. |
owned_by_org | String | Org display name. |
viewer_redacted | SmallInt | 1 when the viewer org has read-but-redacted access. |
latitude | Double | |
longitude | Double | |
address … address_state | String | When known. |
Coverage cells (/1, /7, /8, /9)
| Field | Type | Notes |
|---|
OBJECTID | OID | |
h3_cell | String | 15-char hex H3 index at resolution 9. |
h3_res | SmallInt | Always 9 in this release. |
reads_count | Integer | Total reads in the lookback window. |
last_read_at | String | ISO 8601. null for gap cells. |
days_since_last_read | Integer | -1 for gap cells. |
Detections (/3, /10, /11)
| Field | Type | Notes |
|---|
OBJECTID | OID | |
detection_uuid | String | |
type | String | Detection category. |
confidence | Double | Model confidence score. |
is_approved | SmallInt | 1 when an operator approved. |
captured_at | String | ISO 8601. |
device_uuid | String | |
hazard_uuid | String | Parent hazard, or null for orphan detections. |
model_version | String | |
latitude | Double | |
longitude | Double | |
Service area (/4)
| Field | Type | Notes |
|---|
OBJECTID | OID | |
org_uuid | String | |
org_name | String | |
area_km2 | Double | Polygon area in square kilometres. |
Adding the service to ArcGIS Online
- In ArcGIS Online, open Map Viewer and choose Add → Add layer
from URL.
- Paste the service URL with your token appended:
https://app.arterial.us/api/arcgis/arterial/FeatureServer?token=artgis_…
- ArcGIS reads the manifest and shows the layer list. Add as many as
you want — top-level layers, sub-layers, or both.
- Save the map. When the underlying data updates, refresh the layer
from the layer settings menu.
Adding the service to QGIS
- Open Layer → Add Layer → Add ArcGIS REST Server Layer.
- Use New Connection, paste the service URL (without
/0 —
FeatureServer root only), and store the token in the query string.
- Choose the layers you need from the connection’s layer list.
Multi-layer shapefile export
The dashboard’s GIS exports panel issues an export job that
produces a single .zip file containing one shapefile (.shp,
.shx, .dbf, .prj) per requested layer, plus a top-level
manifest.json describing the bundle:
{
"version": 1,
"generatedAt": "2026-05-10T17:42:00.000Z",
"layers": [
{
"id": 0,
"key": "hazards.all",
"name": "Hazards",
"geometryType": "esriGeometryPoint",
"featureCount": 1842
},
{
"id": 4,
"key": "service_area.all",
"name": "Service Area",
"geometryType": "esriGeometryPolygon",
"featureCount": 1
}
]
}
Each layer’s shapefile lives under a folder named after the stable
layer key with dots replaced by underscores
(hazards_all/, coverage_cells_fresh/, …) so unzip-into-folder
workflows produce a clean per-layer directory tree.
The legacy single-layer export (when no layers field is supplied)
keeps producing arterial-hazards.zip with the same shape it always
had — your existing automation does not need to change.
Multi-layer ESRI JSON export
When the export format is esri_json and more than one layer is
requested, the response is a versioned envelope:
{
"version": 1,
"exportedAt": "2026-05-10T17:42:00.000Z",
"layers": [
{
"id": 0,
"key": "hazards.all",
"name": "Hazards",
"geometryType": "esriGeometryPoint",
"fields": [{ "name": "OBJECTID", "alias": "Object ID", "type": "esriFieldTypeOID" }, …],
"result": {
"exceededTransferLimit": false,
"totalCount": 1842,
"features": [{ "attributes": { … }, "geometry": { … } }, …]
}
},
…
]
}
Single-layer ESRI JSON exports continue to use the flat
{ features: [...], fields: [...], … } shape for back-compat.
Limits and quirks
- Read-only — the service does not support
applyEdits.
where=1=1 is the only supported predicate. Filter by subscribing to
the relevant sub-layer instead.
- Page size is capped at 1000 records. Iterate
resultOffset to
stream large layers.
- Coverage cells query against an H3 resolution-9 grid clipped to your
service area. The lookback window for a single query is one year.
- Orphan detections are scoped to your org by checking each
detection’s
(latitude, longitude) against your service-area
polygon — a detection that drifts outside the polygon will not
appear in /11.
Last modified on May 11, 2026