> ## Documentation Index
> Fetch the complete documentation index at: https://docs.seam.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Locking and Unlocking Smart Locks

> Learn how to lock and unlock a smart lock, and confirm the action's success.

## 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](../../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](/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](../../capability-guides/device-and-system-capabilities#capability-flags) for the device:

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

Use [Get Device](/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](/core-concepts/devices) of the device, [errors](/core-concepts/devices) or [warnings](/core-concepts/devices) for the device, and [events](/api/events/object) 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.

**Request:**

<CodeGroup>
  ```javascript JavaScript theme={null}
  await seam.devices.get('11111111-1111-1111-1111-444444444444')
  ```

  ```bash cURL theme={null}
  # 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"
  }'
  ```

  ```python Python theme={null}
  seam.devices.get(device_id="11111111-1111-1111-1111-444444444444")
  ```

  ```ruby Ruby theme={null}
  client.devices.get(device_id: "11111111-1111-1111-1111-444444444444")
  ```

  ```php PHP theme={null}
  $seam->devices->get("11111111-1111-1111-1111-444444444444");
  ```

  ```csharp C# theme={null}
  seam.Devices.Get(deviceId: "11111111-1111-1111-1111-444444444444");
  ```
</CodeGroup>

**Response:**

<CodeGroup>
  ```json JavaScript theme={null}
  {
    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.
    ...
  }
  ```

  ```json cURL theme={null}
  {
    "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
  }
  ```

  ```json Python theme={null}
  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.
    ...
  )
  ```

  ```json Ruby theme={null}
  <
    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.
      ...
  >
  ```

  ```json PHP theme={null}
  {
    "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.
    ...
  }
  ```

  ```json C# theme={null}
  {
    "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.
    ...
  }
  ```
</CodeGroup>

***

## Locking a Door

You can lock a door using the [`lock_door`](/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).

**Request:**

<CodeGroup>
  ```javascript JavaScript theme={null}
  // 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,
    })
  }
  ```

  ```bash cURL theme={null}
  # 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
  ```

  ```python Python theme={null}
  # 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)
  ```

  ```ruby Ruby theme={null}
  # 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
  ```

  ```php PHP theme={null}
  // 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);
  }
  ```

  ```csharp C# theme={null}
  // 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);
  }
  ```
</CodeGroup>

**Response:**

<CodeGroup>
  ```json JavaScript theme={null}
  {
    "actionAttempt": {
      "status": "success",
      "action_attempt_id": "11111111-2222-3333-4444-555555555555",
      "action_type": "LOCK_DOOR",
      "result": {},
      "error": null
    }
  }
  ```

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

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

  ```json Ruby theme={null}
  <Seam::ActionAttempt:0x00438
    status="pending"
    action_type="LOCK_DOOR"
    action_attempt_id="11111111-2222-3333-4444-555555555555"
    result=nil>
  ```

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

  ```json C# theme={null}
  {
    "status": "pending",
    "action_type": "LOCK_DOOR",
    "action_attempt_id": "11111111-2222-3333-4444-555555555555"
  }
  ```
</CodeGroup>

***

## Unlocking a Door

You can unlock a door using the [unlock\_door](/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).

**Request:**

<CodeGroup>
  ```javascript JavaScript theme={null}
  // 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,
    })
  }
  ```

  ```bash cURL theme={null}
  # 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
  ```

  ```python Python theme={null}
  # 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)
  ```

  ```ruby Ruby theme={null}
  # 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
  ```

  ```php PHP theme={null}
  // 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);
  }
  ```

  ```csharp C# theme={null}
  // 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);
  }
  ```
</CodeGroup>

**Response:**

<CodeGroup>
  ```json JavaScript theme={null}
  {
    "actionAttempt": {
      "status": "success",
      "action_attempt_id": "11111111-2222-3333-4444-555555555555",
      "action_type": "UNLOCK_DOOR",
      "result": {
        "was_confirmed_by_device": false
      },
      "error": null
    }
  }
  ```

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

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

  ```json Ruby theme={null}
  <Seam::ActionAttempt:0x00438
    status="pending"
    action_type="UNLOCK_DOOR"
    action_attempt_id="11111111-2222-3333-4444-555555555555"
    result=nil>
  ```

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

  ```json C# theme={null}
  {
    "status": "pending",
    "action_type": "UNLOCK_DOOR",
    "action_attempt_id": "11111111-2222-3333-4444-555555555555"
  }
  ```
</CodeGroup>

***

## 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.

**Request:**

