sites
post/sites/

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

Request body

parent_idstring uuid required

The ID of the parent site.

account_idstring uuid nullable

Optional account (the client's customer) to group this site under. The account must belong to the same client as parent_id. Omit or null to place the site directly under the client.

namestring required

The name of the site.

addressstring required

The address of the site.

citystring required

The city of the site.

statestring required

The state of the site.

zip_codestring required

The 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 nullable

IANA timezone the site's monitoring schedule is evaluated in. Omit to use the server default.

police_nearest_precinct_namestring required

The name of the police nearest precinct.

police_non_emergency_linestring required

The police non-emergency line.

police_direct_dispatch_linestring nullable

The direct dispatch line.

police_jurisdiction_notesstring nullable required

The jurisdiction notes.

alarm_license_numberstring nullable

The dealer's alarm license number for this site's state or city.

alarm_license_issuerstring nullable

Who issued the alarm license.

mobile_guard_contractboolean required

The mobile guard contract is available.

stage'live' | 'test' nullable

'test' or 'live' (a display label only). Omit or send null for the default, 'test'.

guard_companystring nullable

Mobile guard company name.

guard_unitstring nullable

Mobile guard unit or contact identifier.

guard_contactstring nullable

Mobile guard dispatch phone.

Example request

{
  "name": "San Diego Sewing Site",
  "address": "1234 cherry hairy lane",
  "city": "San Diego",
  "state": "CA",
  "zip_code": "123456",
  "timezone": "America/Los_Angeles",
  "police_nearest_precinct_name": "SD Police",
  "police_non_emergency_line": "1234555",
  "police_direct_dispatch_line": "123456",
  "police_jurisdiction_notes": "They own here",
  "alarm_license_number": "127.001463",
  "alarm_license_issuer": "Illinois",
  "mobile_guard_contract": true,
  "stage": "test",
  "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"
        }
      ]
    }
  ]
}

Response

Successful Response

stage'live' | 'test' nullable

The stored site stage, a display label only. New sites default to '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). Who set a mark is never exposed. Empty when none.

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.

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

{
  "stage": "test",
  "onboarding_marks": {
    "first_night": "2026-10-13T08:00:00.000Z"
  },
  "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"
    }
  ],
  "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 new optional request property

    • info

      added the new optional request property

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status