Ask or search…
K
Links

Get started with SmartThings Hubs + Smart Locks

Overview

Seam provides a universal API to connect and control many brands of smart locks. This guide provides a rapid introduction to connecting and controlling your SmartThings Hub and smart lock using the Seam API. SmartThings Hub is connected to your local network using either Wi-Fi or Ethernet. The smart lock is paired to SmartThings via Zigbee or Z-Wave. These locks can then be remotely locked, unlocked, and have access codes programmed to allow keyless entry.
To learn more about other smart lock brands supported by Seam such as August, Yale, and Salto, head over to our integration page.

1 — Install Seam SDK

Seam provides client libraries for many languages, such as JavaScript, Python, Ruby, PHP, and others, as well as a Postman collection and OpenAPI spec.
JavaScript
Python
Ruby
PHP
Java
C#
Go
npm i seam
pip install seamapi
# For some development environments, use pip3 in this command instead of pip.
bundle add seamapi
composer require seamapi/seam
Gradle:
// build.gradle
dependencies {
implementation 'io.github.seamapi:java:0.x.x'
}
Maven:
<!-- pom.xml -->
<dependency>
<groupId>io.github.seamapi</groupId>
<artifactId>java</artifactId>
<version>0.x.x</version>
</dependency>
Install using nuget.
go get github.com/seamapi/go
Once installed, sign-up for Seam to get your API key, and export it as an environment variable:
$ export SEAM_API_KEY=seam_test2ZTo_0mEYQW2TvNDCxG5Atpj85Ffw
This guide uses a sandbox workspace. You can only connect virtual devices in a sandbox workspace. If you need to connect a real device, use a non-sandbox workspace and API key.
To pair a SmartThings Hub and smart lock with our API, you must sign in to a SmartThings account. To do so, create a Seam Connect Webview.
Python
Javascript
Ruby
from seamapi import Seam
seam = Seam()
webview = seam.connect_webviews.create(accepted_providers=["smartthings"])
assert webview.login_successful is False
# Send the webview URL to your user
print(webview.url)
import { Seam } from "seam"
const seam = Seam()
const webview = await seam.connect_webviews.create({
accepted_providers: ["smartthings"]
})
console.log(webview)
/*
{
"connect_webview_id": "811b80e7-7c87-4ce1-a938-2f6936851aa9",
"url": "https://connect.getseam.com/v1/connect_webviews/view?connect_webview_id=811b80e7-7c87-4ce1-a938-2f6936851aa9&auth_token=GXtMoAaperbuNhSCByyQMroT9HMRquXK6",
"device_selection_mode": "none",
"accepted_providers": [
"smartthings"
],
"created_at": "2022-01-03T21:11:27.002Z",
"login_successful": false,
"status": "pending"
}
*/
require "seamapi"
seam = Seam::Client.new(api_key: "MY_API_KEY")
webview = seam.connect_webviews.create(
accepted_providers: ["smartthings"]
)
puts webview
# <Seam::ConnectWebview:0x006a950
# url="https://connect.getseam.com/connect_webviews/view?connect_webview_id=123e4567-e89b-12d3-a456-426614174000&auth_token=q123DASDASKd23DADdad29"
# status="pending"
# created_at="2022-07-06T23:20:09.785729+00:00"
# workspace_id="123e4567-e89b-12d3-a456-426614174000"
# accepted_devices=[]
# login_successful=false
# accepted_providers=["smartthings"]
# any_device_allowed=nil
# connect_webview_id="123e4567-e89b-12d3-a456-426614174000"
# custom_redirect_url=nil
# any_provider_allowed=false
# device_selection_mode="none">
Now, send the Connect Webview URL to the user. When the user signs in, you see a "completed" status on the Connect Webview or login_successful set to true.
Python
Javascript
Ruby
updated_webview = seam.connect_webviews.get(webview.connect_webview_id)
assert updated_webview.login_successful
const updated_webview = await seam.connect_webviews.get(
webview.connect_webview_id
)
console.log(updated_webview.login_successful)
// true
updated_webview = seam.connect_webviews.get(
webview.connect_webview_id
)
puts updated_webview.login_successful
# true
You can now find all the devices that are associated with the connected account. From the returned payload, see whether the door lock is locked or unlocked.
Python
Javascript
Ruby
from pprint import pprint
all_devices = seam.devices.list()
some_device = all_devices[0]
assert device.properties["online"] is True
assert device.properties["locked"] is True
pprint(device)
# Device(device_id='a8669e4c-76e3-4db6-a827-11a65eb360ba',
# device_type='smartthings_lock',
# location=None,
# properties={'smartthings_metadata': {...}},
# 'locked': True,
# 'online': True})
const all_locks = await seam.locks.list()
const some_lock = all_locks[0]
console.log(some_lock)
/*
{
device_id: 'a8669e4c-76e3-4db6-a827-11a65eb360ba',
device_type: 'smartthings_lock',
location: null,
properties: { smartthings_metadata: {...} },
locked: true,
online: true
}
*/
all_locks = seam.locks.list()
some_lock = all_locks.first
puts some_lock
# <Seam::Device:0x001e870
# device_id="123e4567-e89b-12d3-a456-426614174000"
# device_type="smartthings_lock"
# properties={
# "locked"=>true,
# "online"=>true,
# "battery_level"=>1,
# "smartthings_metadata"=>{
# "device_id"=>"123e4567-e89b-12d3-a456-426614174000",
# "device_name"=>"Yale Door Lock"},
# "name"=>"Yale Door Lock"}>

