---
title: "Around this alarm: the closed alarms nearby and the cameras that fire with this one"
method: GET
path: "/events/{event_id}/around"
tags: ["events"]
---

# Around this alarm: the closed alarms nearby and the cameras that fire with this one

`GET /events/{event_id}/around`

## Request

- Base URL: `https://api.verdun.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.verdun.ai/events/{event_id}/around`
- Auth: HTTP bearer

The context rail for one alarm. `anchor` is the alarm; `graph.neighbours` are the cameras that co-fire with its camera over 30 days (cached per site per hour; `graph.status` says ready / stale / unavailable and the rail still works without it); `items` are the CLOSED alarms in the window `before_minutes` before to `after_minutes` after the anchor, newest first, as three kinds: `reviewed` (an operator closed it), `filtered` (stopped before AI review by a pre-processing gate, DeepAlert and its confirmers) and `agent_closed`. `scope=related` (default) draws from the anchor's camera and its neighbours; `scope=site` from every camera at the site. `counts` always covers the whole window for the related cameras and the rest of the site, so the console can say how much is not shown. Open alarms are not returned (they are in the queue, and new ones arrive over the push stream). Open an item with `GET /events/{event_id}` and `/clip-url`. Central staff only (`require_central_staff`: owner, monitoring manager, operator, support, read-only), and tenant-scoped like every per-event read: an alarm outside the caller's scope and an unknown id are both 404, and only cameras the caller may see are read. `ALARM_CONTEXT_ENABLED` off answers 200 `status: "disabled"` with nothing else, before any alarm-context database work (authentication and the caller's scope load still run): show no rail. A feed or counts query that fails or hits its 3 s deadline answers 200 `status: "degraded"` with no items: say the rail is unavailable and retry later. This is an optional-rail fallback, not an end-to-end latency guarantee.

## Path parameters

- `event_id` string, uuid, required

## Query parameters

- `before_minutes` integer: Minutes before the alarm to read
- `after_minutes` integer: Minutes after the alarm to read
- `scope` 'related' | 'site': `related`: this camera and its neighbours. `site`: every camera at the site
- `limit` integer: Most items to return

## Response `200`

Successful Response

- AlarmContextResponse
  - `status` 'ok' | 'degraded' | 'disabled', required: `ok`; `degraded`: the feed query hit its deadline, items and counts are empty, the rail should say it is unavailable and may retry; `disabled`: ALARM_CONTEXT_ENABLED is off, show no rail (nothing else in this body is filled in).
  - `enabled` boolean, required: False exactly when status is `disabled`
  - `anchor` AlarmContextAnchor
    - `event_id` string, required: The alarm the rail is built around
    - `camera_id` string, required: The anchor alarm's camera
    - `camera_name` string, required: That camera's label
    - `site_id` string, required: The anchor alarm's site
    - `created_at` string, date-time, required: When the anchor alarm fired
  - `window` AlarmContextWindow
    - `start` string, date-time, required: Start of the window the rows are drawn from (alarm time)
    - `end` string, date-time, required: End of the window (alarm time)
    - `before_minutes` integer, required: Minutes before the anchor alarm that were read
    - `after_minutes` integer, required: Minutes after the anchor alarm that were read
  - `scope` 'related' | 'site', nullable: Which cameras `items` was drawn from (the request's scope parameter)
  - `graph` AlarmContextGraph
    - `status` 'ready' | 'stale' | 'unavailable', required: `ready`: this hour's graph. `stale`: an earlier graph, served because this hour's could not be built right now. `unavailable`: no graph yet (first request for the site after a restart, or builds are failing); `neighbours` is then empty and the rail has only the anchor camera.
    - `reason` string, nullable: Why the status is not `ready`: `building` (another request or task is building it), `busy` (this process is already building its maximum number of graphs), `backoff` (a recent build failed), `timeout`, `over_budget`, `error`
    - `built_at` string, date-time, nullable: When the graph served here was built
    - `window_days` integer, required: Length of the history the graph is learned from
    - `truncated` boolean: True when the graph was built within its work budget: the site had more events than the event cap (only the newest were used) or more cameras than the camera cap (only the first were candidates). The feed, counts and anchor are never limited by this.
    - `neighbours` AlarmContextNeighbour[], required: The anchor camera's neighbours, strongest first; never includes the anchor camera
      - `camera_id` string, required: A camera that co-fires with the anchor alarm's camera
      - `camera_name` string, required: That camera's label
      - `cofire_count` integer, required: Times, over the graph's window, one of the two cameras fired and the other followed within 60 s (both directions summed; storm minutes excluded)
      - `expected_cofire` number, required: How many co-fires chance alone would give, from the two cameras' firing rates
      - `lift` number, required: cofire_count / expected_cofire. Higher means more likely adjacent
  - `items` AlarmContextItem[]: Newest first, at most `limit`
    - `event_id` string, required: Open it with GET /events/{event_id} and /clip-url
    - `camera_id` string, required: The camera this alarm fired on
    - `camera_name` string, nullable: Null for a camera that is no longer at the site
    - `created_at` string, date-time, required: When the alarm fired
    - `offset_seconds` number, required: created_at minus the anchor alarm's, in seconds; negative = before
    - `relation` 'self' | 'neighbour' | 'site', required: `self`: the anchor alarm's camera. `neighbour`: a camera in the graph's neighbour list. `site`: any other camera at the site (only returned with scope=site)
    - `kind` 'reviewed' | 'filtered' | 'agent_closed', required: `reviewed`: closed by an operator. `filtered`: stopped before AI review by a pre-processing gate (DeepAlert, or its confirmers). `agent_closed`: closed by the agent. Open alarms are not here; they are already in the operator's queue and arrive over the push stream.
    - `disposition` string, nullable: The disposition label as the History list shows it
    - `closed_at` string, date-time, nullable: When it was closed
    - `closed_by_operator_id` string, nullable: The closing operator (`reviewed` only)
    - `closed_by_name` string, nullable: The closing operator's name (`reviewed` only)
    - `summary` string, nullable: The ingestor's trigger text for the alarm ("Motion confirmed by <provider>: <labels>", or the placeholder "Something is happening" when the motion validator named nothing). It is NOT a read of the alarm and the console no longer prints it on the rail; use `vlm_summary`.
    - `vlm_summary` string, nullable: The VLM's one-line read of this alarm: the rationale of the event's NEWEST interpretation row (by created_at, then id), whitespace collapsed and cut at 240 characters on a word boundary with a trailing ellipsis. Null (never the ingestor placeholder, never an older read) when the newest row is not a VLM read: no interpretation, a gate stop (DeepAlert filtered), the fail-safe sentinel, a VLM-fallback envelope, or an empty rationale; also null for every row when the optional lookup failed or is cooling down after a failure. Absent from an older api.
  - `truncated` boolean: True when more rows matched than `limit` returned
  - `counts` AlarmContextCountsByRelation
    - `related` AlarmContextCounts, required
      - `reviewed` integer: Alarms an operator closed
      - `filtered` integer: Alarms stopped before AI review by a pre-processing gate (DeepAlert and its confirmers)
      - `agent_closed` integer: Alarms the agent closed
    - `rest_of_site` AlarmContextCounts, required
      - `reviewed` integer: Alarms an operator closed
      - `filtered` integer: Alarms stopped before AI review by a pre-processing gate (DeepAlert and its confirmers)
      - `agent_closed` integer: Alarms the agent closed

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/verdun/apis/verdun-api.md) - [All operations](https://skmtc.dev/verdun/apis/verdun-api/llms.txt) - [OpenAPI document](https://skmtc.dev/verdun/apis/verdun-api/revisions/a19366be50a3?raw)
