# Locking and Unlocking Smart Locks

## Overview

Seam enables you to lock or unlock your door lock remotely. This guide walks you through how to perform these actions using the Seam API.

When you send a command to a smart lock, it might take a while for Seam to confirm the action's success. To handle this, Seam provides [an "action attempt" object](https://docs.seam.co/latest/core-concepts/action-attempts), which indicates whether the action was successful.

To ensure that the action has been successfully executed, we advise checking the status of the action attempt object by polling the ["Get Action Attempt" request](https://docs.seam.co/latest/api/action_attempts/get). Once Seam has successfully confirmed the action, the action attempt's `status` will indicate `success`.

Some providers and device models cannot confirm whether the physical lock or unlock happened in a reasonable time or at all. In those cases, a successful action attempt can still include `action_attempt.result.was_confirmed_by_device = false`.

***

## Before You Begin: Confirm Capabilities

Before you attempt to lock or unlock a device, be sure to confirm that your device has the capability to perform these operations. You can inspect the capabilities of a device by checking the following [capability flags](https://docs.seam.co/latest/device-and-system-capabilities#capability-flags) for the device:

* `device.can_remotely_lock`
* `device.can_remotely_unlock`

Use [Get Device](https://docs.seam.co/latest/api/devices/get) for a specific device to return these capability flags. Then, use an `if` statement or similar check to confirm that the relevant flag is both present and `true` before attempting to lock or unlock the device.

If either of these capability flags is `false` or not present, you can view the [properties](https://docs.seam.co/latest/api/devices/#properties) of the device, [errors](https://docs.seam.co/latest/api/devices/#errors) or [warnings](https://docs.seam.co/latest/api/devices/#warnings) for the device, and [events](https://docs.seam.co/latest/api/events/) related to the device to learn more about the cause of these issues. For example, you could examine `device.properties.online`. In addition, you could look for a `device.disconnected` event.

{% tabs %}
{% tab title="JavaScript" %}
**Request:**

```javascript
await seam.devices.get("11111111-1111-1111-1111-444444444444")
```

**Response:**

```json
{
  device_id: '11111111-1111-1111-1111-444444444444',
  can_remotely_lock: true,   // You can use seam.locks.lockDoor() on this device.
  can_remotely_unlock: true, // You can use seam.locks.unlockDoor() on this device.
  ...
}
```

{% endtab %}

{% tab title="cURL" %}
**Request:**

```bash
# Use GET or POST.
curl -X 'GET' \
  'https://connect.getseam.com/devices/get' \
  -H 'accept: application/json' \
  -H "Authorization: Bearer ${SEAM_API_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
  "device_id": "11111111-1111-1111-1111-444444444444"
}'
```

**Response:**

```json
{
  "device": {
    "device_id": "11111111-1111-1111-1111-444444444444",
    "can_remotely_lock": true,   // You can use /locks/lock_door on this device.
    "can_remotely_unlock": true, // You can use /locks/unlock_door on this device.
    ...
  },
  "ok": true
}
```

{% endtab %}

{% tab title="Python" %}
**Request:**

```python
seam.devices.get(device_id="11111111-1111-1111-1111-444444444444")
```

**Response:**

```
Device(
  device_id='11111111-1111-1111-1111-444444444444',
  can_remotely_lock=True,   // You can use seam.locks.lock_door() on this device.
  can_remotely_unlock=True, // You can use seam.locks.unlock_door() on this device.
  ...
)
```

{% endtab %}

{% tab title="Ruby" %}
**Request:**

```ruby
client.devices.get(device_id: "11111111-1111-1111-1111-444444444444")
```

**Response:**

```
<
  Seam::Device:0x00438
    device_id="11111111-1111-1111-1111-444444444444"
    can_remotely_lock=true   // You can use client.locks.lock_door() on this device.
    can_remotely_unlock=true // You can use client.locks.unlock_door() on this device.
    ...
>
```

{% endtab %}

{% tab title="PHP" %}
**Request:**

```php
$seam->devices->get("11111111-1111-1111-1111-444444444444");
```

**Response:**

```json
{
  "device_id": "11111111-1111-1111-1111-444444444444",
  "can_remotely_lock": true,   // You can use $seam->locks->lock_door() on this device.
  "can_remotely_unlock": true, // You can use $seam->locks->unlock_door() on this device.
  ...
}
```

{% endtab %}

{% tab title="C#" %}
**Request:**

```csharp
seam.Devices.Get(deviceId: "11111111-1111-1111-1111-444444444444");
```

**Response:**

```
{
  "device_id": "11111111-1111-1111-1111-444444444444",
  "can_remotely_lock": true,   // You can use seam.Locks.LockDoor() on this device.
  "can_remotely_unlock": true, // You can use seam.Locks.UnlockDoor() on this device.
  ...
}
```

{% endtab %}
{% endtabs %}

***

## Locking a Door

You can lock a door using the [`lock_door`](https://docs.seam.co/latest/api/locks/lock_door) endpoint. To confirm the success of the action, see [Verifying the success of a lock or unlock action](#verifying-the-success-of-a-lock-or-unlock-action).

{% tabs %}
{% tab title="JavaScript" %}
**Request:**

```javascript
// Get the device.
const device = await seam.devices.get({
  device_id: "11111111-1111-1111-1111-444444444444"
});

// Confirm that the device can remotely lock.
if (device.can_remotely_lock) {
  // Perform the lock operation.
  await seam.locks.lockDoor({
    device_id: device.device_id
  })
};
```

**Response:**

```json
{
  actionAttempt: {
    status: 'success',
    action_attempt_id: '11111111-2222-3333-4444-555555555555',
    action_type: 'LOCK_DOOR',
    result: {},
    error: null
  }
}
```

{% endtab %}

{% tab title="cURL" %}
**Request:**

```bash
# Get the device.
device=$(
  # Use GET or POST.
  curl -X 'GET' \
    'https://connect.getseam.com/devices/get' \
    -H 'accept: application/json' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d '{
      "device_id": "11111111-1111-1111-1111-444444444444"
  }')

# Confirm that the device can remotely lock.
if  $(jq -r '.device.can_remotely_lock' <<< ${device}); then \
  # Perform the lock operation.
  curl -X 'POST' \
    'https://connect.getseam.com/locks/lock_door' \
    -H 'accept: application/json' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d "{
      \"device_id\": \"$(jq -r '.device.device_id' <<< ${device})\"
  }";
fi
```

**Response:**

```json
{
  "action_attempt": {
    "status":"pending",
    "action_type":"LOCK_DOOR",
    "action_attempt_id":"11111111-2222-3333-4444-555555555555",
    "result":null,
    "error":null
  },
  "ok":true
}
```

{% endtab %}

{% tab title="Python" %}
**Request:**

```python
# Get the device.
device = seam.devices.get(
  device_id="11111111-1111-1111-1111-444444444444"
)

# Confirm that the device can remotely lock.
if device.can_remotely_lock:
  # Perform the lock operation.
  seam.locks.lock_door(device_id=device.device_id)
```

**Response:**

```
ActionAttempt(status='pending',
              action_type='LOCK_DOOR',
              action_attempt_id='11111111-2222-3333-4444-555555555555',
              result=None,
              error={})
```

{% endtab %}

{% tab title="Ruby" %}
**Request:**

```ruby
# Get the device.
device = client.devices.get(device_id: "11111111-1111-1111-1111-444444444444")

# Confirm that the device can remotely lock.
if (device.can_remotely_lock)
  # Perform the lock operation.
  client.locks.lock_door(device_id: device.device_id)
end
```

**Response:**

```
<Seam::ActionAttempt:0x00438
  status="pending"
  action_type="LOCK_DOOR"
  action_attempt_id="11111111-2222-3333-4444-555555555555"
  result=nil>
```

{% endtab %}

{% tab title="PHP" %}
**Request:**

```php
// Get the device.
$device = $seam->devices->get(device_id: "11111111-1111-1111-1111-444444444444");

// Confirm that the device can remotely lock.
if ($device->can_remotely_lock) {
  // Perform the lock operation.
  $seam->locks->lock_door(device_id: $device->device_id);
}
```

**Response:**

```json
{
  "action_attempt_id":"11111111-2222-3333-4444-555555555555",
  "action_type":"LOCK_DOOR",
  "error":null,
  "result":{},
  "status":"success"
}
```

{% endtab %}

{% tab title="C#" %}
**Request:**

```csharp
// Get the device.
Device device = seam.Devices.Get(deviceId: "11111111-1111-1111-1111-444444444444");

// Confirm that the device can remotely lock.
if (device.CanRemotelyLock == true) {
  // Perform the lock operation.
  seam.Locks.LockDoor(deviceId: device.DeviceId);
}
```

**Response:**

```json
{
  "status": "pending",
  "action_type": "LOCK_DOOR",
  "action_attempt_id": "11111111-2222-3333-4444-555555555555"
}
```

{% endtab %}
{% endtabs %}

***

## Unlocking a Door

You can unlock a door using the [unlock\_door](https://docs.seam.co/latest/api/locks/unlock_door) endpoint. To confirm the success of the action, see [Verifying the success of a lock or unlock action](#verifying-the-success-of-a-lock-or-unlock-action).

{% tabs %}
{% tab title="JavaScript" %}
**Request:**

```javascript
// Get the device.
const device = await seam.devices.get({
  device_id: "11111111-1111-1111-1111-444444444444"
});

// Confirm that the device can remotely unlock.
if (device.can_remotely_unlock) {
  // Perform the unlock operation.
  await seam.locks.unlockDoor({
    device_id: device.device_id
  })
};
```

**Response:**

```json
{
  actionAttempt: {
    status: 'success',
    action_attempt_id: '11111111-2222-3333-4444-555555555555',
    action_type: 'UNLOCK_DOOR',
    result: {
      was_confirmed_by_device: false
    },
    error: null
  }
}
```

{% endtab %}

{% tab title="cURL" %}
**Request:**

```bash
# Get the device.
device=$(
  # Use GET or POST.
  curl -X 'GET' \
    'https://connect.getseam.com/devices/get' \
    -H 'accept: application/json' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d '{
      "device_id": "11111111-1111-1111-1111-444444444444"
  }')

# Confirm that the device can remotely unlock.
if  $(jq -r '.device.can_remotely_unlock' <<< ${device}); then \
  # Perform the unlock operation.
  curl -X 'POST' \
    'https://connect.getseam.com/locks/unlock_door' \
    -H 'accept: application/json' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d "{
      \"device_id\": \"$(jq -r '.device.device_id' <<< ${device})\"
  }";
fi
```

**Response:**

```json
{
  "action_attempt": {
    "status":"pending",
    "action_type":"UNLOCK_DOOR",
    "action_attempt_id":"11111111-2222-3333-4444-555555555555",
    "result":null,
    "error":null
  },
  "ok":true
}
```

{% endtab %}

{% tab title="Python" %}
**Request:**

```python
# Get the device.
device = seam.devices.get(
  device_id="11111111-1111-1111-1111-444444444444"
)

# Confirm that the device can remotely unlock.
if device.can_remotely_unlock:
  # Perform the unlock operation.
  seam.locks.unlock_door(device_id=device.device_id)
```

**Response:**

```
ActionAttempt(status='pending',
              action_type='UNLOCK_DOOR',
              action_attempt_id='11111111-2222-3333-4444-555555555555',
              result=None,
              error={})
```

{% endtab %}

{% tab title="Ruby" %}
**Request:**

```ruby
# Get the device.
device = client.devices.get(device_id: "11111111-1111-1111-1111-444444444444")

# Confirm that the device can remotely unlock.
if (device.can_remotely_unlock)
  # Perform the unlock operation.
  client.locks.unlock_door(device_id: device.device_id)
end
```

**Response:**

```
<Seam::ActionAttempt:0x00438
  status="pending"
  action_type="UNLOCK_DOOR"
  action_attempt_id="11111111-2222-3333-4444-555555555555"
  result=nil>
```

{% endtab %}

{% tab title="PHP" %}
**Request:**

```php
// Get the device.
$device = $seam->devices->get(device_id: "11111111-1111-1111-1111-444444444444");

// Confirm that the device can remotely unlock.
if ($device->can_remotely_unlock) {
  // Perform the unlock operation.
  $seam->locks->unlock_door(device_id: $device->device_id);
}
```

**Response:**

```json
{
  "action_attempt_id":"11111111-2222-3333-4444-555555555555",
  "action_type":"UNLOCK_DOOR",
  "error":null,
  "result":{
    "was_confirmed_by_device":false
  },
  "status":"success"
}
```

{% endtab %}

{% tab title="C#" %}
**Request:**

```csharp
// Get the device.
Device device = seam.Devices.Get(deviceId: "11111111-1111-1111-1111-444444444444");

// Confirm that the device can remotely unlock.
if (device.CanRemotelyUnlock == true) {
  // Perform the unlock operation.
  seam.Locks.UnlockDoor(deviceId: device.DeviceId);
}
```

**Response:**

```json
{
  "status": "pending",
  "action_type": "UNLOCK_DOOR",
  "action_attempt_id": "11111111-2222-3333-4444-555555555555"
}
```

{% endtab %}
{% endtabs %}

***

## Verifying the Success of a Lock or Unlock Action

### 1. Execute a Lock request (or other action)

When initiating a lock or unlock action, the Seam API returns an action attempt, which monitors the success or failure of the action.

{% tabs %}
{% tab title="JavaScript" %}
**Request:**

```javascript
await seam.locks.lockDoor({
  device_id: "11111111-1111-1111-1111-444444444444"
});
```

**Response:**

```json
{
  actionAttempt: {
    status: 'success',
    action_attempt_id: '11111111-2222-3333-4444-555555555555',
    action_type: 'LOCK_DOOR',
    result: {},
    error: null
  }
}
```

{% endtab %}

{% tab title="cURL" %}
**Request:**

```bash
curl -X 'POST' \
  'https://connect.getseam.com/locks/lock_door' \
  -H 'accept: application/json' \
  -H "Authorization: Bearer ${SEAM_API_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
    "device_id": "11111111-1111-1111-1111-444444444444"
}'
```

**Response:**

```json
{
  "action_attempt": {
    "status":"pending",
    "action_type":"LOCK_DOOR",
    "action_attempt_id":"11111111-2222-3333-4444-555555555555",
    "result":null,
    "error":null
  },
  "ok":true
}
```

{% endtab %}

{% tab title="Python" %}
**Request:**

```python
seam.locks.lock_door(device_id="11111111-1111-1111-1111-444444444444")
```

**Response:**

```
ActionAttempt(status='pending',
              action_type='LOCK_DOOR',
              action_attempt_id='11111111-2222-3333-4444-555555555555',
              result=None,
              error={})
```

{% endtab %}

{% tab title="Ruby" %}
**Request:**

```ruby
client.locks.lock_door(device_id: "11111111-1111-1111-1111-444444444444")
```

**Response:**

```
<Seam::ActionAttempt:0x00438
  status="pending"
  action_type="LOCK_DOOR"
  action_attempt_id="11111111-2222-3333-4444-555555555555"
  result=nil>
```

{% endtab %}

{% tab title="PHP" %}
**Request:**

```php
$seam->locks->lock_door(device_id: "11111111-1111-1111-1111-444444444444");
```

**Response:**

```json
{
  "action_attempt_id":"11111111-2222-3333-4444-555555555555",
  "action_type":"LOCK_DOOR",
  "error":null,
  "result":{},
  "status":"success"
}
```

{% endtab %}

{% tab title="C#" %}
**Request:**

```csharp
seam.Locks.LockDoor(deviceId: "11111111-1111-1111-1111-444444444444");
```

**Response:**

```json
{
  "status": "pending",
  "action_type": "LOCK_DOOR",
  "action_attempt_id": "11111111-2222-3333-4444-555555555555"
}
```

{% endtab %}
{% endtabs %}

### 2. Poll the Action Attempt to Verify the Success of the Action

Use the `action_attempt_id` from the prior response to make a [Get Action Attempt request](https://docs.seam.co/latest/api/action_attempts/get). When the action attempt's `status` changes to `success`, it indicates the action has been successful.

{% hint style="info" %}
Some providers and device models do not confirm whether a lock or unlock completed on the physical device. In those cases, the action attempt can still succeed while `action_attempt.result.was_confirmed_by_device` is `false`. Use this property to set the right expectation in your UI, especially for unlock flows.
{% endhint %}

{% tabs %}
{% tab title="JavaScript" %}
**Request:**

```javascript
await seam.actionAttempts.get({action_attempt_id: "11111111-2222-3333-4444-555555555555"});
```

**Response:**

```json
{
  status: 'success',
  action_attempt_id: '11111111-2222-3333-4444-555555555555',
  action_type: 'LOCK_DOOR',
  result: {
    was_confirmed_by_device: true
  },
  error: null
}
```

{% endtab %}

{% tab title="cURL" %}
**Request:**

```bash
# Use GET or POST.
curl -X 'GET' \
  'https://connect.getseam.com/action_attempts/get' \
  -H 'accept: application/json' \
  -H "Authorization: Bearer ${SEAM_API_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
  "action_attempt_id": "11111111-2222-3333-4444-555555555555"
}'
```

**Response:**

```json
{
  "action_attempt": {
    "status": "success",
    "action_attempt_id": "11111111-2222-3333-4444-555555555555",
    "action_type": "LOCK_DOOR",
    "result": {
      "was_confirmed_by_device": true
    },
    "error": null
  },
  "ok": true
}
```

{% endtab %}

{% tab title="Python" %}
**Request:**

```python
seam.action_attempts.get(action_attempt_id="11111111-2222-3333-4444-555555555555")
```

**Response:**

```
ActionAttempt(action_attempt_id='11111111-2222-3333-4444-555555555555',
              action_type='LOCK_DOOR',
              status='success',
              result={'was_confirmed_by_device': True},
              error=None)
```

{% endtab %}

{% tab title="Ruby" %}
**Request:**

```ruby
client.action_attempts.get(action_attempt_id: "11111111-2222-3333-4444-555555555555")
```

**Response:**

```
<Seam::ActionAttempt:0x00438
  status="success"
  action_attempt_id="11111111-2222-3333-4444-555555555555"
  action_type="LOCK_DOOR"
  result={"was_confirmed_by_device"=>true}>
```

{% endtab %}

{% tab title="PHP" %}
**Request:**

```php
$seam->action_attempts->get(action_attempt_id: "11111111-2222-3333-4444-555555555555");
```

**Response:**

```json
{
  "action_attempt_id":"11111111-2222-3333-4444-555555555555",
  "action_type":"LOCK_DOOR",
  "error":null,
  "result":{
    "was_confirmed_by_device":true
  },
  "status":"success"
}
```

{% endtab %}

{% tab title="C#" %}
**Request:**

```csharp
seam.ActionAttempts.Get("11111111-2222-3333-4444-555555555555");
```

**Response:**

```
{
  "status": "success",
  "action_type": "LOCK_DOOR",
  "action_attempt_id": "11111111-2222-3333-4444-555555555555",
  "result": {
    "was_confirmed_by_device": true
  },
  "error": null
}
```

{% endtab %}
{% endtabs %}

***

## Checking the Locked Status of a Lock

To retrieve the locked status of a specific door lock, use the [Get Device](https://docs.seam.co/latest/api/devices/get) endpoint by providing the `device_id` of the desired lock. This operation returns detailed information, including the current locked status. Note that if the lock is offline, Seam does not return the `device.locked` property.

{% tabs %}
{% tab title="JavaScript" %}
**Request:**

```javascript
await seam.devices.get("11111111-1111-1111-1111-444444444444")
```

**Response:**

```json
{
  device_id: '11111111-1111-1111-1111-444444444444',
  properties: {
    locked: true,
    ...
  },
  ...
}
```

{% endtab %}

{% tab title="cURL" %}
**Request:**

```bash
# Use GET or POST.
curl -X 'GET' \
  'https://connect.getseam.com/devices/get' \
  -H 'accept: application/json' \
  -H "Authorization: Bearer ${SEAM_API_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
  "device_id": "11111111-1111-1111-1111-444444444444"
}'
```

**Response:**

```json
{
  "lock": {
    "device_id": "11111111-1111-1111-1111-444444444444",
    "properties": {
      "locked": true,
      ...
    },
    ...
  },
  "ok": true
}
```

{% endtab %}

{% tab title="Python" %}
**Request:**

```python
seam.devices.get(device_id="11111111-1111-1111-1111-444444444444")
```

**Response:**

```
Device(
  device_id='11111111-1111-1111-1111-444444444444',
  properties={
    'locked': True,
    ...
  },
  ...
)
```

{% endtab %}

{% tab title="Ruby" %}
**Request:**

```ruby
client.devices.get(device_id: "11111111-1111-1111-1111-444444444444")
```

**Response:**

```
<Seam::Device:0x00438
  device_id="11111111-1111-1111-1111-444444444444"
  properties={
    "locked"=>true,
    ...
  }
  ...
>
```

{% endtab %}

{% tab title="PHP" %}
**Request:**

```php
$seam->devices->get("11111111-1111-1111-1111-444444444444");
```

**Response:**

```json
{
  "device_id": "11111111-1111-1111-1111-444444444444",
  "properties": {
    "locked": true,
    ...
  },
  ...
}
```

{% endtab %}

{% tab title="C#" %}
**Request:**

```csharp
seam.Devices.Get("11111111-1111-1111-1111-444444444444");
```

**Response:**

```json
{
  "device_id": "11111111-1111-1111-1111-444444444444",
  "properties": {
    "locked": true,
    ...
  },
  ...
}
```

{% endtab %}
{% endtabs %}

***

## Lock and Unlock Events

Whenever a lock is locked or unlocked, Seam emits a `lock.locked` or `lock.unlocked` event. You can see these events by making a [List Events request](https://docs.seam.co/latest/api/events/list) or by setting up a webhook. For more information on how to set up webhooks, see the [Webhooks guide](https://docs.seam.co/latest/developer-tools/webhooks).

A lock or unlock event looks like the following:

```json
{
  "event": {
    "event_id": "22222222-3333-4444-5555-666666666666",
    "device_id": "11111111-1111-1111-1111-444444444444",
    "event_type": "lock.locked",
    "workspace_id": "00000000-0000-0000-0000-000000000000",
    "created_at": "2023-10-13T15:10:18.443Z",
    "occurred_at": "2023-10-13T15:09:08.531Z",
    "method": "unknown",
    "connected_account_id": "11111111-1111-1111-1111-222222222222"
  },
  "ok": true
}
```

For more information about the `lock.locked` and `lock.unlocked` attributes, please see[ Events](https://docs.seam.co/latest/api/events/).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.seam.co/latest/capability-guides/smart-locks/lock-and-unlock.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
