Skip to main content

Salto KS

Cloud control for Salto KS — Salto's cloud-managed commercial access control platform — via the public Connect API. The driver does online unlock/lock, lock-roster reads, user enumeration, and audit-feed polling. Offline-only locks programmed via the Salto Space client are out of scope.

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. The driver assumes at minimum these scopes:
    • 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 returned by get_locks but unlock will fail with a Salto-side error.

Setup

  1. In the Salto KS portal → Account → API Credentials, create a new credential pair. Copy both client_id and client_secret.
  2. Create a device row with driver salto_ks.
  3. Paste client_id into the username field and client_secret into the password field. (The dedicated client_id / client_secret attribute names are also accepted if you prefer.)
  4. Optional: if your tenant is on a regional endpoint other than clp.my-clay.com, set api_base (e.g. https://api.regional.saltoks.com/v1.1) and auth_url.
  5. Run get_sites. Copy the site UUID and paste into the device's site_id attribute. Single-site accounts are auto-detected — the driver fills site_id on first connect.
  6. Run get_locks to enumerate doors. Create one zone per lock; zone.address = Salto lock UUID exactly as returned.
  7. Run get_status address=<lock-uuid> for one zone to verify end-to-end connectivity.

Attribute reference

AttributeRequiredDefaultNotes
username (or client_id)yesOAuth2 client_id.
password (or client_secret)yesOAuth2 client_secret. Stored encrypted.
site_idsometimesRequired for multi-site accounts; auto-detected when only one site is visible.
api_basenohttps://clp.my-clay.com/v1.1Resource API base.
auth_urlnohttps://clp.my-clay.com/oauth2/tokenOAuth2 token endpoint.
status_intervalno60000 msLock-roster sweep cadence. Mind tenant rate limits.
event_poll_intervalno30000 msAudit-feed cadence. Set 0 to disable the audit loop entirely.
unlock_secondsno5Default release duration when unlock is called without seconds. Clamped 1–60.
released_state_msno5000 msHow long zone.state stays released after an unlock before reverting to locked.

Per-zone override:

AttributeNotes
salto_typeOverride for ambiguous addresses. lock (default) or door.

Zone address

Zone address is the Salto lock UUID — copy it verbatim from get_locks. One zone per online lock.

Commands

CommandArgumentsNotes
unlockaddress, optional seconds (1–60)Online release for unlock_seconds (or seconds arg). Sets zone.state = released, reverts 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_eventslimit (≤200), since (ISO ts)Tail the audit feed.
refresh_tokenDiscard cached bearer and re-authenticate.

State surfaced per zone

The status loop sets these attributes on each zone whose address matches a Salto lock id:

  • online (bool)
  • battery_level (int 0-100)
  • statelocked (default) or released (during/after unlock)

The audit loop additionally sets:

  • last_event — event type/action string
  • last_event_at — ISO timestamp
  • last_event_user — user name or email if present in the audit row

Known limitations

  • Offline-only locks cannot be unlocked over the API. They appear in get_locks with online=false. unlock will return 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; state and last-event surfacing both poll. 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 404.
  • SIP video stations are out of scope. Use a dedicated intercom driver (aiphone_ix, butterflymx, comelit_vip, gds3710, doorbird) for door-station video.
  • User management is read-only in this driver. 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

  • 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 device row.
  • oauth token failed (status 400) — The Connect API add-on is probably not enabled on this tenant. Contact Salto support.
  • salto ks 403 — The credential is valid but lacks the scope for that endpoint. Re-mint with the scopes listed under Prerequisites.
  • salto ks 422 on unlock — Lock is offline or hardware does not support the operation. Confirm with get_status.
  • No events appearing — Verify event_poll_interval > 0 and that the credential has audit:read. If the audit feed returns rows from get_events but zone.last_event is not updating, confirm zone.address matches the lockId field in the audit payload exactly.