> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vangrid.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Monitoring Critical Infrastructure with Vangrid

> Stream continuous ground truth from Vangrid edge nodes to detect anomalies, track changes, and protect critical infrastructure assets in real time.

Power grids, water systems, transportation networks, and industrial facilities share a common vulnerability: physical change — an intrusion, equipment failure, or environmental shift — can escalate into a serious incident within minutes. Traditional monitoring relies on scheduled inspections or sparse fixed cameras that miss transient events entirely. Vangrid gives your operations team continuous spatial ground truth over any defined geographic zone, so anomalies are detected the moment they appear and your systems can respond before an incident compounds.

## Key capabilities for infrastructure monitoring

<CardGroup cols={2}>
  <Card title="Continuous ground truth" icon="satellite-dish">
    Edge nodes stream observations continuously. Your monitoring system always has a current spatial picture of the area, not a snapshot from the last scheduled scan.
  </Card>

  <Card title="Spatial change detection" icon="bell">
    Compare incoming observations against a known baseline to identify deviations — new objects, removed infrastructure, access-point breaches, or environmental changes like flooding.
  </Card>

  <Card title="Streaming updates" icon="bolt">
    The Vangrid streaming API delivers Server-Sent Events so your alerting and SCADA systems receive spatial updates in real time over a persistent connection without polling.
  </Card>

  <Card title="Polygon AOI targeting" icon="draw-polygon">
    Define your monitoring zone with a precise GeoJSON polygon — a substation perimeter, a pipeline corridor, a port facility — and receive observations scoped exactly to that area.
  </Card>
</CardGroup>

## Infrastructure types supported

Vangrid's edge network covers a range of physical infrastructure environments:

<AccordionGroup>
  <Accordion title="Energy — power grids and substations">
    Monitor substation perimeters, transmission corridor right-of-ways, and generation facility boundaries. Detect unauthorized access, equipment displacement, or vegetation encroachment in real time.
  </Accordion>

  <Accordion title="Water — treatment plants and distribution networks">
    Maintain continuous spatial awareness of facility perimeters and intake zones. Identify physical access events or structural changes that could indicate tampering or damage.
  </Accordion>

  <Accordion title="Transportation — rail, road, and ports">
    Stream ground truth over rail corridors, highway segments, and port facilities. Detect stopped vehicles, track intrusions, or identify infrastructure damage affecting operations.
  </Accordion>

  <Accordion title="Industrial — refineries, pipelines, and manufacturing sites">
    Monitor large-footprint industrial sites where perimeter length makes physical patrol impractical. Receive spatial change alerts the moment conditions deviate from a known-good baseline.
  </Accordion>
</AccordionGroup>

## Use case walkthrough: infrastructure perimeter monitoring

This walkthrough sets up a streaming spatial subscription for a power substation perimeter and routes anomaly events to your alert system.

