Measurement Annotation Persistence
Stable measurement identities, conflict handling, and personal trade profiles.
Ordinary length, area and count measurements use the annotation endpoints. Trade
classification, material, presentation, quantity and source-frame metadata belong
to the measurement payload. They are independent of the annotation's
measurement_note category. Volume calculations retain their dedicated
definition and calculation workflow.
Capability and Identity
GET /v1/spatial/locations/{locationId}/annotations returns items,
hasNextPage and annotationPersistenceVersion: 2. Clients must check this
capability before making annotations authoritative for legacy measurements.
Pages exclude deleted annotations. They are not an incremental deletion feed;
updatedSince alone cannot establish the complete current inventory.
Create a measurement with POST /v1/spatial/locations/{locationId}/annotations
and a stable clientKey of 1–256 characters. The location/key combination is
unique, including deleted records. Retrying identical content returns the same
annotation. Reusing a key for different content or a deleted record returns
HTTP 409 (annotation_identity_conflict). Concurrent creates can also produce
409; reload and compare the saved record before retrying. Never invent a new key
merely to bypass a conflict. Unkeyed legacy creates are also rejected when the
envelope identifies a measurement already reserved by the canonical
pixmeas-v1: SHA-256 key, including tombstones.
Responses include clientKey and a decimal string revision. Existing
unkeyed records may acquire a key through a conditional PATCH. Once assigned,
a key cannot be changed or cleared. Volume annotations do not accept these keys.
Conditional Changes and Deletion
Send the last observed string baseRevision and matching clientKey with PATCH.
A missing or mismatching key on a keyed row returns 409 (annotation_identity_required),
preventing older config-shadow clients from overwriting migrated data even after
fetching a fresh revision. Keyed measurements
require the exact record revision, including when changes touch different fields:
the payload and coordinate frame form one measurement. Ordinary unkeyed notes
retain the existing field-level conflict behavior. A stale measurement write
returns HTTP 409 and must not overwrite the remote record automatically.
Delete keyed measurements with:
DELETE /v1/spatial/annotations/{annotationId}?baseRevision=7The revision must match. Missing or stale preconditions return 409; malformed revisions return 400. The server retains a tombstone and the identity reservation so a delayed create cannot resurrect deleted work. Deleted rows are excluded from ordinary reads, lists, counts and shared-model annotation delivery. A missing/deleted annotation does not invalidate surviving captured model content.
Location and document authorization applies before identity lookup and mutation. The API never takes the measurement author from a caller-supplied user ID.
Payload and Migration
Ordinary note bodies remain limited to 4,000 characters. Measurement-note bodies
may contain a validated __pixmeas: 1 JSON envelope up to 262,144 characters,
including the measurement ID/type, coordinate-space marker, checksum and data.
The client is responsible for verifying the complete payload, source/frame and
checksum before rendering or declaring a legacy migration verified. A local
payload's placeholder WGS84 coordinates are not replacement measurement points.
Keep a recoverable legacy snapshot and pending edits until every migrated row has been reloaded and verified. Partial inventory, failed writes, malformed payloads and revision conflicts must block authoritative completion. Never interpret an incomplete or failed load as an empty dataset to save over.
The additive schema migration preserves existing annotation revisions and content. Downgrade refuses to discard keys, tombstones, larger bodies or saved user preferences; reconciliation/export is required before removing that schema.
Personal Picker Default
Read and save defaultMeasurementProfileId through GET/PATCH /v1/users/me.
Profiles are roofing, roadworks, utilities and earthworks; unset accounts
use roofing. This is a personal preference across devices. Several users may
work on the same model with different defaults. Switching a picker profile
never changes saved classifications or filters persistence and reports.