Skip to main content

Verkada Command

Verkada Command cloud REST API — surfaces the camera and access-door rosters for a Verkada org, polls door lock state, follows the events feed for access activity, and offers remote admin-unlock for doors plus on-demand HLS and thumbnail links for cameras.

One GEM device row = one Verkada org (one API key). One zone per Verkada device you want to surface — a door, a camera, or both.

Prerequisites

  • Verkada Command admin access for the org you want to integrate.
  • An API key minted in Admin → API with the scopes you intend to use:
    • Cameras: Read — for get_cameras, get_camera_link, get_thumbnail.
    • Access: Read — for get_doors, door state polling, the events feed.
    • Access: Write — for unlock (admin pulse) and lock.
  • Outbound HTTPS to api.verkada.com (or your tenant's API base for GovCloud installs). No inbound firewall changes are required.

Setup

  1. Mint an API key. In Command go to Admin → API → "+ Create API Key". Choose only the scopes you need. Copy the key immediately — Verkada does not show it again.
  2. Create the GEM device. Go to System → Devices (Open Devices) and click Add Device. Choose the Verkada Command driver, then paste the key into the Verkada API Key field. The device-level Subsystem picker only matters when a driver auto-creates a zone for the device — this driver does not, so you can leave it; you choose a subsystem per zone in step 5.
  3. Save and reload. On save the driver smoke-tests both rosters against the key. The device shows Connected on the Devices grid as soon as the key validates against at least one roster (cameras or access). If the server log notes (no access scope) or (no camera scope), the key is missing that scope — add it to the key in Command; no GEM change is needed.
  4. Discover the rosters. Open the device and, from its Commands tab, run get_doors and get_cameras. get_doors returns each door's UUID, name, site, online flag, and lock state; get_cameras returns each camera's 16-char camera_id, name, model, and site. Note the id of each door or camera you want to surface — that is the zone address in the next step.
  5. Create one zone per door or camera you want to surface. The driver does not create or discover zones for you — running get_doors / get_cameras only lists what the key can see; it does not add anything to GEM. For each one, add a zone (see Zones) bound to this device and set the zone Address:
    • Access door — Address = the door UUID from get_doors. Place it in the Doors subsystem (or Security if you manage doors alongside the alarm panel).
    • Camera — Address = the 16-char camera_id from get_cameras. Place it in the Cameras subsystem.
  6. Resolve an id collision if one ever occurs. If the same id turns up in both rosters, set the zone-level Verkada Device Type (verkada_type) attribute to door or camera to pin the routing. Otherwise the driver auto-detects by roster lookup, falling back to the id shape (16-char hex → camera, UUID → door).
Subsystem placement

A default GEM install seeds Doors, Gates, Cameras, and Security subsystems — there is no access subsystem, and the camera subsystem is Cameras (plural). When you open the New Zone editor for a Verkada zone it pre-selects Security (the only one of this driver's subsystem hints that matches a seeded subsystem), so change it to Doors or Cameras as appropriate. A zone's subsystem only governs where the door or camera appears in the rest of GEM — it does not affect how the driver talks to Verkada.

Attribute Reference

Device

AttributeRequiredDescription
api_keyyesThe Verkada Command API key. Stored encrypted.
api_basenoOverride the API base URL — set this only for GovCloud / dedicated tenants. Default https://api.verkada.com.
status_intervalnoDoor-roster poll interval in ms. Default 60000.
event_poll_intervalnoAccess-events poll interval in ms. Default 30000. Set to 0 to disable event polling entirely.
enable_event_pollingnoWhen false, skips the events loop even if event_poll_interval > 0. Default true.
unlock_secondsnoDefault unlock pulse duration when the unlock command is called without an explicit duration. Verkada caps at 60 s. Default 5.
request_timeoutnoHTTPS request timeout in ms. Default 15000.

Zone

AttributeDescription
verkada_typeOptional hint — door or camera. Only needed when auto-detection fails.

Zone State Attributes (written by the driver for door zones)

AttributeDescription
stateCoarse state derived from lock_statelocked, unlocked, open, closed, the raw lowercased string when Verkada returns a value the driver doesn't yet map, or unknown when the door reports no lock value.
lock_stateRaw lock state from the API.
lock_statusRaw lock status string when present (some firmware exposes this separately from lock_state).
onlineBoolean — is the access controller reporting in.
site_nameThe Verkada site this door belongs to.
schedule_activeBoolean — is the door currently following a Command schedule.
last_eventMost recent event type seen by the events loop (e.g. door.access_granted, door.forced_open).
last_event_atUnix timestamp of the most recent event.
last_event_userUser name from the most recent event, if present.

Camera zones are not polled for state — the door status loop only refreshes door zones. A camera zone is simply a handle for the on-demand get_camera_link, get_thumbnail, and get_status commands. The access-event attributes (last_event, last_event_at, last_event_user) are cataloged, so they autocomplete in the Attribute editor and can drive attribute triggers; the lock-state attributes above are written live as the door roster is polled, without a catalog entry.

Zone Address Format

  • Door zones: the Verkada door UUID (looks like 12345678-90ab-cdef-1234-567890abcdef).
  • Camera zones: the 16-char hex camera_id (e.g. a1b2c3d4e5f60718).

Commands

CommandArgsNotes
get_camerasList all cameras visible to the API key.
get_doorsList all access doors with lock state and online status.
get_statusaddressRefresh and return current state for one zone. Auto-detects whether it's a door or camera.
unlockaddress, durationAdmin pulse-unlock a door. duration is 1-60 seconds (default 5). Logged in Command audit as "Admin Unlock".
lockaddressSend a lock command to a door. Doors under a Command schedule will reject this — adjust the schedule in Command instead.
get_eventssinceFetch access events newer than the supplied unix timestamp. Defaults to the last 5 minutes.
get_camera_linkaddressReturn a short-lived HLS playback URL for one camera (Verkada expires these in ~15 min).
get_thumbnailaddressReturn a JPEG thumbnail URL for one camera.
refreshForce an immediate door-roster + events sweep.

Known Limitations

  • Camera control surface is read-only. PTZ, recording controls, and audio talk-down are not exposed by the public API and so are not implemented here.
  • Lock is best-effort and schedule-dependent. There is no universal "lock now" verb across every Command build, so the driver issues a lock request and, on doors that are under a Locked or Unlocked schedule block — or where the build doesn't expose the verb — returns a friendly error directing you to set the schedule in Command instead. For deterministic lock control, drive the door's schedule in Command rather than the lock command.
  • Admin-unlock attribution. Verkada audit logs show the unlock as "Admin Unlock" performed by the API key name, not by an end user. If end-user attribution matters, the call needs to go through the user-mode unlock endpoint, which requires a per-user OAuth token rather than the org-level API key — out of scope for this driver.
  • Events watermark drift. The driver tracks the last event timestamp it consumed and only asks for newer events on subsequent polls. A long disconnect will leave the watermark stale; on reconnect, the first sweep may pull a large batch.
  • Camera footage links are ephemeral. get_camera_link returns signed URLs that expire (~15 min). Don't cache them; re-fetch when needed.
  • GovCloud / FedRAMP tenants. Set api_base to the correct hostname for those deployments. The default api.verkada.com will return 401/404 against the wrong tenant.
  • API key scopes are silent. A key missing a scope returns 403 from the call that needs it, not at key creation. The driver logs the HTTP status and the body so missing-scope errors are easy to identify.

Troubleshooting

  • http 401 on every callapi_key is wrong, revoked, or expired. Re-mint in Command.
  • http 403 on a specific endpoint — the key lacks the scope needed for that endpoint. Edit the key in Command and add the scope.
  • http 429 — You're being rate-limited. Raise status_interval and event_poll_interval, and avoid hammering refresh.
  • unknown address; run get_doors or get_cameras — The zone address isn't in either cached roster, and auto-detection failed. Either run get_doors / get_cameras to refresh the cache, or set verkada_type on the zone explicitly.
  • lock not supported by this api key / door — adjust schedule in command — Either the API key lacks Access: Write, or the door is on a schedule that owns lock state. Both are configured in Command.
  • No events appear after enabling event polling — Either the API key lacks Access: Read, or the org has no recent activity. Bump since further back via get_events {since: <unix_ts>} to confirm.
  • Zones — create one zone per door or camera and set its Address.
  • Subsystems — the Doors, Cameras, and Security subsystems these zones belong to.
  • Devices — adding, reloading, and running commands on the Verkada device.
  • Commands — running get_doors / get_cameras and the unlock / lock control commands.