---
title: "Arm Site For Testing"
method: POST
path: "/sites/{site_id}/arm"
tags: ["sites"]
---

# Arm Site For Testing

`POST /sites/{site_id}/arm`

## 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/sites/{site_id}/arm`
- Auth: HTTP bearer

Hold this site's cameras ON for a bounded test (0104).

Refused with a 409 while a customer's disarm is live — their decision is
not cancelled by our install test.

## Path parameters

- `site_id` string, required

## Request body

- ArmSiteRequest
  - `minutes` integer, required: How long the site's cameras should stay on for testing, in minutes, even though the schedule has them off. 1-120; anything above 120 is a 422 here, so the service's clamp never fires through this API and the response's `clamped` is always false. The site's disarm_max_minutes deliberately does NOT apply.

## Response `200`

Successful Response

- ArmStateResponse: The site's live TEST ARM state after a console arm or end-arm (0104). The mirror of `DisarmStateResponse`: the same four fields the site serializers carry for the arm window, so the console can apply the response to its cached site without a refetch, plus what the request resolved to and the two derived schedule fields. The two features are ONE state machine with two directions, so the same traps apply — above all, a non-null `arm_until` does NOT mean armed.
  - `site_id` string, uuid, required: The site whose cameras this concerns.
  - `arm_until` string, date-time, nullable: When the test window ends by itself and the cameras go back to their schedule. Ending a test early sets this to the moment it ended rather than nulling it, so the window that really happened stays readable historically — which means a non-null value does NOT mean 'armed for testing'. Read `arm_active` for that. Expiry is implicit; nothing sweeps this column.
  - `arm_set_at` string, date-time, nullable: When the current test window began. The resolver's predicate is the window between this and arm_until, so a historical read is not repainted by a test started later. An extend inside a live window keeps the original value.
  - `arm_by` string, nullable: Who started the test: always 'operator:<uuid>'. The console is the only channel into a test arm, so unlike disarm_by this never carries a customer's phone number. Retained after the window is closed early, alongside the closed window.
  - `arm_active` boolean: Whether this site's cameras are on FOR A TEST right now — the window predicate, resolved server-side. Always false on an end-arm response. Never derive this from arm_until.
  - `minutes` integer, nullable: Minutes actually applied, after clamping to the 120-minute product ceiling; null on an end-arm.
  - `clamped` boolean: True when the request asked for longer than the arm's ceiling and was shortened. ALWAYS FALSE THROUGH THIS API TODAY: the request model refuses anything above 120 minutes and the arm clamps to that same ceiling only (never to the site's disarm_max_minutes). Kept for contract symmetry with DisarmStateResponse and so that a later decision to clamp arms to the site cap is not a contract change.
  - `monitoring_now` string, nullable: Live View only (site flag or every live camera individually flagged) reads 'live_view_only' and overrides both arm and disarm windows. Otherwise: Whether this site's cameras are being monitored RIGHT NOW, resolved server-side. A live test arm reads 'monitored' — it is not a fifth value; read arm_active to tell a test apart from the schedule doing it. 'disarmed' still wins over a test arm, though a successful arm cannot return it (the route refuses while a disarm is live). On an end-arm response this is what the SCHEDULE leaves behind, which is the whole point: ending a test on an off-schedule site reports 'off_schedule'.
  - `schedule_monitoring_now` string, nullable: The current schedule-only monitoring state, ignoring Live View only flags, the test arm and the disarm window. Resolved at the same instant as monitoring_now. This is what lets the console say 'on for a test; the schedule has this site off until 7:00 AM'.
  - `monitoring_next_change_at` string, date-time, nullable: The next instant this site's monitored/off state flips BY SCHEDULE ALONE — the test window is deliberately ignored, because you already have arm_until above. Null when nothing changes within 7 days and for an 'unscheduled' site. Aligned to a 15-minute boundary in the site's own timezone.

## 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/35a2a6ebedda?raw)
