Site assessments
Read and record field walkthroughs: assessments, the pins dropped on the site with their quantities, notes and photos, and totals per service.
View as MarkdownA site assessment is a field walkthrough on a job. As the crew walks the lot they drop pins: each pin is a location with what was found (a service such as Pothole repair or Crack fill), a quantity, a severity, notes and photos. Assessments roll their pins up into totals per service, which flow into the job's estimate.
A job has at most one open assessment. New pins on the job join it until it is completed. Completing an assessment saves a handoff snapshot for the operations team; it can be reopened.
Note
Partner keys add firm_id to name the workspace: in the query string, or in the JSON body on writes. See Partner API.
The assessment object#
| Field | Type | Description |
|---|---|---|
id |
integer | Assessment id. |
job_id |
integer | The job. |
location_id |
integer or null | The job's site. |
scope |
string | job (one scope of work) or location (a whole-site walkthrough). |
title, notes |
string | |
status |
string | open or completed. |
pin_count |
integer | Pins in the assessment. |
created_by |
object | {id, name}. |
completed_at, created_at, updated_at |
string | UTC, ISO 8601 with Z. |
The pin object#
| Field | Type | Description |
|---|---|---|
id |
integer | Pin id. |
job_id, assessment_id |
integer | assessment_id is null for pins dropped outside an assessment. |
label |
string | Display name: the pin's name, else "Pothole repair 2", else "Pin 3". |
name |
string or null | A name someone gave the pin. |
latitude, longitude |
number | Where it is. |
service_type |
object or null | {id, name}: what the pin is for. See List assessment services. |
tag |
object or null | {id, name} for pins recorded with a photo tag instead of a service. |
color |
string | Map color. |
severity |
string | low, medium or high. |
size |
string | small, medium or large. |
notes |
string or null | |
visibility |
string | internal (team only) or external (may show on customer maps and reports). |
keep_for_proposal |
boolean | Kept for the proposal. |
measurement |
object | type (none, count, sqft, dimensions, volume, lf), value, unit (EA, SF, LF, CY) and data (dimensions, drawn shapes and form answers as captured). |
ai_severity, ai_rationale |
string or null | Automatic grade, when one was run. |
photos |
array | {id, url, thumbnail_url, title, caption, stage, visibility, is_video, taken_at}. |
created_by_user_id |
integer | |
created_at, updated_at |
string | UTC, ISO 8601 with Z. |
Assessments#
List site assessments#
GET /v1/site-assessments
Permission: Read jobs
Most recently changed first.
| Name | Type | Required | Description |
|---|---|---|---|
job_id |
integer | No | Only this job. |
location_id |
integer | No | Only this site. |
status |
string | No | open or completed. |
scope |
string | No | job or location. |
updated_after |
string | No | ISO 8601. Assessments changed after it, oldest first. |
limit, offset |
integer | No | Default 50 (max 200) and 0. |
curl "https://trutec.ai/api/v1/site-assessments?job_id=4812" \
-H "X-API-Key: sk_your_api_key_here"
{
"data": [
{
"id": 702,
"job_id": 4812,
"location_id": 2290,
"scope": "job",
"title": "Spring walkthrough",
"notes": null,
"status": "open",
"pin_count": 2,
"created_by": {"id": 311, "name": "Dana Ortiz"},
"completed_at": null,
"created_at": "2026-10-12T15:04:11Z",
"updated_at": "2026-10-12T15:30:52Z"
}
],
"pagination": {"total": 1, "limit": 50, "offset": 0}
}
A pin added to an assessment does not change the assessment's updated_at. To sync pins, use List pins with updated_after.
Get a site assessment#
GET /v1/site-assessments/{assessment_id}
Permission: Read jobs
The assessment with totals per service (grouped the same way as the job page's assessment card) and every pin. Add include_pins=false for the totals only.
{
"data": {
"id": 702,
"job_id": 4812,
"title": "Spring walkthrough",
"status": "open",
"pin_count": 2,
"services": [
{"label": "Pothole repair", "color": "#f97316", "pin_count": 1, "photo_count": 1,
"quantities": [{"unit": "EA", "value": 3}], "severities": {"high": 1}, "pin_ids": [15520]},
{"label": "Crack fill", "color": "#0ea5e9", "pin_count": 1, "photo_count": 0,
"quantities": [{"unit": "LF", "value": 120.0}], "severities": {"medium": 1}, "pin_ids": [15521]}
],
"severity_totals": {"low": 0, "medium": 1, "high": 1},
"pins": [
{
"id": 15520,
"job_id": 4812,
"assessment_id": 702,
"label": "Entrance potholes",
"name": "Entrance potholes",
"latitude": 30.40121,
"longitude": -97.72088,
"service_type": {"id": 41, "name": "Pothole repair"},
"tag": null,
"color": "#f97316",
"severity": "high",
"size": "medium",
"notes": "Three potholes at the entrance, one deep",
"visibility": "external",
"keep_for_proposal": true,
"measurement": {"type": "count", "value": 3, "unit": "EA", "data": {}},
"photos": [
{"id": 9021, "url": "https://media.example.com/photos/job_4812/c11e0a.jpg",
"thumbnail_url": "https://media.example.com/photos/job_4812/c11e0a_thumb.jpg",
"title": null, "caption": "Deepest one", "stage": "before", "visibility": "external",
"is_video": false, "taken_at": "2026-10-12T14:58:02Z"}
],
"created_by_user_id": 311,
"created_at": "2026-10-12T15:04:11Z",
"updated_at": "2026-10-12T15:04:11Z"
}
]
}
}
Start a site assessment#
POST /v1/site-assessments
Permission: Write jobs
Starts an assessment on a job, the same as Start assessment on the job page. Pins already on the job that belong to no assessment join it. If the job already has an open assessment, that one is returned with 200 and "created": false.
| Name | Type | Required | Description |
|---|---|---|---|
job_id |
integer | Yes | The job. |
title |
string | No | Default "Site Assessment · Oct 12, 2026". |
notes |
string | No |
curl -X POST https://trutec.ai/api/v1/site-assessments \
-H "X-API-Key: sk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"job_id": 4812, "title": "Spring walkthrough"}'
Returns 201 with {"data": assessment, "created": true}. Whole-site (location) walkthroughs are started in the app.
Update a site assessment#
PATCH /v1/site-assessments/{assessment_id}
Permission: Write jobs
Change title (cannot be empty) or notes. Returns 200 with {"data": assessment}.
Complete a site assessment#
POST /v1/site-assessments/{assessment_id}/complete
Permission: Write jobs
Closes the assessment: new pins on the job stop joining it, loose pins on the job are attached, and a handoff snapshot is saved for the operations team. Completing a completed assessment changes nothing. Returns 200 with the assessment.
Reopen a site assessment#
POST /v1/site-assessments/{assessment_id}/reopen
Permission: Write jobs
New pins on the job join it again. Returns 200 with the assessment.
List assessment services#
GET /v1/assessment-services
Permission: Read jobs
The services a pin can be for, as set up in TruTec under Site Assessment settings, with the measurement each one takes.
{
"data": [
{"id": 41, "name": "Pothole repair", "group": "Asphalt repair", "color": "#f97316", "measurement_type": "count"},
{"id": 42, "name": "Crack fill", "group": "Asphalt repair", "color": "#0ea5e9", "measurement_type": "lf"}
]
}
Pins#
List pins#
GET /v1/assessment-pins
Permission: Read jobs
Pins across the workspace, newest first.
| Name | Type | Required | Description |
|---|---|---|---|
job_id |
integer | No | Only this job. |
assessment_id |
integer | No | Only this assessment. |
service_type_id |
integer | No | Only this service. |
updated_after |
string | No | ISO 8601. Pins changed after it, oldest first. |
limit, offset |
integer | No | Default 50 (max 200) and 0. |
Get a pin#
GET /v1/assessment-pins/{pin_id}
Permission: Read jobs
Returns {"data": pin}.
Add a pin#
POST /v1/assessment-pins
Permission: Write jobs
Drops a pin the way the field capture page does. The pin joins assessment_id if you send it (it must be open), otherwise the job's open assessment. A pin for a service on a job that has never had an assessment starts one. Pin quantities reach the job's draft estimate like pins captured in the field.
| Name | Type | Required | Description |
|---|---|---|---|
job_id |
integer | Yes, unless assessment_id |
The job. |
assessment_id |
integer | No | An open assessment on that job. |
latitude, longitude |
number | Yes | Location. |
service_type_id |
integer | No | What it is for. |
measurement_type |
string | No | none, count, sqft, dimensions, volume or lf. |
measurement_value |
number | No | The quantity. |
measurement_unit |
string | No | EA, SF, LF or CY. |
length_ft, width_ft, depth_in |
number | No | Dimensions instead of a value, for dimensions and volume services. |
measurement_data |
object | No | Extra measurement detail, as the capture page stores it. |
severity |
string | No | low, medium (default) or high. |
size |
string | No | small, medium (default) or large. |
notes |
string | No | |
name |
string | No | Pin name, up to 80 characters. |
visibility |
string | No | external (default) or internal. |
keep_for_proposal |
boolean | No | |
tag_type_id |
integer | No | A photo tag instead of a service. |
defect_type_id |
integer | No | A standard defect type. |
curl -X POST https://trutec.ai/api/v1/assessment-pins \
-H "X-API-Key: sk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"assessment_id": 702,
"latitude": 30.40121,
"longitude": -97.72088,
"service_type_id": 41,
"measurement_type": "count",
"measurement_value": 3,
"measurement_unit": "EA",
"severity": "high",
"notes": "Three potholes at the entrance",
"name": "Entrance potholes"
}'
Returns 201 with {"data": pin}.
| Status | error |
|---|---|
| 400 | latitude and longitude are required, job_id or assessment_id is required, a field message such as severity must be one of: low, medium, high, Unknown fields |
| 404 | Job not found, Site assessment not found, Assessment service not found, Photo tag not found |
| 409 | Assessment is completed. Reopen it first. |
Update a pin#
PATCH /v1/assessment-pins/{pin_id}
Permission: Write jobs
Send only what changes: any field from Add a pin except job_id and assessment_id. Moving a pin also moves any shape drawn around it. Returns 200 with {"data": pin}.
curl -X PATCH https://trutec.ai/api/v1/assessment-pins/15520 \
-H "X-API-Key: sk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"notes": "Three potholes, one deep", "severity": "medium"}'
Delete a pin#
DELETE /v1/assessment-pins/{pin_id}
Permission: Write jobs and Delete records
Deletes the pin and its photos from the assessment and updates the job's draft estimate. Returns 204. This cannot be undone.
Add a photo to a pin#
POST /v1/assessment-pins/{pin_id}/photos
Permission: Write jobs
Multipart field photo (repeat it for several), or JSON with url (a public https:// image link, up to 15 MB). Optional: caption, title, stage (before, during, after, general), visibility (external, internal), taken_at, client_uid (repeat uploads with the same id are not duplicated).
curl -X POST https://trutec.ai/api/v1/assessment-pins/15520/photos \
-H "X-API-Key: sk_your_api_key_here" \
-F "[email protected]" -F "caption=Deepest one" -F "stage=before"
Returns 201 with the pin and its photos, plus photo_ids of the photos just added. Errors: 400 No photo provided or Invalid photo, 422 url is not an image, 503 when photo storage is briefly unavailable (retry).
Copy an assessment#
Duplicate a site assessment#
POST /v1/site-assessments/{assessment_id}/duplicate
Permission: Write jobs
The same as Duplicate on the assessment page. Makes a new assessment on the same job with a copy of every pin and its photos, so one walkthrough can be split into phases: duplicate it, then delete the pins that don't belong in each copy (DELETE /v1/assessment-pins/{pin_id}).
The copy is saved as completed, so new pins on the job keep joining the open assessment; reopen the copy if new pins should join it instead. Photos are shared, not uploaded again, and deleting a pin or photo in one copy leaves the other untouched.
| Name | Type | Required | Description |
|---|---|---|---|
title |
string | No | Title of the copy. Default is the original's title followed by "(Copy)". |
curl -X POST https://trutec.ai/api/v1/site-assessments/702/duplicate \
-H "X-API-Key: sk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"title": "Spring walkthrough, phase 2"}'
Returns 201 with {"data": assessment, "pins_copied": 14, "photos_copied": 22}. Errors: 400 for an unknown field or an empty title, 404 when the assessment is not in your workspace.
Assessments can't be deleted on their own (in TruTec they go when their job is deleted). To take pins out of one, delete the pins.