Sites
Job sites, one per property. The domain calls these addresses internally; the API calls them sites, because that is what an arborist means.
get
https://treeinventory.ai/api/v1/sitesList sites
Filter by customerId to get one customer's properties. A customerId belonging to another organization returns an empty page, not an error, because confirming that an id exists elsewhere is itself a leak.
Scope: sites:read
Query parameters
| Field | Type | Notes |
|---|---|---|
| cursor | string | Opaque. Take it from a previous response's nextCursor and send it back unchanged. Do not parse it; its contents are not part of this contract. |
| limit | integer | Page size. Defaults to 50, clamped to 200 rather than refused. |
| customerId | uuid | Only this customer's sites. |
| search | string | Case-insensitive substring of the street line. |
Each item in data.items
| Field | Type | Notes |
|---|---|---|
| id | uuid | |
| customerId | uuid | |
| label | string or null | Optional nickname ("Back lot"). |
| street | string | |
| city | string | |
| state | string | |
| zip | string | |
| country | string | |
| latitude | number or null | Null until the site has been geocoded or located. |
| longitude | number or null | |
| createdAt | string | |
| updatedAt | string |
Example response 200
{
"success": true,
"message": "Sites retrieved",
"data": {
"items": [
{
"id": "3a7c9e21-5b48-4f0a-9d33-71c6ee204b18",
"customerId": "9f1b2c3d-4e5f-4a6b-8c7d-0e1f2a3b4c5d",
"label": "Front acre",
"street": "3760 W Delap Rd",
"city": "Bloomington",
"state": "IN",
"zip": "47404",
"country": "US",
"latitude": 39.1912,
"longitude": -86.5847,
"createdAt": "2026-08-19T14:05:47.008Z",
"updatedAt": "2026-08-19T14:05:47.008Z"
}
],
"nextCursor": null
}
}Failures
401Missing, malformed, revoked or expired credential. TheWWW-Authenticateheader names the scheme, which isApiKey.403The key is valid but does not carry the scope this operation requires. The message names the scope, so you can ask for exactly the grant you need.404No such record in your organization. A record belonging to somebody else is indistinguishable from one that does not exist.422Validation failed. Every bad field is named, at once.429Rate limit exceeded.500Something failed on our side. Retry with the SAME Idempotency-Key; a 5xx is the one status where retrying is correct.
post
https://treeinventory.ai/api/v1/sitesCreate a site
Omit latitude/longitude and the address is geocoded for you. That is usually what you want.
Scope: sites:write
Headers
| Field | Type | Notes |
|---|---|---|
| Idempotency-Key | uuid | A UUID you mint per logical action and REUSE on every retry of it. Replay returns the original response and creates nothing. Omit it and a retry creates a second record. |
Request body
| Field | Type | Notes |
|---|---|---|
| customerIdrequired | uuid | |
| label | string or null | |
| streetrequired | string | |
| cityrequired | string | |
| staterequired | string | |
| ziprequired | string | |
| country | string | |
| latitude | number or null | Optional. Omit it and we geocode the address. Send it and we keep it only if it agrees with the geocode, because a phone's GPS at the moment a form opened is not evidence about the address typed into it. |
| longitude | number or null |
Example request
{
"customerId": "9f1b2c3d-4e5f-4a6b-8c7d-0e1f2a3b4c5d",
"label": "Front acre",
"street": "3760 W Delap Rd",
"city": "Bloomington",
"state": "IN",
"zip": "47404",
"country": "US"
}data
| Field | Type | Notes |
|---|---|---|
| id | uuid | |
| customerId | uuid | |
| label | string or null | Optional nickname ("Back lot"). |
| street | string | |
| city | string | |
| state | string | |
| zip | string | |
| country | string | |
| latitude | number or null | Null until the site has been geocoded or located. |
| longitude | number or null | |
| createdAt | string | |
| updatedAt | string |
Example response 201
{
"success": true,
"message": "Site created",
"data": {
"id": "3a7c9e21-5b48-4f0a-9d33-71c6ee204b18",
"customerId": "9f1b2c3d-4e5f-4a6b-8c7d-0e1f2a3b4c5d",
"label": "Front acre",
"street": "3760 W Delap Rd",
"city": "Bloomington",
"state": "IN",
"zip": "47404",
"country": "US",
"latitude": 39.1912,
"longitude": -86.5847,
"createdAt": "2026-08-19T14:05:47.008Z",
"updatedAt": "2026-08-19T14:05:47.008Z"
}
}Failures
401Missing, malformed, revoked or expired credential. TheWWW-Authenticateheader names the scheme, which isApiKey.403The key is valid but does not carry the scope this operation requires. The message names the scope, so you can ask for exactly the grant you need.404No such record in your organization. A record belonging to somebody else is indistinguishable from one that does not exist.409Idempotency conflict: thisIdempotency-Keywas used with a different body (idempotency_key_reused), or an identical request is still in flight (command_in_progress, withRetry-After).422Validation failed. Every bad field is named, at once.429Rate limit exceeded.500Something failed on our side. Retry with the SAME Idempotency-Key; a 5xx is the one status where retrying is correct.