Skip to main content

Salto KS

Cloud control for Salto KS — Salto's cloud-managed commercial access-control platform — over the public Connect API. The driver performs online unlock / lock, lock-roster and battery reads, user enumeration, and audit-feed polling for last-event surfacing. Each online lock is exposed as a GEM zone you create by hand.

Online locks only. Offline-only hardware (classic XS4, or an IQ Door / Neo Cylinder without the online module) is programmed through the Salto Space client and is out of scope here. Salto SIP video stations are also out of scope — use a dedicated intercom driver (e.g. aiphone_ix, butterflymx, comelit_vip) for door-station video.

Prerequisites

  • A Salto KS subscription with the Connect API add-on enabled by Salto support. The API is not exposed on a stock KS account — submit a request through your Salto rep before commissioning.
  • A client_id / client_secret pair minted in the KS portal under Account → API Credentials. Note the scopes granted; this driver assumes at minimum:
    • locks:read
    • locks:write
    • users:read
    • audit:read
  • Online locks (XS4 One, Neo Cylinder with online module, IQ Door on the online tier). Pure offline locks are still returned by get_locks, but unlock against them fails with a Salto-side error.

Setup

  1. In the Salto KS portal → Account → API Credentials, create a new credential pair. Copy both the client_id and client_secret.
  2. Add the device. Go to System → Devices → Add Device and pick the Salto KS driver (key salto_ks).
  3. Enter credentials. Paste the client_id into the Client ID field and the client_secret into the Client Secret field. (Those two fields are the username / password attributes under the hood; the dedicated client_id / client_secret attribute names also work if you prefer to enter them directly.)
  4. Endpoint (usually leave default). Most tenants — EU and US included — share the default clp.my-clay.com host, so leave API Base URL and OAuth Token URL at their defaults. Override them only if Salto has placed your tenant on a different host, and then enter the exact base URL and token endpoint Salto gave you.
  5. Resolve the site. Run get_sites, copy the site UUID you want to manage, and paste it into the Site ID field. Single-site accounts are auto-detected — when only one site is visible the driver fills site_id itself on first connect, so you can leave it blank.
  6. Create one zone per lock. Run get_locks to enumerate doors. For each online lock, create a Zone whose Address is the Salto lock UUID exactly as returned. Zones are not auto-created — the driver only writes state onto zones you create and address yourself (see the subsystem note below).
  7. Verify. Run get_status with address=<lock-uuid> for one zone to confirm the token flow and per-lock connectivity end to end.
Subsystem placement

