Data model
Every guide on this site walks the same structure. This page is that structure in one place.
Companies, sites and operations
Section titled “Companies, sites and operations”- Company your Sitemark organisation company-level datasets component models — the catalogue of panel, inverter and structure types your sites are built from
- Site a physical site: a solar park, a wind farm site-level datasets design files (DXF and PDF overlays), tickets, and components — the physical elements on site, which persist across flights
- Operation one drone flight or data capture on that site operation-level datasets detection outputs, orthomosaics, digital surface models, point clouds, contour lines, annotations
- Site a physical site: a solar park, a wind farm site-level datasets design files (DXF and PDF overlays), tickets, and components — the physical elements on site, which persist across flights
site_id and no operation_id, a site-level one has a site_id only, an operation-level one has both. That is also what decides which filter returns it.A layer lives at the level it belongs to: detections come out of a single flight, so they are operation-level; components describe the site itself and outlive any one flight, so they are site-level.
This is what decides which filter you scope by, and it is the thing that most often catches people out:
| You want | Filter by | Why |
|---|---|---|
Detections (DEVIATIONS, SOLAR_ANOMALIES, WIND_ANOMALIES, …) and annotations (ANNOTATIONS) |
operation_id, or site_id for every flight at once |
Both are produced per capture |
Components (TRENCHES, SOLAR_PANELS, FENCES, ROADS, …) |
site_id |
Components are design objects tracked on the site, across flights |
Tickets (PUNCH_LIST_ITEMS) |
site_id |
Tickets persist across flights |
Filtering components or tickets by operation_id returns nothing, because they are not attached
to a single flight.
What a dataset holds
Section titled “What a dataset holds”A dataset’s type says how the data is stored, and its semantic_type says what the data
represents. Only one type holds layer features:
geojson-layer vector
Holds layer features — one row per record, each with its own geometry and properties. These are what /layerFeatures returns.
- deviations, solar anomalies
- trenches, panels, fences and other components
- tickets, annotations
Every other type no features
Imagery, models and files. The data lives in tiles or files rather than in records, so these datasets have no layer features.
tile-layer,tile-layer-raw— visual and thermal orthomosaics, surface models3d-point-cloud,3d-mesh— point clouds and 3D modelsphotos,georeferenced-pdf,dxf
So a thermal orthomosaic and a digital surface model are both stored as tile-layer-raw but differ
in semantic_type (THERMAL versus DIGITAL_SURFACE_MODEL), while deviations and tickets are both
geojson-layer and differ the same way. Querying /layerFeatures for a dataset that is not a
geojson-layer returns nothing — there are no records to return.
type is a filter, not a response field: List datasets returns
semantic_type but not type. To get only the datasets that hold records, filter on it —
GET /datasets?site_id=<id>&type=geojson-layer.
How properties are keyed
Section titled “How properties are keyed”A layer feature’s properties object is keyed by property-definition UUID rather than by name,
because property schemas are configurable per dataset.
List property definitions is the dictionary for those UUIDs —
name, type, and the option list for dropdown properties:
curl -X GET "https://api.sitemark.com/propertyDefinitions?_pageSize=1000" \ -H "Authorization: ApiKey <your-api-key>"Fetch it once, build a UUID → name map, and use it to turn feature properties into readable rows.
Two things to know before you do:
- Resolve across every dataset you have access to rather than filtering by
dataset_id. A dataset can inherit property definitions from a parent dataset, so a UUID on a feature is not always defined on that feature’s own dataset. - Not every key is a UUID. Built-in properties —
STATUS,ASSIGNEE,VOLUMEand the like — are keyed by their own name and are not returned by List property definitions. Leave any key that is not a UUID as it is instead of looking it up.