Saved measurements & imagery
Read the takeoffs your team saved in TruTec, download their map exports and imagery, and find out which imagery they were measured on.
View as MarkdownA saved measurement is a takeoff saved in the TruTec app, including every edit your estimators made. These endpoints read them.
Detection calls (/detect/full, /detect/address, /detect/tiles) do not create saved measurements. Store detection results in your own database, or fetch an async result again from GET /v1/detect/status/{job_id}. See Measure a site.
All endpoints on this page need the Read measurements permission, except the tile and map picture URLs, which carry their own token.
Endpoints#
List saved measurements#
GET /v1/measurements
Permission: Read measurements
Returns your workspace's saved measurements, newest first.
| Name | Type | Required | Description |
|---|---|---|---|
job_id |
integer | No | Only measurements on this job. |
limit |
integer | No | Page size. Default 50, maximum 100. |
offset |
integer | No | Rows to skip. Default 0. |
curl "https://trutec.ai/api/v1/measurements?job_id=4812&limit=20" \
-H "X-API-Key: sk_your_api_key_here"
{
"data": [
{
"id": 90311,
"name": "Northgate Plaza - Takeoff",
"type": "parking_lot",
"job_id": 4812,
"area": 186420.4,
"created_at": "2026-10-08T14:22:51.318204"
}
],
"pagination": {"total": 1, "limit": 20, "offset": 0}
}
area is the total drawn area in square feet. created_at is UTC.
Get a saved measurement#
GET /v1/measurements/{measurement_id}
Permission: Read measurements
Returns the takeoff as it is saved now, with quantities per category, per area and per phase.
| Name | Type | Required | Description |
|---|---|---|---|
measurement_id |
integer (path) | Yes | From the list. |
unit |
string | No | Area unit for counter_summary values: sf (default), sy, sm or acres. |
curl "https://trutec.ai/api/v1/measurements/90311?unit=sf" \
-H "X-API-Key: sk_your_api_key_here"
{
"data": {
"id": 90311,
"name": "Northgate Plaza - Takeoff",
"type": "parking_lot",
"area": 186420.4,
"created_at": "2026-10-08T14:22:51.318204",
"counter_summary": {
"stalls": {
"label": "Stalls",
"data_type": "marker",
"default_display": "count",
"count": 401,
"formatted": "401",
"values": {
"count": {"value": 401, "formatted": "401"},
"linear_feet": {"value": 7140.0, "unit": "LF", "formatted": "7,140 LF"}
},
"linear_feet": 7140
}
},
"parking_areas": [
{
"id": "area-1",
"type": "parking_detection",
"phase": "Phase 1",
"spec": null,
"area_sqft": 154210.4,
"rings": [[[30.40104, -97.72225], [30.40101, -97.72066], [30.39993, -97.72068], [30.39996, -97.72229]]],
"is_hole": false,
"is_carport": false,
"is_concrete": false,
"is_sidewalk": false,
"objects_counted": true
}
],
"phases": [
{"name": "Phase 1", "area_sqft": 154210.4, "areas": [], "specs": {}, "striping": {}}
],
"deducted_counts": {"stalls": 401},
"measurement_types_by_object": {},
"striping_by_phase": {},
"custom_items_summary": {},
"geometry": {},
"metrics": {}
}
}
| Field | Description |
|---|---|
counter_summary |
One entry per category, same shape as in a detection result. See Measurement result reference. Labels use your workspace's names. |
parking_areas[] |
Every drawn area: type, phase, spec (the surface spec chosen in the app, if any), area_sqft, rings ([lat, lng], first ring is the outline), and flags for holes, carports, concrete and sidewalk. |
phases[] |
Drawn areas grouped by phase, with area_sqft (holes excluded), area per spec in specs, and striping quantities in striping. |
deducted_counts |
Final count per category. |
striping_by_phase |
Striping quantities split by phase. |
custom_items_summary |
Custom items your team added in the app. |
geometry, metrics |
The raw data the app saves. Their shape can change; use the fields above where you can. |
Returns 404 {"error": "Measurement not found"} when the id doesn't exist or belongs to another workspace, and 403 {"error": "API key lacks measurement read permission"} without Read measurements.
Download the map export#
GET /v1/measurements/{measurement_id}/export-image
Permission: Read measurements
Downloads the rendered aerial map with the takeoff drawn on it and your logo, as in the app's map export.
| Name | Type | Required | Description |
|---|---|---|---|
measurement_id |
integer (path) | Yes | |
format |
string | No | png (default) or pdf. |
curl -o northgate-map.png \
"https://trutec.ai/api/v1/measurements/90311/export-image?format=png" \
-H "X-API-Key: sk_your_api_key_here"
The response is the file, sent as a download. Headers X-TruTec-Measurement-Id, X-TruTec-Job-Id and X-TruTec-Project-Id (when set) identify it.
| Status | error |
|---|---|
| 400 | format must be either pdf or png |
| 404 | Measurement not found |
| 422 | Measurement has no drawn areas to export (also returned for plan-sheet takeoffs) |
| 422 | Unable to render map export for this measurement |
Download the raw imagery#
GET /v1/measurements/{measurement_id}/imagery
Permission: Read measurements
Downloads the clean aerial image behind a takeoff: the same imagery source the takeoff was measured on, covering the takeoff, with no drawings, legend or logo. Use it to keep the imagery next to the quantities in your own system. The longest side is at most 3,600 pixels.
| Name | Type | Required | Description |
|---|---|---|---|
measurement_id |
integer (path) | Yes | |
format |
string | No | png (default) or jpeg (jpg also accepted). |
curl -o northgate-imagery.jpg \
"https://trutec.ai/api/v1/measurements/90311/imagery?format=jpeg" \
-H "X-API-Key: sk_your_api_key_here"
The X-TruTec-Imagery-Source header says which imagery was used, for example google or nearmap:88f1e2a0-1234-5678-abcd-1234567890ab (Nearmap plus the survey id). X-TruTec-Measurement-Id and X-TruTec-Job-Id are also set.
| Status | error |
|---|---|
| 400 | format must be png or jpeg |
| 404 | Measurement not found |
| 422 | Measurement has no mapped area to fetch imagery for |
| 422 | Unable to fetch imagery for this measurement |
Get a link to the map#
POST /v1/measurements/{measurement_id}/map-link
Permission: Read measurements
Returns a link that opens the takeoff's map picture in a browser for 24 hours, with no API key. Use it to show a map to someone, or in a chat app, without handing out your key.
| Name | Type | Required | Description |
|---|---|---|---|
measurement_id |
integer (path) | Yes | |
style |
string (body) | No | annotated (default): the takeoff drawn on the aerial with its legend and your logo, like the map export. aerial: the clean imagery. |
curl -X POST https://trutec.ai/api/v1/measurements/90311/map-link \
-H "X-API-Key: sk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"style": "annotated"}'
{
"data": {
"measurement_id": 90311,
"url": "https://trutec.ai/api/v1/map-images/eyJtIjo5MDMxMX0.abc123.def456.jpg",
"style": "annotated",
"expires_at": "2026-10-14T15:04:11Z"
}
}
The annotated picture leaves out internal assessment pins and takeoff notes, because a link can be forwarded. The export-image download above keeps them.
| Status | error |
|---|---|
| 400 | style must be one of: annotated, aerial |
| 404 | Measurement not found |
| 422 | Measurement has no drawn areas to export (also returned for plan-sheet takeoffs) |
Fetch a map picture#
GET /v1/map-images/{token}.jpg
Permission: None. The token in the URL is the credential.
Use the url from the call above rather than building this URL yourself. Returns a JPEG, at most 2,400 pixels on its long side. Anyone with the URL can see the map until it expires, so treat it like a secret.
An expired or altered link returns an empty 404. The link also stops working early when the key that made it is revoked or the takeoff leaves the workspace; get a new link then. A 503 with a Retry-After header means the map is still being drawn: try again after that many seconds.
Get a Nearmap tile layer#
GET /v1/measurements/{measurement_id}/imagery-tiles
Permission: Read measurements
For drawing a takeoff on your own map over the same Nearmap imagery it was measured on. Returns an XYZ tile URL template that needs no headers, limited to the area around the site.
curl https://trutec.ai/api/v1/measurements/90311/imagery-tiles \
-H "X-API-Key: sk_your_api_key_here"
{
"data": {
"measurement_id": 90311,
"imagery_source": "nearmap",
"tiles": {
"provider": "nearmap",
"survey_id": "88f1e2a0-1234-5678-abcd-1234567890ab",
"url_template": "https://trutec.ai/api/v1/imagery-tiles/eyJtIjo5MDMxMX0.abc123/{z}/{x}/{y}.jpg",
"tile_size": 256,
"min_zoom": 15,
"max_zoom": 21,
"bounds": {"south": 30.39685, "west": -97.72536, "north": 30.40412, "east": -97.71758},
"attribution": "Imagery © Nearmap",
"expires_at": "2027-01-10T15:04:11Z"
}
}
}
tiles is null when the takeoff is on Google imagery, when your plan no longer includes Nearmap, or when the takeoff spans more than about 3.5 miles. Keep your own base map in that case. The URL expires after 90 days; fetch a new one before then.
Fetch a tile#
GET /v1/imagery-tiles/{token}/{z}/{x}/{y}.jpg
Permission: None. The token in the URL is the credential.
Use the url_template from the call above rather than building this URL yourself. Returns a JPEG tile. Tiles outside the site area or below zoom 15 return an empty 404. The layer also stops working if the key that created it is revoked, the workspace loses Nearmap, or the takeoff is re-measured on another survey; fetch a new layer then. Treat the URL like a secret.
Imagery source and capture date#
| Where | Source | Capture date |
|---|---|---|
Detection result (imagery_source) |
google by default; nearmap when you pass nearmap_survey_id |
Google: none. Nearmap: only the nearmap_date you sent, copied back. |
GET /v1/measurements/{id}/imagery |
X-TruTec-Imagery-Source header: google or nearmap:<survey id> |
Not returned |
GET /v1/measurements/{id}/imagery-tiles |
imagery_source and tiles.survey_id |
Not returned |
GET /v1/measurements/{id} |
Not returned | Not returned |
Condition ratings (image) |
google or nearmap |
Nearmap: image.capture_date of the survey used. Google: null. See Condition ratings. |
Google does not publish capture dates for its satellite imagery. When the date of the imagery matters, measure on a Nearmap survey whose date you know, or upload your own dated imagery with /detect/tiles.