API Contracts

The API shape from gist's DSL (SpatialPortalAPI, v0.2) — run-oriented evaluation plus a relationships query and an Orchestrator health probe. Contracts are versioned under /api/v1. These are the specified contracts; the runtime API is Phase 2 (page 11).

Layers

GET /api/v1/tenants/{tenant_code}/layers
GET /api/v1/tenants/{tenant_code}/layers/{layer_code}/features   ?status= &bbox=

Features

GET   /api/v1/features/{feature_id}
POST  /api/v1/features                    (permission feature.create)
PATCH /api/v1/features/{feature_id}       (permission feature.edit; partial body)

A geometry change triggers rule evaluation when enabled (see TriggerDefinition, page 07).

Spatial evaluation

POST /api/v1/spatial/evaluate     → SpatialEvaluationRun
{
  "source_feature_id": "uuid",
  "target_feature_id": "uuid (optional)",
  "rule_code": "ROAD_INTERSECTS_MINING_LEASE (optional)",
  "trigger_code": "FEATURE_GEOMETRY_CHANGED (optional)"
}

Returns the run (status, candidate/match counts, metrics), not a bare relationship list — the relationships it produced are read separately:

GET /api/v1/relationships          ?feature_id= &status=      → list<SpatialRelationship>

Events

GET  /api/v1/events                ?tenant_code= &status= &correlation_id=   → list<SpatialEvent>
POST /api/v1/events/{event_id}/acknowledge                                   → SpatialEvent

Import / export

POST /api/v1/import/geojson        (body geojson)   → DataTransfer
GET  /api/v1/export/geojson        ?tenant_code= (required) &layer_code=     → geojson

Integration health

GET /api/v1/integrations/orchestrator/health   → { "available": bool, "checked_at": datetime }

Error envelope

{
  "error": {
    "code": "GIS_FEATURE_INVALID_GEOMETRY",
    "message": "Polygon geometry is invalid.",
    "details": {}
  },
  "correlation_id": "..."
}

Note vs. the starter pack: the starter returned list<SpatialRelationship> from /evaluate and exposed an inbound POST /api/v1/webhooks/orchestrator. gist (v0.2) is run-oriented (/evaluate → SpatialEvaluationRun, GET /relationships) and replaces the inbound webhook with the Orchestrator health probe above.