<Steps>
  <Step title="Define your monitoring zone">
    Model the infrastructure perimeter as a GeoJSON polygon. For a substation, this is typically the fence line plus a small outer buffer. Keep the polygon as tight as practical — a focused AOI reduces noise and keeps the `ground_truth_score` high by concentrating node coverage.

    ```json substation-perimeter.json theme={null}
    {
      "type": "Polygon",
      "coordinates": [[
        [-87.6520, 41.8340],
        [-87.6490, 41.8340],
        [-87.6490, 41.8370],
        [-87.6520, 41.8370],
        [-87.6520, 41.8340]
      ]]
    }
    ```
  </Step>

  <Step title="Establish a streaming subscription">
    Open a persistent streaming connection to `/v1/spatial/stream` with your perimeter polygon. Set a `ground_truth_score_min` threshold to suppress low-confidence observations before they reach your alert logic.

    <CodeGroup>
      ```bash curl theme={null}
      curl -N -X GET \
        "https://api.vangrid.io/v1/spatial/stream?geometry=POLYGON((-87.6520+41.8340,-87.6490+41.8340,-87.6490+41.8370,-87.6520+41.8370,-87.6520+41.8340))&ground_truth_score_min=0.92" \
        -H "Authorization: Bearer $VANGRID_API_KEY" \
        -H "Accept: text/event-stream"
      ```

      ```python python theme={null}
      import os
      import json
      import requests

      api_key = os.environ["VANGRID_API_KEY"]

      params = {
          "geometry": (
              "POLYGON((-87.6520 41.8340,-87.6490 41.8340,"
              "-87.6490 41.8370,-87.6520 41.8370,-87.6520 41.8340))"
          ),
          "ground_truth_score_min": "0.92",
      }

      with requests.get(
          "https://api.vangrid.io/v1/spatial/stream",
          headers={
              "Authorization": f"Bearer {api_key}",
              "Accept": "text/event-stream",
          },
          params=params,
          stream=True,
      ) as response:
          for line in response.iter_lines():
              if line:
                  raw = line.decode("utf-8")
                  if raw.startswith("data: "):
                      event = json.loads(raw[6:])
                      handle_spatial_event(event)
      ```
    </CodeGroup>
  </Step>

  <Step title="Detect anomalies in the stream">
    Each streamed event includes an array of `data_points`. Inspect each point's `observation` field for values that indicate a change from the expected state. Route anomalous observations to your incident management or SCADA system.

    ```python python theme={null}
    def handle_spatial_event(event):
        anomaly_observations = {
            "obstruction_detected",
            "unauthorized_access",
            "structural_change",
            "perimeter_breach",
        }

        for point in event.get("data_points", []):
            if point["observation"] in anomaly_observations:
                trigger_alert(
                    zone="substation-perimeter",
                    observation=point["observation"],
                    lat=point["lat"],
                    lon=point["lon"],
                    confidence=point["confidence"],
                    provenance_hash=point["provenance_hash"],
                    captured_at=point["captured_at"],
                )
    ```

    <Tip>
      Store the `provenance_hash` from every anomaly event alongside your incident record. This gives you a tamper-evident audit trail that you can use for post-incident review, regulatory reporting, or legal proceedings.
    </Tip>
  </Step>

  <Step title="Fall back to on-demand queries during stream interruptions">
    If a streaming connection drops — due to network conditions or a maintenance window — your monitoring system should fall back to polling `/v1/spatial/query` on a short interval until the stream reconnects. This ensures you have no unmonitored windows during the transition.

    ```python python theme={null}
    import time

    def poll_until_stream_reconnects(geometry, interval_seconds=10):
        while True:
            response = requests.post(
                "https://api.vangrid.io/v1/spatial/query",
                headers={
                    "Authorization": f"Bearer {os.environ['VANGRID_API_KEY']}",
                    "Content-Type": "application/json",
                },
                json={
                    "aoi": geometry,
                    "max_age_seconds": interval_seconds,
                    "min_ground_truth_score": 0.92,
                },
            )
            handle_spatial_event(response.json())
            time.sleep(interval_seconds)
    ```
  </Step>
</Steps>

## Example streaming event

A typical streaming event for a perimeter monitoring subscription looks like this:

```json theme={null}
{
  "query_id": "stream_7c4a1f9e2d3b8605",
  "timestamp": "2026-05-22T07:33:15.882Z",
  "node_count": 88,
  "ground_truth_score": 0.95,
  "data_points": [
    {
      "node_id": "node_1d7c4f",
      "lat": 41.8352,
      "lon": -87.6508,
      "observation": "clear",
      "confidence": 0.97,
      "captured_at": "2026-05-22T07:33:15.441Z",
      "provenance_hash": "sha256:d1a9f3e7c4b2605ae9d1c4f3b7a2e1d9c4f7a3e2"
    },
    {
      "node_id": "node_8a2e6b",
      "lat": 41.8361,
      "lon": -87.6513,
      "observation": "perimeter_breach",
      "confidence": 0.93,
      "captured_at": "2026-05-22T07:33:15.709Z",
      "provenance_hash": "sha256:f3a1d9e7b4c2605fd1a9c4e3b7f2a1d9e4c7b3f1"
    }
  ],
  "provenance_hash": "sha256:e4b7f1c9a3d2605be4c7a1f9d3b2e7c4a1d9f3b2"
}
```

<Warning>
  A streaming event with `ground_truth_score` below 0.80 means fewer than the expected number of edge nodes contributed observations for that interval. Do not suppress alerts during low-score periods — treat them as periods of reduced visibility and increase your alert sensitivity accordingly.
</Warning>

## Relevant concepts

<CardGroup cols={3}>
  <Card title="Ground truth" icon="circle-check" href="/concepts/ground-truth">
    How `ground_truth_score` is calculated and what thresholds are appropriate for monitoring applications.
  </Card>

  <Card title="Data pipeline" icon="arrow-right-arrow-left" href="/concepts/data-pipeline">
    How observations move from edge capture to your streaming endpoint, including latency characteristics.
  </Card>

  <Card title="Cryptographic provenance" icon="fingerprint" href="/data/cryptographic-provenance">
    How to use `provenance_hash` values for audit trails and post-incident verification.
  </Card>
</CardGroup>
