sites
get/sites/{site_id}

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}
  • Auth
    HTTP bearer

Path parameters

site_idstring required

Response

Successful Response

idstring uuid required

Unique identifier of the site

account_idstring uuid nullable

Account (the client's customer) this site is grouped under; null = directly under the client. This is the ONLY expression of account membership -- group sites by it client-side.

namestring required

Name of the site

addressstring required

Address of the site

citystring required

City of the site

statestring required

State of the site

zip_codestring required

Zip code of the site

type'Commercial' | 'Car Dealership' | 'Construction' | 'Residential' | 'Logistics' | 'Education' | 'Healthcare' | 'Utilities' | 'Other' required
priority_tier'critical' | 'high' | 'medium' required
monitoring_hours'Nights' | 'All Day' | 'Weekends' | 'Custom' required
timezonestring required

IANA timezone the site's monitoring schedule is evaluated in

police_nearest_precinct_namestring required

Police nearest precinct name

police_non_emergency_linestring required

Police non-emergency line

police_direct_dispatch_linestring nullable

Police direct dispatch line

police_jurisdiction_notesstring nullable

Police jurisdiction notes

alarm_license_numberstring nullable

Dealer alarm license number

alarm_license_issuerstring nullable

Who issued the alarm license

mobile_guard_contractboolean required

Mobile guard contract available?

guard_companystring nullable

Mobile guard company name.

guard_unitstring nullable

Mobile guard unit or contact identifier.

guard_contactstring nullable

Mobile guard dispatch phone.

agent_contextstring nullable

Site-wide scene context composed into the LLM prompt for every camera at this site.

agent_thread_window_minutesinteger nullable

Incident-thread join window for this site's agent cameras, in minutes; null = global default.

heightened_exceptionsobject[] nullable

Owner-curated heightened-monitoring exception categories; null = none.

holidaysobject[] nullable

Per-site closure calendar: on each listed site-local day every schedule cell that would read 'off' reads 'monitored' instead. Entries are {'rule': <catalog key>} or {'date': 'YYYY-MM-DD', 'label': str}. Managed through GET/PUT /sites/{id}/holidays; null on a payload built before the column existed.

stage'live' | 'test' nullable

'test' or 'live'. A display label only: the console badges test sites; monitoring, reporting and billing are identical for both. New sites start as 'test'.

closedboolean nullable

Closed site: any human activity warrants an immediate police call. A display flag only (the console badges it); nothing else branches on it. Set via PUT /sites/{id}/closed.

onboarding_marksobject

Onboarding checklist marks: mark key -> when it was set (ISO-8601 UTC). Keys: setup_call, first_night, streaming_test, skip:setup_call, skip:instructions, skip:passcode, skip:speakers, skip:holidays, completed. Who set a mark is never exposed. Empty when none.

map_modestring nullable

Map-tab mode: 'geo' (geographic pin) or 'floorplan' (uploaded plan); null = not configured.

map_latnumber nullable

Geographic latitude of the site pin (geo mode).

map_lngnumber nullable

Geographic longitude of the site pin (geo mode).

floorplan_widthinteger nullable

Natural pixel width of the uploaded floor plan.

floorplan_heightinteger nullable

Natural pixel height of the uploaded floor plan.

has_floorplanboolean

Whether a floor-plan image is uploaded (fetch it via GET /sites/{id}/floorplan-url).

disarm_untilstring date-time nullable

End of the current or most recent disarm window. NOT a null-means-armed flag: an early re-arm sets this to the re-arm instant, so it is non-null for every site that has ever been disarmed; read disarm_active for the live state. Expiry is implicit -- nothing sweeps it.

disarm_set_atstring date-time nullable

When the current disarm window began. The resolver's predicate is the window between this and disarm_until, so a historical read is never repainted by a disarm set later.

disarm_bystring nullable

Who turned the cameras off: 'sms:<E.164>' for a customer text, 'voice:<E.164>' for a customer call, 'operator:<uuid>' from the console.

disarm_activeboolean

Whether this site's cameras are off RIGHT NOW because of a text-to-disarm. Resolved server-side from the same window predicate the ingest gate uses -- do NOT recompute it from disarm_until, which stays set at the moment an early re-arm ended the window and so is non-null for every site that has ever been disarmed.

arm_untilstring date-time nullable

End of the current or most recent TEST ARM window, during which an operator held the cameras on outside the schedule. NOT a null-means-off flag: ending a test early sets this to that instant, so it is non-null for every site ever tested; read arm_active for the live state.

arm_set_atstring date-time nullable

When the current test-arm window began. The resolver's predicate is the window between this and arm_until, so a historical read is never repainted by a test started later.

arm_bystring 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.

arm_activeboolean

Whether this site's cameras are on FOR A TEST right now. Resolved server-side from the same window predicate the ingest gate uses -- do NOT recompute it from arm_until. A live disarm beats a live test arm, and starting a disarm ends the test outright.

disarm_max_minutesinteger nullable

The longest a single disarm may last at this site (1-120).

live_view_onlyboolean

Live View only: every camera at this site is connected for Live View with no AI and no alarms (monitoring state always off), whatever the schedule, disarm or test arm say.

has_disarm_passcodeboolean

Whether this site has a disarm passcode. Read the code through the dedicated disarm-passcode endpoint.

disarm_passcode_hintstring nullable

Last two characters of the stored passcode, for rendering it as '****92'.

disarm_passcode_revisionstring nullable

Opaque revision that changes whenever the passcode is minted or reset, including when its hint is unchanged.

monitoring_nowstring 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: 'disarmed' (a live text/call/console disarm window - it beats every schedule), 'monitored' (at least one live camera resolves monitored or heightened now), 'off_schedule' (no camera is monitored now, but the schedule turns one on within 7 days - see monitoring_next_change_at), or 'unscheduled' (no monitored hours anywhere in the week). Derived, never stored. Null on payloads that embed a site incidentally (an event); ask a site endpoint. Do NOT derive this from the schedule grid client-side.

monitoring_next_change_atstring date-time nullable

The next instant this site's monitored/off state flips BY SCHEDULE ALONE - the disarm window is deliberately ignored, because the console already has disarm_until. Null when nothing changes within 7 days and for an 'unscheduled' site. Aligned to a 15-minute boundary in the site's own timezone.

Example response

{
  "name": "San Diego Sewing Company - 1",
  "address": "1234 Hairy Cherry Lane",
  "city": "Shanghai",
  "state": "CA",
  "zip_code": "78912",
  "timezone": "America/Los_Angeles",
  "police_nearest_precinct_name": "SD Police hehe",
  "police_non_emergency_line": "1231231234",
  "police_direct_dispatch_line": "32133",
  "police_jurisdiction_notes": "This is the police",
  "alarm_license_number": "127.001463",
  "alarm_license_issuer": "Illinois",
  "mobile_guard_contract": true,
  "agent_context": "Gated storage facility; groundskeeper drives a white pickup weekday mornings.",
  "agent_thread_window_minutes": 5,
  "heightened_exceptions": [
    {
      "description": "Navy uniforms with badge",
      "label": "Uniformed security"
    }
  ],
  "holidays": [
    {
      "rule": "thanksgiving"
    },
    {
      "date": "2026-12-24",
      "label": "Christmas Eve half day"
    }
  ],
  "stage": "test",
  "onboarding_marks": {
    "first_night": "2026-10-13T08:00:00.000Z"
  },
  "map_mode": "geo",
  "map_lat": 42.0442,
  "map_lng": -87.9816,
  "floorplan_width": 1200,
  "floorplan_height": 800,
  "has_floorplan": true,
  "disarm_until": "2026-09-05T21:15:00Z",
  "disarm_set_at": "2026-09-05T19:45:00Z",
  "disarm_by": "sms:+18015550142",
  "disarm_active": true,
  "arm_until": "2026-09-18T04:30:00Z",
  "arm_set_at": "2026-09-18T04:00:00Z",
  "arm_by": "operator:6f1c8f2a-...",
  "arm_active": true,
  "disarm_max_minutes": 120,
  "has_disarm_passcode": true,
  "disarm_passcode_hint": "92",
  "monitoring_now": "monitored",
  "monitoring_next_change_at": "2026-09-08T04:30:00Z",
  "contacts": [
    {
      "first_name": "1231231234",
      "last_name": "1231231234",
      "role": "Security Manager",
      "primary_phone_number": "1231231234",
      "afterhours_phone_number": "1231231234",
      "email": "JJ@example.com",
      "availability": [
        {
          "days": [
            0,
            1,
            2,
            3,
            4
          ],
          "end": "17:00",
          "start": "08:00"
        }
      ]
    }
  ]
}

Changes

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status