Saving & managing takeoffs
Save a detection onto a job as a takeoff, rename or delete takeoffs, and read every quantity a takeoff provides, by item and by service.
View as MarkdownA takeoff (a saved measurement) is what a job's estimate pulls quantities from. Takeoffs you draw in TruTec are already saved. A detection you run through the API (Measure a site) is not: it returns quantities and geometry but attaches nothing to a job. Save it onto a job to make it a takeoff: it then shows on the job, opens in the aerial takeoff editor where your team can adjust it, and feeds estimates.
Typical flow:
POST /v1/detect/address(or/v1/detect/full) with"async": true. Keep the returnedid.- Poll
GET /v1/detect/status/{id}untilstatusiscompleted. POST /v1/jobs/{job_id}/measurementswith{"detection_id": "<id>"}.GET /v1/measurements/{measurement_id}/itemsfor the quantities.
Reading saved takeoffs is covered in Saved measurements & imagery. To add, remove or reclassify an aerial takeoff's areas, counts, lines and custom item shapes, see Editing takeoff shapes. Plan-sheet takeoffs can be built and edited end to end through the API, see Blueprint takeoffs.
Note
Partner keys add firm_id to name the workspace: in the query string, or in the JSON body on writes. See Partner API.
Save a detection onto a job#
POST /v1/jobs/{job_id}/measurements
Permission: Write measurements
| Name | Type | Required | Description |
|---|---|---|---|
detection_id |
string | One of the two | The id of an async detection run by this workspace. It must be completed. |
detection |
object | One of the two | The JSON body a synchronous detect call returned. It must be the json format, not GeoJSON or KMZ. |
name |
string | No | Up to 200 characters. Default "<job name> Aerial Takeoff". |
curl -X POST https://trutec.ai/api/v1/jobs/4812/measurements \
-H "X-API-Key: sk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"detection_id": "6b0f2a51-8c1e-4d7a-9f3e-2a7c4b9d1e60", "name": "Lakeside Plaza main lot"}'
Returns 201:
{
"data": {
"id": 90311,
"name": "Lakeside Plaza main lot",
"type": "parking",
"job_id": 4812,
"area": 18250.5,
"imagery_source": "google",
"created_at": "2026-10-12T15:04:11Z",
"updated_at": "2026-10-12T15:04:11Z"
}
}
The takeoff is recorded on the job's timeline as the person who created the API key. imagery_source is google, or nearmap:<survey id> when the detection ran on a Nearmap survey, so map exports and imagery downloads use the same imagery.
If the detection ran with add-on models, its curbs, wheel stops, speed bumps, bollards and parallel stalls are saved as the takeoff's curb, wheel stop, speed bump, bollard and parallel stall items, so they show in the takeoff editor. Curb linear feet and curb count are in the takeoff's quantities right away; the other items' counts, and parallel stall striping footage, are worked out by the editor and fill in the first time someone saves the takeoff there. Add-ons whose status is failed add nothing. Landscape results are not saved into the takeoff.
Saving does not run or bill another detection. Each save makes a new takeoff, so save a detection once. If your team later runs detection again on this takeoff inside the TruTec editor, that run is billed like any new detection.
| Status | error |
|---|---|
| 400 | Send detection_id or detection (neither or both sent), name must be 200 characters or less, Unknown fields |
| 403 | API key lacks measurement write permission |
| 404 | Job not found, Detection not found (unknown id, or another workspace's run) |
| 409 | Detection still running. Poll GET /v1/detect/status/{id} and save it when it is completed. |
| 422 | Detection failed, GeoJSON results cannot be saved, Not a detection result |
Get takeoff quantities#
GET /v1/measurements/{measurement_id}/items
Permission: Read measurements
Every quantity an estimate can pull from the takeoff: the same list the estimate's quantity picker shows. It covers total area, area by spec, concrete and sidewalk area, stall and marking counts and their striping footage, spec splits (for example van-accessible handicap stalls), custom items, and blueprint layers. Works for any saved takeoff, aerial or blueprint.
services lists services the takeoff's Services tab mapped measured items to, with the summed quantity in the unit the takeoff measured. It is empty when nothing was mapped.
curl https://trutec.ai/api/v1/measurements/90311/items \
-H "X-API-Key: sk_your_api_key_here"
{
"data": {
"measurement_id": 90311,
"name": "Lakeside Plaza main lot",
"job_id": 4812,
"items": [
{"key": "total_area_sf", "label": "Total area", "quantity": 18250.5, "unit": "SF"},
{"key": "stalls", "label": "Parking stalls", "quantity": 142, "unit": "EA"},
{"key": "stalls_lf", "label": "Parking stalls", "quantity": 2556.0, "unit": "LF"},
{"key": "item_spec:handicap:Van accessible", "label": "Handicap — Van accessible", "quantity": 2, "unit": "EA", "kind": "spec"}
],
"services": [
{"service_id": 318, "service_name": "4\" Restripe", "item_keys": ["stalls", "crosswalks"], "quantity": 2980.0, "unit": "LF"}
]
}
}
| Field | Description |
|---|---|
items[].key |
Stable key for the quantity on this takeoff. |
items[].label |
What the estimate picker calls it. |
items[].quantity, items[].unit |
Value and unit: SF, LF, EA, CY, TON. |
items[].kind |
spec for a spec or size split, custom for a custom item. Absent for standard quantities. |
services[].service_id, service_name |
The catalog service. |
services[].item_keys |
Measured items mapped to it. |
services[].quantity, unit |
The summed quantity, or null when nothing mapped was measured. |
Only quantities above zero are listed. 422 Could not read quantities means the takeoff's saved data could not be read; open it in TruTec and save it again.
Rename a takeoff#
PATCH /v1/measurements/{measurement_id}
Permission: Write measurements
| Name | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Up to 200 characters. |
curl -X PATCH https://trutec.ai/api/v1/measurements/90311 \
-H "X-API-Key: sk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "Main lot"}'
Returns 200 with the takeoff in the same shape as the save response. Errors: 400 name is required, 400 name must be 200 characters or less, 400 Unknown fields (only name can change here).
Delete a takeoff#
DELETE /v1/measurements/{measurement_id}
Permission: Write measurements and Delete records
Deletes the takeoff the way the editor's Delete does: it is logged on the job, and its stored plan sheets and drone photos are cleaned up. Estimates that already pulled quantities from it keep their numbers. Returns 204. This cannot be undone.
curl -X DELETE https://trutec.ai/api/v1/measurements/90311 \
-H "X-API-Key: sk_your_api_key_here"