Locking a Door

post
https://connect.getseam.com
/locks/lock_door
Lock a door
Python
Javascript
Ruby
seam.locks.lock_door(some_device)
updated_device = seam.devices.get(some_device.device_id)
assert updated_device.properties["locked"] is True
await seam.locks.lock_door({ device: some_device })
const updated_device = await seam.devices.get(some_device)
console.log(updated_device.properties.locked)
// true
action_attempt = seam.locks.lock_door(some_lock.device_id)
action_attempt.wait_until_finished
updated_lock = seam.devices.get(some_lock.device_id)
puts updated_lock.properties["locked"]
# true

Unlocking a Door

post
https://connect.getseam.com
/locks/unlock_door
Unlock a door
Python
Javascript
Ruby
seam.locks.unlock_door(some_device)
updated_device = seam.devices.get(some_device.device_id)
assert updated_device.properties["locked"] is False
await seam.locks.unlock_door({ lock: some_lock })
const updated_lock = await seam.locks.get(some_lock.device_id)
console.log(updated_lock.properties.locked)
// false
action_attempt = seam.locks.unlock_door(some_lock.device_id)
action_attempt.wait_until_finished
updated_lock = seam.devices.get(some_lock.device_id)
puts updated_lock.properties["locked"]
# false

Create an Access Code

post
https://connect.getseam.com
/access_codes/create
Create an Access Code
For Scheduled Access Codes, both starts_at and ends_at are required. For Ongoing Access Codes, don't set starts_at or ends_at.
Python
Javascript
Ruby
access_code = seam.access_codes.create(
device=some_device,
name="new code",
code="876543",
starts_at="2022-01-13T21:17:56.138Z",
ends_at="2022-01-13T21:17:58.138Z"
)
pprint(access_code)
# AccessCode(
# access_code_id='a8669e4c-76e3-4db6-a827-11a65eb360ba',
# type='ongoing',
# name='new code',
# code='876543',
# starts_at='2022-01-13T21:17:56.138Z'
# ends_at='2022-01-13T21:17:58.138Z',
# location=None,
# )
const access_code = await seam.access_codes.create({
lock: some_lock,
code: "876543",
})
console.log(access_code)
/*
{
"access_code_id": "a8669e4c-76e3-4db6-a827-11a65eb360ba",
"code": "876543",
"type": "ongoing",
"starts_at": "2022-01-13T21:17:56.138Z",
"ends_at": null
}
*/
access_code = seam.access_codes.create(
device_id: some_lock.device_id,
name: "new code",
code: "876543",
starts_at: "2022-01-13T21:17:56.138Z",
ends_at: "2022-01-13T21:17:58.138Z"
)
puts access_code
# <Seam::AccessCode:0x002cf60
# code="876543"
# name="new code"
# type="time_bound"
# ends_at="2022-01-13T21:18:00.000Z"
# starts_at="2022-01-13T21:18:00.000Z"
# created_at="2022-07-06T22:57:56.650Z"
# access_code_id="a8669e4c-76e3-4db6-a827-11a65eb360ba">

Delete an Access Code

delete
https://connect.getseam.com
/access_codes/remove
Remove an Access Code
Python
Javascript
Ruby
attempt = seam.access_codes.delete(access_code=access_code)
pprint(attempt)
# ActionAttempt(
# action_attempt_id='af0155aa-51fe-4e63-9acb-2fbd33675cac',
# action_type='DELETE_ACCESS_CODE',
# status='success',
# result={},
# error=None
# )
await seam.access_codes.remove({
code: access_code
})
attempt = seam.access_codes.delete(access_code.access_code_id)
puts attempt
# <Seam::ActionAttempt:0x0000000107026c98
# status="success"
# action_type="DELETE_ACCESS_CODE",
# action_attempt_id="af0155aa-51fe-4e63-9acb-2fbd33675cac",
# result={}>

List Access Codes

get
https://connect.getseam.com
/access_codes
List Access Codes
Python
Javascript
Ruby
# you can use a device or a device_id as the "device" parameter
seam.access_codes.list(device=some_device)
# [
# AccessCode(
# access_code_id='af5272b1-2a49-4eb5-9388-2447fc7b5bd1',
# type='ongoing',
# code='123459',
# starts_at=None,
# ends_at=None,
# name='ongoing 1'
# ),
# AccessCode(
# access_code_id='57f8216a-ebc4-46e7-8f89-9c9448f70733',
# type='ongoing',
# code='189644',
# starts_at=None,
# ends_at=None,
# name='ongoing 2'
# )
# ]
// you can use a device or a device_id as the "device" parameter
const access_codes = await seam.access_codes.list({
device: {
"device_id": "af5272b1-2a49-4eb5-9388-2447fc7b5bd1"
}
})
console.log(access_codes)
/*
[
{
"access_code_id": "a8669e4c-76e3-4db6-a827-11a65eb360ba",
"code": "876543",
"type": "ongoing",
"starts_at": "2022-01-13T21:17:56.138Z",
"ends_at": null
}
]
*/
access_codes = seam.access_codes.list(some_lock.device_id)
puts access_codes
# [<Seam::AccessCode:0x002cf60
# code="876543"
# name="new code"
# type="time_bound"
# ends_at="2022-01-13T21:18:00.000Z"
# starts_at="2022-01-13T21:18:00.000Z"
# created_at="2022-07-06T22:57:56.650Z"
# access_code_id="09c1ba5a-623a-4de4-9826-91377e468c14">]