<CodeGroup>
  ```javascript JavaScript theme={null}
  await seam.locks.lockDoor({
    device_id: '11111111-1111-1111-1111-444444444444',
  })
  ```

  ```bash cURL theme={null}
  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"
  }'
  ```

  ```python Python theme={null}
  seam.locks.lock_door(device_id="11111111-1111-1111-1111-444444444444")
  ```

  ```ruby Ruby theme={null}
  client.locks.lock_door(device_id: "11111111-1111-1111-1111-444444444444")
  ```

  ```php PHP theme={null}
  $seam->locks->lock_door(device_id: "11111111-1111-1111-1111-444444444444");
  ```

  ```csharp C# theme={null}
  seam.Locks.LockDoor(deviceId: "11111111-1111-1111-1111-444444444444");
  ```
</CodeGroup>

**Response:**

<CodeGroup>
  ```json JavaScript theme={null}
  {
    "actionAttempt": {
      "status": "success",
      "action_attempt_id": "11111111-2222-3333-4444-555555555555",
      "action_type": "LOCK_DOOR",
      "result": {},
      "error": null
    }
  }
  ```

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

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

  ```json Ruby theme={null}
  <Seam::ActionAttempt:0x00438
    status="pending"
    action_type="LOCK_DOOR"
    action_attempt_id="11111111-2222-3333-4444-555555555555"
    result=nil>
  ```

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

  ```json C# theme={null}
  {
    "status": "pending",
    "action_type": "LOCK_DOOR",
    "action_attempt_id": "11111111-2222-3333-4444-555555555555"
  }
  ```
</CodeGroup>

### 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](/api/action_attempts/get). When the action attempt's `status` changes to `success`, it indicates the action has been successful.

<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.
</Info>

**Request:**

<CodeGroup>
  ```javascript JavaScript theme={null}
  await seam.actionAttempts.get({
    action_attempt_id: '11111111-2222-3333-4444-555555555555',
  })
  ```

  ```bash cURL theme={null}
  # 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"
  }'
  ```

  ```python Python theme={null}
  seam.action_attempts.get(action_attempt_id="11111111-2222-3333-4444-555555555555")
  ```

  ```ruby Ruby theme={null}
  client.action_attempts.get(action_attempt_id: "11111111-2222-3333-4444-555555555555")
  ```

  ```php PHP theme={null}
  $seam->action_attempts->get(action_attempt_id: "11111111-2222-3333-4444-555555555555");
  ```

  ```csharp C# theme={null}
  seam.ActionAttempts.Get("11111111-2222-3333-4444-555555555555");
  ```
</CodeGroup>

**Response:**

<CodeGroup>
  ```json JavaScript theme={null}
  {
    "status": "success",
    "action_attempt_id": "11111111-2222-3333-4444-555555555555",
    "action_type": "LOCK_DOOR",
    "result": {
      "was_confirmed_by_device": true
    },
    "error": null
  }
  ```

  ```json cURL theme={null}
  {
    "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
  }
  ```

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

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

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

  ```json C# theme={null}
  {
    "status": "success",
    "action_type": "LOCK_DOOR",
    "action_attempt_id": "11111111-2222-3333-4444-555555555555",
    "result": {
      "was_confirmed_by_device": true
    },
    "error": null
  }
  ```
</CodeGroup>

***

## Checking the Locked Status of a Lock

To retrieve the locked status of a specific door lock, use the [Get Device](/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.

**Request:**

<CodeGroup>
  ```javascript JavaScript theme={null}
  await seam.devices.get('11111111-1111-1111-1111-444444444444')
  ```

  ```bash cURL theme={null}
  # 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"
  }'
  ```

  ```python Python theme={null}
  seam.devices.get(device_id="11111111-1111-1111-1111-444444444444")
  ```

  ```ruby Ruby theme={null}
  client.devices.get(device_id: "11111111-1111-1111-1111-444444444444")
  ```

  ```php PHP theme={null}
  $seam->devices->get("11111111-1111-1111-1111-444444444444");
  ```

  ```csharp C# theme={null}
  seam.Devices.Get("11111111-1111-1111-1111-444444444444");
  ```
</CodeGroup>

**Response:**

<CodeGroup>
  ```json JavaScript theme={null}
  {
    device_id: '11111111-1111-1111-1111-444444444444',
    properties: {
      locked: true,
      ...
    },
    ...
  }
  ```

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

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

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

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

  ```json C# theme={null}
  {
    "device_id": "11111111-1111-1111-1111-444444444444",
    "properties": {
      "locked": true,
      ...
    },
    ...
  }
  ```
</CodeGroup>

***

## 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](/api/events/list) or by setting up a webhook. For more information on how to set up webhooks, see the [Webhooks guide](../../developer-tools/webhooks).

A lock or unlock event looks like the following:

```json theme={null}
{
  "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](/api/events/object).