Salto lock zones are not auto-created and the driver does not pre-select a subsystem for you. Its subsystem hints (access_control / door / lock) don't match any of GEM's default-seeded subsystems, so the New Zone editor leaves the Subsystem field empty — pick one by hand. Doors is the natural home (it's seeded by default and groups door/lock zones); Security is a reasonable alternative if you keep all access hardware together. The choice drives grouping and iconography only — lock state is written directly by the driver, not derived from relay-to-state mapping.

Device attributes

Attribute (key)Field labelDefaultNotes
username (or client_id)Client IDOAuth2 client_id from the KS portal. Required.
password (or client_secret)Client SecretOAuth2 client_secret. Stored encrypted. Required.
site_idSite IDSalto site UUID. Required for multi-site accounts; auto-filled on first connect when only one site is visible.
api_baseAPI Base URLhttps://clp.my-clay.com/v1.1Resource API base. Override only for a non-default regional host.
auth_urlOAuth Token URLhttps://clp.my-clay.com/oauth2/tokenOAuth2 token endpoint. Override only for a non-default regional host.
status_intervalLock-roster Poll (ms)60000Lock-roster + battery sweep cadence. Minimum 15000. Mind tenant rate limits.
event_poll_intervalAudit Poll (ms)30000Audit-feed cadence. Set 0 to disable the audit loop entirely.
unlock_secondsDefault Unlock Duration (s)5Release duration when unlock is called without a seconds argument. Clamped 1–60.
released_state_msReleased State Hold (ms)5000How long zone.state stays released after an unlock before reverting to locked. Set 0 to leave it released (no auto-revert).

The driver caches the OAuth bearer token, refreshes it about a minute before expiry, and on a 401 force-refreshes and retries the request once — so a credential rotation in the portal is picked up without a device reload.

Zone attributes

AttributeField labelRequiredNotes
addressAddressyesThe Salto lock UUID, copied verbatim from get_locks. One zone per online lock; the driver matches a zone to its lock by this value alone.
salto_typeSalto Object TypenoDeclared (lock / door) for forward compatibility; the current driver ignores it and keys zones purely by address. Leave it unset.

As state arrives, the driver writes the following onto each lock zone:

  • online — boolean; whether the lock is currently reachable on the Salto cloud.
  • battery_level — battery percentage (0–100).
  • statelocked (default) or released (set the moment an unlock is accepted, reverting to locked after released_state_ms).

When the audit loop is enabled (event_poll_interval > 0) it additionally writes:

  • last_event — the most recent event type / action string for that lock.
  • last_event_at — ISO timestamp of that event.
  • last_event_user — user name or email, when the audit row carries one.

These six names are cataloged, so they autocomplete in the Attribute editor's name picker and can drive attribute triggers — for example, notify when a lock's battery_level drops below 20, when online flips to false, or when last_event records a denied/forced entry.

Commands

CommandArgumentsNotes
unlockaddress, optional seconds (1–60)Online release for unlock_seconds (or the seconds arg). Sets zone.state = released, reverting to locked after released_state_ms.
lockaddressProgrammatic lock. Not supported on every hardware revision — older XS4 strikes return 422.
get_sitesSites visible to this credential.
get_locksLock roster for the configured site.
get_usersUser roster for the configured site.
get_statusaddressPer-lock detail: battery, online, last event.
get_eventsoptional limit (default 50, max 200), since (ISO timestamp)Tail the audit feed directly.
refresh_tokenDiscard the cached bearer and re-authenticate.

unlock and lock carry the lock UUID as their address argument; when you fire them against a zone (from a macro, trigger, scene, or a UI control) the zone's address fills it automatically.

Known limitations

  • Offline-only locks cannot be unlocked over the API. They appear in get_locks with online=false; calling unlock returns a Salto-side error.
  • lock (programmatic lock) is hardware-dependent. Older XS4 strikes do not implement it and return 422.
  • No event push. The Connect API does not push; both lock state and last-event surfacing rely on polling. Tune status_interval and event_poll_interval to your tenant's rate limit.
  • Audit endpoint variation. Some legacy KS tenants expose the audit feed at /audit/log instead of /audit-trails; the driver falls back automatically on a 404, so both get_events and the audit loop keep working.
  • User management is read-only. Credential issuance, schedule writes, and access-rule changes are intentionally not exposed — they belong in the Salto KS portal, where the audit chain is preserved.

Troubleshooting

SymptomCheck
oauth token failed (status 401)client_id or client_secret is wrong, or the credential was disabled in the KS portal. Re-mint and update the Client ID / Client Secret fields.
oauth token failed (status 400)The Connect API add-on is probably not enabled on this tenant. Contact Salto support.
salto ks 403The credential is valid but lacks the scope for that endpoint. Re-mint with the scopes listed under Prerequisites.
salto ks 422 on unlockThe lock is offline or the hardware doesn't support the operation. Confirm with get_status.
multi-site account, wrong/empty dataMore than one site is visible, so nothing is auto-selected. Run get_sites and set Site ID explicitly.
no events appearingConfirm Audit Poll (ms) is greater than 0 and the credential has audit:read. If get_events returns rows but zone.last_event never updates, confirm the zone Address matches the lockId in the audit payload exactly.
  • Zones — create one zone per online lock (place them in the Doors or Security subsystem).
  • Subsystems — the subsystem these lock zones belong to.
  • Devices — add and configure the Salto KS cloud connection.
  • Commands — the command grid and Test runner for unlock, lock, and the get_* queries.