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

# Get Started with Aqara Locks

> Learn how to connect and control your Aqara lock with the Seam API.

## 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 [Aqara](https://www.seam.co/manufacturers/aqara) lock using the Seam API. To learn more about other smart lock brands supported by Seam, head over to our [integration page](https://www.seam.co/supported-devices-and-systems).

## 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](https://connect.getseam.com/openapi.json) spec.

* JavaScript / TypeScript ([npm](https://www.npmjs.com/package/seam), [GitHub](https://github.com/seamapi/javascript))
* Python ([pip](https://pypi.org/project/seam/), [GitHub](https://github.com/seamapi/python))
* Ruby Gem ([rubygem](https://rubygems.org/gems/seam), [GitHub](https://github.com/seamapi/ruby))
* PHP ([packagist](https://packagist.org/packages/seamapi/seam), [GitHub](https://github.com/seamapi/php))
* C# ([nuget](https://www.nuget.org/packages/Seam), [GitHub](https://github.com/seamapi/csharp))
* Java ([GitHub](https://github.com/seamapi/java))

<Tabs>
  <Tab title="JavaScript">
    ```bash theme={"dark"}
    npm i seam
    ```
  </Tab>

  <Tab title="Python">
    ```bash theme={"dark"}
    pip install seam
    # For some development environments, use pip3 in this command instead of pip.
    ```
  </Tab>

  <Tab title="Ruby">
    ```bash theme={"dark"}
    bundle add seam
    ```
  </Tab>

  <Tab title="PHP">
    ```bash theme={"dark"}
    composer require seamapi/seam
    ```
  </Tab>

  <Tab title="C#">
    Install using [nuget](https://www.nuget.org/packages/Seam).
  </Tab>

  <Tab title="Java">
    Install using [GitHub](https://github.com/seamapi/java).
  </Tab>
</Tabs>

Once installed, [sign up for Seam](https://console.seam.co/) to get your API key, and export it as an environment variable:

```
$ export SEAM_API_KEY=seam_test2ZTo_0mEYQW2TvNDCxG5Atpj85Ffw
```

<Info>
  This guide uses a Sandbox Workspace. Only virtual devices can be connected. If
  you need to connect a real Aqara lock, use a non-sandbox workspace and
  API key.
</Info>

## 2 — Link Aqara Account with Seam

To control your Aqara lock via the Seam API, you must first authorize your Seam workspace against your Aqara account. To do so, Seam provides [Connect Webviews](/docs/core-concepts/connect-webviews): pre-built UX flows that walk you through authorizing your application to control your Aqara lock.

#### Request a Connect Webview

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  import { Seam } from 'seam'

  const seam = new Seam()

  const connectWebview = await seam.connectWebviews.create({
    accepted_providers: ['aqara'],
  })

  console.log(connectWebview.login_successful) // false

  // Send the webview URL to your user
  console.log(connectWebview.url)
  ```

  ```python Python theme={"dark"}
  from seam import Seam

  seam = Seam()

  webview = seam.connect_webviews.create(
      accepted_providers=["aqara"]
  )

  assert webview.login_successful is False

  # Send the webview URL to your user
  print(webview.url)
  ```

  ```ruby Ruby theme={"dark"}
  require "seam"

  seam = Seam.new()

  webview = seam.connect_webviews.create(
    accepted_providers: ["aqara"]
  )

  puts webview.login_successful # false

  # Send the webview URL to your user
  puts webview.url
  ```

  ```php PHP theme={"dark"}
  <?php
  use Seam\SeamClient;

  $seam = new SeamClient("YOUR_API_KEY");

  $webview = $seam->connect_webviews->create(
    accepted_providers: ["aqara"]
  );

  echo $webview->login_successful; // false

  // Send the webview URL to your user
  echo $webview->url;
  ```

  ```csharp C# theme={"dark"}
  using Seam.Client;

  var seam = new SeamClient(apiToken: "YOUR_API_KEY");

  var webview = seam.ConnectWebviews.Create(
    acceptedProviders: new List<string> { "aqara" }
  );

  Console.WriteLine(webview.LoginSuccessful); // false

  // Send the webview URL to your user
  Console.WriteLine(webview.Url);
  ```

  ```java Java theme={"dark"}
  import co.seam.Seam;
  import co.seam.api.types.ConnectWebview;

  Seam seam = Seam.builder().apiKey("YOUR_API_KEY").build();

  ConnectWebview webview = seam.connectWebviews().create(
    ConnectWebviewsCreateRequest.builder()
      .acceptedProviders(List.of("aqara"))
      .build()
  );

  System.out.println(webview.getLoginSuccessful()); // false

  // Send the webview URL to your user
  System.out.println(webview.getUrl());
  ```

  ```bash cURL (bash) theme={"dark"}
  curl -X 'POST' \
    'https://connect.getseam.com/connect_webviews/create' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d '{
      "accepted_providers": ["aqara"]
    }'
  ```
</CodeGroup>

#### Authorize Your Workspace

Navigate to the URL returned by the Webview object. Since you are using a sandbox workspace, complete the login flow by entering the Aqara [sandbox test account](./sandbox-aqara-locks) credentials below:

* **email:** [jane@example.com](mailto:jane@example.com)
* **password:** 1234
* **region:** United States

Confirm the Connect Webview was successful by querying its status:

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  const updatedWebview = await seam.connectWebviews.get(
    connectWebview.connect_webview_id,
  )

  console.log(updatedWebview.login_successful) // true
  ```

  ```python Python theme={"dark"}
  updated_webview = seam.connect_webviews.get(
      connect_webview_id=webview.connect_webview_id
  )

  assert updated_webview.login_successful # true
  ```

  ```ruby Ruby theme={"dark"}
  updated_webview = seam.connect_webviews.get(
    connect_webview_id: webview.connect_webview_id
  )

  puts updated_webview.login_successful # true
  ```

  ```php PHP theme={"dark"}
  <?php
  $updated_webview = $seam->connect_webviews->get(
    connect_webview_id: $webview->connect_webview_id
  );

  echo $updated_webview->login_successful; // true
  ```

  ```csharp C# theme={"dark"}
  var updatedWebview = seam.ConnectWebviews.Get(
    connectWebviewId: webview.ConnectWebviewId
  );

  Console.WriteLine(updatedWebview.LoginSuccessful); // true
  ```

  ```java Java theme={"dark"}
  ConnectWebview updatedWebview = seam.connectWebviews().get(
    ConnectWebviewsGetRequest.builder()
      .connectWebviewId(webview.getConnectWebviewId())
      .build()
  );

  System.out.println(updatedWebview.getLoginSuccessful()); // true
  ```

  ```bash cURL (bash) theme={"dark"}
  curl -X 'POST' \
    'https://connect.getseam.com/connect_webviews/get' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d "{
      \"connect_webview_id\": \"${CONNECT_WEBVIEW_ID}\"
    }"
  ```
</CodeGroup>

## 3 — Retrieve Aqara Lock Devices

After an Aqara account is linked with Seam, you can retrieve devices for this Aqara account. The Seam API exposes most of the device's properties such as battery level or door lock status.

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  const allLocks = await seam.locks.list()

  const someLock = allLocks[0]

  console.log(someLock.properties.online) // true
  console.log(someLock.properties.locked) // true

  console.log(someLock)
  /*
  {
    device_id: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
    device_type: 'aqara_lock',
    capabilities_supported: ['lock', 'access_code'],
    properties: {
      locked: true,
      online: true,
      manufacturer: 'aqara',
      aqara_metadata: {
        device_name: 'Aqara Smart Lock U200',
        model: 'aqara.matter.4447_10242'
      },
      name: 'Aqara Smart Lock U200',
      battery: {
        level: 0.65,
        status: 'good'
      }
    },
    location: null
  }
  */
  ```

  ```python Python theme={"dark"}
  all_locks = seam.locks.list()

  some_lock = all_locks[0]

  assert some_lock.properties["online"] is True
  assert some_lock.properties["locked"] is True

  print(some_lock)

  # Device(
  #     device_id='aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
  #     device_type='aqara_lock',
  #     location=None,
  #     properties={
  #         'locked': True,
  #         'online': True,
  #         'manufacturer': 'aqara',
  #         'aqara_metadata': {
  #             'device_name': 'Aqara Smart Lock U200',
  #             'model': 'aqara.matter.4447_10242'
  #         },
  #         'name': 'Aqara Smart Lock U200',
  #         'battery': {
  #             'level': 0.65,
  #             'status': 'good'
  #         }
  #     },
  #     capabilities_supported=['lock', 'access_code']
  # )
  ```

  ```ruby Ruby theme={"dark"}
  some_lock = seam.locks.list.first

  puts some_lock.properties.online # true
  puts some_lock.properties.locked # true

  puts some_lock.inspect

  # <Seam::Device:0x00438
  #   device_id="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
  #   device_type="aqara_lock"
  #   properties={
  #     "locked"=>true,
  #     "online"=>true,
  #     "manufacturer"=>"aqara",
  #     "aqara_metadata"=>{
  #       "device_name"=>"Aqara Smart Lock U200",
  #       "model"=>"aqara.matter.4447_10242"
  #     },
  #     "name"=>"Aqara Smart Lock U200",
  #     "battery"=>{"level"=>0.65, "status"=>"good"}
  #   }
  # >
  ```

  ```php PHP theme={"dark"}
  <?php
  $locks = $seam->locks->list();

  $some_lock = $locks[0];

  echo $some_lock->properties->online; // true
  echo $some_lock->properties->locked; // true

  echo json_encode($some_lock, JSON_PRETTY_PRINT);

  // {
  //   "device_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  //   "device_type": "aqara_lock",
  //   "properties": {
  //     "locked": true,
  //     "online": true,
  //     "manufacturer": "aqara",
  //     "aqara_metadata": {
  //       "device_name": "Aqara Smart Lock U200",
  //       "model": "aqara.matter.4447_10242"
  //     },
  //     "name": "Aqara Smart Lock U200",
  //     "battery": {
  //       "level": 0.65,
  //       "status": "good"
  //     }
  //   }
  // }
  ```

  ```csharp C# theme={"dark"}
  var locks = seam.Locks.List();

  var someLock = locks[0];

  Console.WriteLine(someLock.Properties.Online); // true
  Console.WriteLine(someLock.Properties.Locked); // true

  Console.WriteLine(someLock);

  // {
  //   "device_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  //   "device_type": "aqara_lock",
  //   "properties": {
  //     "locked": true,
  //     "online": true,
  //     "manufacturer": "aqara",
  //     "aqara_metadata": {
  //       "device_name": "Aqara Smart Lock U200",
  //       "model": "aqara.matter.4447_10242"
  //     },
  //     "name": "Aqara Smart Lock U200",
  //     "battery": {
  //       "level": 0.65,
  //       "status": "good"
  //     }
  //   }
  // }
  ```

  ```java Java theme={"dark"}
  var locks = seam.locks().list();

  var someLock = locks.get(0);

  System.out.println(someLock.getProperties().getOnline()); // true
  System.out.println(someLock.getProperties().getLocked()); // true

  System.out.println(someLock);

  // {
  //   "device_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  //   "device_type": "aqara_lock",
  //   "properties": {
  //     "locked": true,
  //     "online": true,
  //     "manufacturer": "aqara",
  //     "aqara_metadata": {
  //       "device_name": "Aqara Smart Lock U200",
  //       "model": "aqara.matter.4447_10242"
  //     },
  //     "name": "Aqara Smart Lock U200",
  //     "battery": {
  //       "level": 0.65,
  //       "status": "good"
  //     }
  //   }
  // }
  ```

  ```bash cURL (bash) theme={"dark"}
  curl -X 'POST' \
    'https://connect.getseam.com/locks/list' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d '{}'
  ```
</CodeGroup>

## 4 — Lock and Unlock a Door

Next, you can perform the basic action of locking and unlocking the door.

#### Lock a door

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  await seam.locks.lockDoor({ device_id: someLock.device_id })
  ```

  ```python Python theme={"dark"}
  seam.locks.lock_door(device_id=some_lock.device_id)
  ```

  ```ruby Ruby theme={"dark"}
  seam.locks.lock_door(device_id: some_lock.device_id)
  ```

  ```php PHP theme={"dark"}
  <?php
  $seam->locks->lock_door(device_id: $some_lock->device_id);
  ```

  ```csharp C# theme={"dark"}
  seam.Locks.LockDoor(deviceId: someLock.DeviceId);
  ```

  ```java Java theme={"dark"}
  seam.locks().lockDoor(
    LocksLockDoorRequest.builder()
      .deviceId(someLock.getDeviceId())
      .build()
  );
  ```

  ```bash cURL (bash) theme={"dark"}
  curl -X 'POST' \
    'https://connect.getseam.com/locks/lock_door' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d "{
      \"device_id\": \"${DEVICE_ID}\"
    }"
  ```
</CodeGroup>

#### Unlock a door

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  await seam.locks.unlockDoor({ device_id: someLock.device_id })
  ```

  ```python Python theme={"dark"}
  seam.locks.unlock_door(device_id=some_lock.device_id)
  ```

  ```ruby Ruby theme={"dark"}
  seam.locks.unlock_door(device_id: some_lock.device_id)
  ```

  ```php PHP theme={"dark"}
  <?php
  $seam->locks->unlock_door(device_id: $some_lock->device_id);
  ```

  ```csharp C# theme={"dark"}
  seam.Locks.UnlockDoor(deviceId: someLock.DeviceId);
  ```

  ```java Java theme={"dark"}
  seam.locks().unlockDoor(
    LocksUnlockDoorRequest.builder()
      .deviceId(someLock.getDeviceId())
      .build()
  );
  ```

  ```bash cURL (bash) theme={"dark"}
  curl -X 'POST' \
    'https://connect.getseam.com/locks/unlock_door' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d "{
      \"device_id\": \"${DEVICE_ID}\"
    }"
  ```
</CodeGroup>

## 5 — Set Access Codes

Seam enables you to set access codes on Aqara locks with a keypad. You can create ongoing codes that remain active until removed, or timebound codes that are only active during a specified time window.

#### Create an ongoing access code

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  const accessCode = await seam.accessCodes.create({
    device_id: someLock.device_id,
    name: 'My Access Code',
    code: '1234',
  })

  console.log(accessCode)
  /*
  {
    access_code_id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
    device_id: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
    name: 'My Access Code',
    code: '1234',
    type: 'ongoing',
    status: 'setting'
  }
  */
  ```

  ```python Python theme={"dark"}
  access_code = seam.access_codes.create(
      device_id=some_lock.device_id,
      name="My Access Code",
      code="1234"
  )

  print(access_code)

  # AccessCode(
  #     access_code_id='xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
  #     device_id='aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
  #     name='My Access Code',
  #     code='1234',
  #     type='ongoing',
  #     status='setting'
  # )
  ```

  ```ruby Ruby theme={"dark"}
  access_code = seam.access_codes.create(
    device_id: some_lock.device_id,
    name: "My Access Code",
    code: "1234"
  )

  puts access_code.inspect

  # <Seam::AccessCode:0x00438
  #   access_code_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  #   device_id="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
  #   name="My Access Code"
  #   code="1234"
  #   type="ongoing"
  #   status="setting"
  # >
  ```

  ```php PHP theme={"dark"}
  <?php
  $access_code = $seam->access_codes->create(
    device_id: $some_lock->device_id,
    name: "My Access Code",
    code: "1234"
  );

  echo json_encode($access_code, JSON_PRETTY_PRINT);

  // {
  //   "access_code_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  //   "device_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  //   "name": "My Access Code",
  //   "code": "1234",
  //   "type": "ongoing",
  //   "status": "setting"
  // }
  ```

  ```csharp C# theme={"dark"}
  var accessCode = seam.AccessCodes.Create(
    deviceId: someLock.DeviceId,
    name: "My Access Code",
    code: "1234"
  );

  Console.WriteLine(accessCode);

  // {
  //   "access_code_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  //   "device_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  //   "name": "My Access Code",
  //   "code": "1234",
  //   "type": "ongoing",
  //   "status": "setting"
  // }
  ```

  ```java Java theme={"dark"}
  var accessCode = seam.accessCodes().create(
    AccessCodesCreateRequest.builder()
      .deviceId(someLock.getDeviceId())
      .name("My Access Code")
      .code("1234")
      .build()
  );

  System.out.println(accessCode);

  // {
  //   "access_code_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  //   "device_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  //   "name": "My Access Code",
  //   "code": "1234",
  //   "type": "ongoing",
  //   "status": "setting"
  // }
  ```

  ```bash cURL (bash) theme={"dark"}
  curl -X 'POST' \
    'https://connect.getseam.com/access_codes/create' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d "{
      \"device_id\": \"${DEVICE_ID}\",
      \"name\": \"My Access Code\",
      \"code\": \"1234\"
    }"
  ```
</CodeGroup>

#### Create a timebound access code

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  const timeboundCode = await seam.accessCodes.create({
    device_id: someLock.device_id,
    name: 'Guest Access',
    starts_at: '2025-01-01T16:00:00Z',
    ends_at: '2025-01-08T12:00:00Z',
  })

  console.log(timeboundCode)
  /*
  {
    access_code_id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
    device_id: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
    name: 'Guest Access',
    type: 'time_bound',
    starts_at: '2025-01-01T16:00:00.000Z',
    ends_at: '2025-01-08T12:00:00.000Z',
    status: 'unset'
  }
  */
  ```

  ```python Python theme={"dark"}
  timebound_code = seam.access_codes.create(
      device_id=some_lock.device_id,
      name="Guest Access",
      starts_at="2025-01-01T16:00:00Z",
      ends_at="2025-01-08T12:00:00Z"
  )

  print(timebound_code)

  # AccessCode(
  #     access_code_id='xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
  #     device_id='aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
  #     name='Guest Access',
  #     type='time_bound',
  #     starts_at='2025-01-01T16:00:00.000Z',
  #     ends_at='2025-01-08T12:00:00.000Z',
  #     status='unset'
  # )
  ```

  ```ruby Ruby theme={"dark"}
  timebound_code = seam.access_codes.create(
    device_id: some_lock.device_id,
    name: "Guest Access",
    starts_at: "2025-01-01T16:00:00Z",
    ends_at: "2025-01-08T12:00:00Z"
  )

  puts timebound_code.inspect

  # <Seam::AccessCode:0x00438
  #   access_code_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  #   device_id="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
  #   name="Guest Access"
  #   type="time_bound"
  #   starts_at="2025-01-01T16:00:00.000Z"
  #   ends_at="2025-01-08T12:00:00.000Z"
  #   status="unset"
  # >
  ```

  ```php PHP theme={"dark"}
  <?php
  $timebound_code = $seam->access_codes->create(
    device_id: $some_lock->device_id,
    name: "Guest Access",
    starts_at: "2025-01-01T16:00:00Z",
    ends_at: "2025-01-08T12:00:00Z"
  );

  echo json_encode($timebound_code, JSON_PRETTY_PRINT);
  ```

  ```csharp C# theme={"dark"}
  var timeboundCode = seam.AccessCodes.Create(
    deviceId: someLock.DeviceId,
    name: "Guest Access",
    startsAt: "2025-01-01T16:00:00Z",
    endsAt: "2025-01-08T12:00:00Z"
  );

  Console.WriteLine(timeboundCode);
  ```

  ```java Java theme={"dark"}
  var timeboundCode = seam.accessCodes().create(
    AccessCodesCreateRequest.builder()
      .deviceId(someLock.getDeviceId())
      .name("Guest Access")
      .startsAt("2025-01-01T16:00:00Z")
      .endsAt("2025-01-08T12:00:00Z")
      .build()
  );

  System.out.println(timeboundCode);
  ```

  ```bash cURL (bash) theme={"dark"}
  curl -X 'POST' \
    'https://connect.getseam.com/access_codes/create' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d "{
      \"device_id\": \"${DEVICE_ID}\",
      \"name\": \"Guest Access\",
      \"starts_at\": \"2025-01-01T16:00:00Z\",
      \"ends_at\": \"2025-01-08T12:00:00Z\"
    }"
  ```
</CodeGroup>

## Next Steps

Now that you've connected and controlled your Aqara lock with the Seam API, explore the following resources:

* [Access Codes](/docs/low-level-apis/smart-locks/access-codes) — Learn more about managing access codes.
* [Webhooks](/docs/developer-tools/webhooks) — Set up event-driven notifications for lock activity.
* [Connect Webviews](/docs/core-concepts/connect-webviews) — Build custom authorization flows for your users.
* [Core Concepts](/docs/core-concepts/overview) — Understand workspaces, devices, and connected accounts.
