diff --git a/.gitbook.yaml b/.gitbook.yaml
index 1de3d0f3e..548f8e8a4 100644
--- a/.gitbook.yaml
+++ b/.gitbook.yaml
@@ -76,8 +76,8 @@ redirects:
api-clients/access-control-systems/users/update-user: api/acs/users/update.md
api-clients/access-control-systems/users: api/acs/users/README.md
api-clients/access-control-systems: api/acs/README.md
- api-clients/action-attempt/get-action-attempt: api-clients/action_attempts/get.md
- api-clients/action-attempt: api-clients/action_attempts/README.md
+ api-clients/action-attempt/get-action-attempt: api/action_attempts/get.md
+ api-clients/action-attempt: api/action_attempts/README.md
api-clients/client-sessions/create-a-client-session: api/client_sessions/create.md
api-clients/client-sessions/delete-a-client-session: api/client_sessions/delete.md
api-clients/client-sessions/get-a-client-session: api/client_sessions/get.md
diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md
index f64a32e51..8c1069837 100644
--- a/docs/SUMMARY.md
+++ b/docs/SUMMARY.md
@@ -226,8 +226,8 @@
* [Encode an Access Method](api/access_methods/encode.md)
* [Get an Access Method](api/access_methods/get.md)
* [List Access Methods](api/access_methods/list.md)
-* [Action Attempts](api-clients/action_attempts/README.md)
- * [Get Action Attempt](api-clients/action_attempts/get.md)
+* [Action Attempts](api/action_attempts/README.md)
+ * [Get Action Attempt](api/action_attempts/get.md)
* [Client Sessions](api/client_sessions/README.md)
* [Create a Client Session](api/client_sessions/create.md)
* [Delete a Client Session](api/client_sessions/delete.md)
diff --git a/docs/api-overview/overview.md b/docs/api-overview/overview.md
index e96bb31bb..6e342dd36 100644
--- a/docs/api-overview/overview.md
+++ b/docs/api-overview/overview.md
@@ -30,5 +30,5 @@ See the following reference topics:
## Monitoring
* [Events](../api-clients/events/)
-* [Action Attempts](../api-clients/action_attempts/)
+* [Action Attempts](../api/action_attempts/)
* [Connected Accounts](../api/connected_accounts/)
diff --git a/docs/api/action_attempts/README.md b/docs/api/action_attempts/README.md
new file mode 100644
index 000000000..28d3acc72
--- /dev/null
+++ b/docs/api/action_attempts/README.md
@@ -0,0 +1,274 @@
+# Action Attempts
+
+## The action_attempt Object
+
+- [Properties](./#properties)
+- [Events](./#events)
+
+
+Represents an attempt to perform an action against a device.
+
+---
+## Properties
+
+**`action_attempt_id`** *UUID*
+
+ID of the action attempt.
+
+
+
+
+---
+
+**`status`** *Enum*
+
+
+
+
+Enum values
+
+- success
+- pending
+- error
+
+
+
+---
+
+**`action_type`** *String*
+
+Type of the action attempt.
+
+
+
+Enum values
+
+- LOCK_DOOR
+- UNLOCK_DOOR
+- SCAN_CREDENTIAL
+- ENCODE_CREDENTIAL
+- RESET_SANDBOX_WORKSPACE
+- SET_FAN_MODE
+- SET_HVAC_MODE
+- ACTIVATE_CLIMATE_PRESET
+- SIMULATE_KEYPAD_CODE_ENTRY
+- SIMULATE_MANUAL_LOCK_VIA_KEYPAD
+- PUSH_THERMOSTAT_PROGRAMS
+- SYNC_ACCESS_CODES
+- CREATE_ACCESS_CODE
+- DELETE_ACCESS_CODE
+- UPDATE_ACCESS_CODE
+- CREATE_NOISE_THRESHOLD
+- DELETE_NOISE_THRESHOLD
+- UPDATE_NOISE_THRESHOLD
+
+
+
+---
+
+**`error`** *Object*
+
+Errors associated with the action attempt. Null for pending action attempts.
+
+
+
+
+---
+
+**`result`** *Object*
+
+Result of the action attempt. Null for pending action attempts.
+
+
+
+
+---
+
+
+## Events
+
+**`action_attempt.lock_door.succeeded`**
+
+A lock door [action attempt](../../core-concepts/action-attempts.md) succeeded.
+
+
+
+Properties
+
+action_attempt_id UUID
+
+ ID of the affected action attempt.
+
+action_type String
+
+ Type of the action.
+
+created_at Datetime
+
+ Date and time at which the event was created.
+
+event_id UUID
+
+ ID of the event.
+
+event_type Enum
+
+ Value: `action_attempt.lock_door.succeeded`
+
+occurred_at Datetime
+
+ Date and time at which the event occurred.
+
+status String
+
+ Status of the action.
+
+workspace_id UUID
+
+ ID of the [workspace](../../core-concepts/workspaces/README.md) associated with the event.
+
+
+---
+
+**`action_attempt.lock_door.failed`**
+
+A lock door [action attempt](../../core-concepts/action-attempts.md) failed.
+
+
+
+Properties
+
+action_attempt_id UUID
+
+ ID of the affected action attempt.
+
+action_type String
+
+ Type of the action.
+
+created_at Datetime
+
+ Date and time at which the event was created.
+
+event_id UUID
+
+ ID of the event.
+
+event_type Enum
+
+ Value: `action_attempt.lock_door.failed`
+
+occurred_at Datetime
+
+ Date and time at which the event occurred.
+
+status String
+
+ Status of the action.
+
+workspace_id UUID
+
+ ID of the [workspace](../../core-concepts/workspaces/README.md) associated with the event.
+
+
+---
+
+**`action_attempt.unlock_door.succeeded`**
+
+An unlock door [action attempt](../../core-concepts/action-attempts.md) succeeded.
+
+
+
+Properties
+
+action_attempt_id UUID
+
+ ID of the affected action attempt.
+
+action_type String
+
+ Type of the action.
+
+created_at Datetime
+
+ Date and time at which the event was created.
+
+event_id UUID
+
+ ID of the event.
+
+event_type Enum
+
+ Value: `action_attempt.unlock_door.succeeded`
+
+occurred_at Datetime
+
+ Date and time at which the event occurred.
+
+status String
+
+ Status of the action.
+
+workspace_id UUID
+
+ ID of the [workspace](../../core-concepts/workspaces/README.md) associated with the event.
+
+
+---
+
+**`action_attempt.unlock_door.failed`**
+
+An unlock door [action attempt](../../core-concepts/action-attempts.md) failed.
+
+
+
+Properties
+
+action_attempt_id UUID
+
+ ID of the affected action attempt.
+
+action_type String
+
+ Type of the action.
+
+created_at Datetime
+
+ Date and time at which the event was created.
+
+event_id UUID
+
+ ID of the event.
+
+event_type Enum
+
+ Value: `action_attempt.unlock_door.failed`
+
+occurred_at Datetime
+
+ Date and time at which the event occurred.
+
+status String
+
+ Status of the action.
+
+workspace_id UUID
+
+ ID of the [workspace](../../core-concepts/workspaces/README.md) associated with the event.
+
+
+---
+
+## Endpoints
+
+
+[**`/action_attempts/get`**](./get.md)
+
+Returns a specified [action attempt](../../core-concepts/action-attempts.md).
+
+
+[**`/action_attempts/list`**](./list.md)
+
+Returns a list of the [action attempts](../../core-concepts/action-attempts.md) that you specify as an array of `action_attempt_id`s.
+
+
diff --git a/docs/api/action_attempts/get.md b/docs/api/action_attempts/get.md
new file mode 100644
index 000000000..852f841b0
--- /dev/null
+++ b/docs/api/action_attempts/get.md
@@ -0,0 +1,188 @@
+# Get an Action Attempt
+
+- [Request Parameters](#request-parameters)
+- [Response](#response)
+
+Returns a specified [action attempt](../../core-concepts/action-attempts.md).
+
+
+{% tabs %}
+{% tab title="JavaScript" %}
+
+Returns a specified action attempt.
+
+#### Code:
+
+```javascript
+await seam.actionAttempts.get({
+ action_attempt_id: "5f4e3d2c-1b0a-9f8e-7d6c-5b4a3c2d1e0f",
+});
+```
+
+#### Output:
+
+```javascript
+{
+ "action_attempt_id": "5f4e3d2c-1b0a-9f8e-7d6c-5b4a3c2d1e0f",
+ "action_type": "UNLOCK_DOOR",
+ "error": null,
+ "result": {},
+ "status": "success"
+}
+```
+{% endtab %}
+
+{% tab title="cURL" %}
+
+Returns a specified action attempt.
+
+#### Code:
+
+```curl
+curl --include --request POST "https://connect.getseam.com/action_attempts/get" \
+ --header "Authorization: Bearer $SEAM_API_KEY" \
+ --json @- < "5f4e3d2c-1b0a-9f8e-7d6c-5b4a3c2d1e0f",
+ "action_type" => "UNLOCK_DOOR",
+ "error" => nil,
+ "result" => {
+ },
+ "status" => "success",
+}
+```
+{% endtab %}
+
+{% tab title="PHP" %}
+
+Returns a specified action attempt.
+
+#### Code:
+
+```php
+$seam->action_attempts->get(
+ action_attempt_id: "5f4e3d2c-1b0a-9f8e-7d6c-5b4a3c2d1e0f"
+);
+```
+
+#### Output:
+
+```php
+[
+ "action_attempt_id" => "5f4e3d2c-1b0a-9f8e-7d6c-5b4a3c2d1e0f",
+ "action_type" => "UNLOCK_DOOR",
+ "error" => null,
+ "result" => [],
+ "status" => "success",
+];
+```
+{% endtab %}
+
+{% tab title="Seam CLI" %}
+
+Returns a specified action attempt.
+
+#### Code:
+
+```seam_cli
+seam action-attempts get --action_attempt_id "5f4e3d2c-1b0a-9f8e-7d6c-5b4a3c2d1e0f"
+```
+
+#### Output:
+
+```seam_cli
+{
+ "action_attempt_id": "5f4e3d2c-1b0a-9f8e-7d6c-5b4a3c2d1e0f",
+ "action_type": "UNLOCK_DOOR",
+ "error": null,
+ "result": {},
+ "status": "success"
+}
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+
+
+Authentication Methods
+
+- API key
+- Client session token
+- Personal access token
+
Must also include the `seam-workspace` header in the request.
+
+To learn more, see [Authentication](https://docs.seam.co/latest/api/authentication).
+
+
+## Request Parameters
+
+**`action_attempt_id`** *String* (Required)
+
+ID of the action attempt that you want to get.
+
+---
+
+
+## Response
+
+[action\_attempt](./)
+
diff --git a/docs/api/action_attempts/list.md b/docs/api/action_attempts/list.md
new file mode 100644
index 000000000..d6e0f77c8
--- /dev/null
+++ b/docs/api/action_attempts/list.md
@@ -0,0 +1,258 @@
+# List Action Attempts
+
+- [Request Parameters](#request-parameters)
+- [Response](#response)
+
+Returns a list of the [action attempts](../../core-concepts/action-attempts.md) that you specify as an array of `action_attempt_id`s.
+
+
+{% tabs %}
+{% tab title="JavaScript" %}
+
+Returns a list of the action attempts that you specify as an array of `action_attempt_id`s.
+
+#### Code:
+
+```javascript
+await seam.actionAttempts.list({
+ action_attempt_ids: [
+ "5f4e3d2c-1b0a-9f8e-7d6c-5b4a3c2d1e0f",
+ "3f2b1c8d-1b5e-4f8c-9c7d-9a8b7c6d5e4f",
+ ],
+});
+```
+
+#### Output:
+
+```javascript
+[
+ {
+ "action_attempt_id": "5f4e3d2c-1b0a-9f8e-7d6c-5b4a3c2d1e0f",
+ "action_type": "UNLOCK_DOOR",
+ "error": null,
+ "result": {},
+ "status": "success"
+ },
+ {
+ "action_attempt_id": "3f2b1c8d-1b5e-4f8c-9c7d-9a8b7c6d5e4f",
+ "action_type": "LOCK_DOOR",
+ "error": null,
+ "result": {},
+ "status": "success"
+ }
+]
+```
+{% endtab %}
+
+{% tab title="cURL" %}
+
+Returns a list of the action attempts that you specify as an array of `action_attempt_id`s.
+
+#### Code:
+
+```curl
+curl --include --request POST "https://connect.getseam.com/action_attempts/list" \
+ --header "Authorization: Bearer $SEAM_API_KEY" \
+ --json @- < "5f4e3d2c-1b0a-9f8e-7d6c-5b4a3c2d1e0f",
+ "action_type" => "UNLOCK_DOOR",
+ "error" => nil,
+ "result" => {
+ },
+ "status" => "success",
+ },
+ {
+ "action_attempt_id" => "3f2b1c8d-1b5e-4f8c-9c7d-9a8b7c6d5e4f",
+ "action_type" => "LOCK_DOOR",
+ "error" => nil,
+ "result" => {
+ },
+ "status" => "success",
+ },
+]
+```
+{% endtab %}
+
+{% tab title="PHP" %}
+
+Returns a list of the action attempts that you specify as an array of `action_attempt_id`s.
+
+#### Code:
+
+```php
+$seam->action_attempts->list(
+ action_attempt_ids: [
+ "5f4e3d2c-1b0a-9f8e-7d6c-5b4a3c2d1e0f",
+ "3f2b1c8d-1b5e-4f8c-9c7d-9a8b7c6d5e4f",
+ ]
+);
+```
+
+#### Output:
+
+```php
+[
+ [
+ "action_attempt_id" => "5f4e3d2c-1b0a-9f8e-7d6c-5b4a3c2d1e0f",
+ "action_type" => "UNLOCK_DOOR",
+ "error" => null,
+ "result" => [],
+ "status" => "success",
+ ],
+ [
+ "action_attempt_id" => "3f2b1c8d-1b5e-4f8c-9c7d-9a8b7c6d5e4f",
+ "action_type" => "LOCK_DOOR",
+ "error" => null,
+ "result" => [],
+ "status" => "success",
+ ],
+];
+```
+{% endtab %}
+
+{% tab title="Seam CLI" %}
+
+Returns a list of the action attempts that you specify as an array of `action_attempt_id`s.
+
+#### Code:
+
+```seam_cli
+seam action-attempts list --action_attempt_ids ["5f4e3d2c-1b0a-9f8e-7d6c-5b4a3c2d1e0f","3f2b1c8d-1b5e-4f8c-9c7d-9a8b7c6d5e4f"]
+```
+
+#### Output:
+
+```seam_cli
+[
+ {
+ "action_attempt_id": "5f4e3d2c-1b0a-9f8e-7d6c-5b4a3c2d1e0f",
+ "action_type": "UNLOCK_DOOR",
+ "error": null,
+ "result": {},
+ "status": "success"
+ },
+ {
+ "action_attempt_id": "3f2b1c8d-1b5e-4f8c-9c7d-9a8b7c6d5e4f",
+ "action_type": "LOCK_DOOR",
+ "error": null,
+ "result": {},
+ "status": "success"
+ }
+]
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+
+
+Authentication Methods
+
+- API key
+- Personal access token
+
Must also include the `seam-workspace` header in the request.
+
+To learn more, see [Authentication](https://docs.seam.co/latest/api/authentication).
+
+
+## Request Parameters
+
+**`action_attempt_ids`** *Array* *of UUIDs* (Required)
+
+IDs of the action attempts that you want to retrieve.
+
+---
+
+
+## Response
+
+Array of [action\_attempts](./)
+
diff --git a/docs/capability-guides/thermostats/creating-and-managing-climate-presets/activating-a-climate-preset.md b/docs/capability-guides/thermostats/creating-and-managing-climate-presets/activating-a-climate-preset.md
index 69757361c..cb450291c 100644
--- a/docs/capability-guides/thermostats/creating-and-managing-climate-presets/activating-a-climate-preset.md
+++ b/docs/capability-guides/thermostats/creating-and-managing-climate-presets/activating-a-climate-preset.md
@@ -153,7 +153,7 @@ $seam->thermostats->activate_climate_preset(
## Poll the Action Attempt
-Activating a climate preset returns an [action attempt](../../../core-concepts/action-attempts.md). Use the `action_attempt_id` from this response to poll the associated action attempt using the [`/action_attempts/get`](../../../api-clients/action_attempts/get.md) request. When the activation completes successfully, the `status` of the action attempt changes to `success`.
+Activating a climate preset returns an [action attempt](../../../core-concepts/action-attempts.md). Use the `action_attempt_id` from this response to poll the associated action attempt using the [`/action_attempts/get`](../../../api/action_attempts/get.md) request. When the activation completes successfully, the `status` of the action attempt changes to `success`.
{% tabs %}
{% tab title="Python" %}
diff --git a/docs/core-concepts/action-attempts.md b/docs/core-concepts/action-attempts.md
index 2598a9aec..e63f7cba3 100644
--- a/docs/core-concepts/action-attempts.md
+++ b/docs/core-concepts/action-attempts.md
@@ -20,4 +20,4 @@ This action attempt enables you to keep track of the progress of your action.
Our client libraries do this automatically for you. However, you can also choose not to wait and to check on the action at a later time.
-For more information, see the [Action Attempts](../api-clients/action_attempts/) in the Seam API reference.
+For more information, see the [Action Attempts](../api/action_attempts/) in the Seam API reference.
diff --git a/docs/device-and-system-integration-guides/33-lock-devices/get-started-with-33-lock-devices.md b/docs/device-and-system-integration-guides/33-lock-devices/get-started-with-33-lock-devices.md
index d8b7e51e8..3bab75919 100644
--- a/docs/device-and-system-integration-guides/33-lock-devices/get-started-with-33-lock-devices.md
+++ b/docs/device-and-system-integration-guides/33-lock-devices/get-started-with-33-lock-devices.md
@@ -875,7 +875,7 @@ if (frontDoor.CanRemotelyUnlock == true) {
{% endtab %}
{% endtabs %}
-You can track the status of the unlock operation to confirm that the device unlocked successfully. Query the `locked` status of the device, [retrieve the action attempt](../../api-clients/action_attempts/get.md) by ID, or look for a [`lock.unlocked` event](../../api-clients/events/#event-types).
+You can track the status of the unlock operation to confirm that the device unlocked successfully. Query the `locked` status of the device, [retrieve the action attempt](../../api/action_attempts/get.md) by ID, or look for a [`lock.unlocked` event](../../api-clients/events/#event-types).
To query the `locked` status of the device:
diff --git a/docs/device-and-system-integration-guides/4suites-locks/get-started-with-4suites-locks.md b/docs/device-and-system-integration-guides/4suites-locks/get-started-with-4suites-locks.md
index db9ebd207..14ff58065 100644
--- a/docs/device-and-system-integration-guides/4suites-locks/get-started-with-4suites-locks.md
+++ b/docs/device-and-system-integration-guides/4suites-locks/get-started-with-4suites-locks.md
@@ -856,7 +856,7 @@ if (frontDoor.CanRemotelyUnlock == true) {
{% endtab %}
{% endtabs %}
-You can track the status of the unlock operation to confirm that the device unlocked successfully. Query the `locked` status of the device, [retrieve the action attempt](../../api-clients/action_attempts/get.md) by ID, or look for a [`lock.unlocked` event](../../api-clients/events/#event-types).
+You can track the status of the unlock operation to confirm that the device unlocked successfully. Query the `locked` status of the device, [retrieve the action attempt](../../api/action_attempts/get.md) by ID, or look for a [`lock.unlocked` event](../../api-clients/events/#event-types).
To query the `locked` status of the device:
diff --git a/docs/device-and-system-integration-guides/akiles-locks/get-started-with-akiles-locks.md b/docs/device-and-system-integration-guides/akiles-locks/get-started-with-akiles-locks.md
index 02f09d3ea..ba62d24d2 100644
--- a/docs/device-and-system-integration-guides/akiles-locks/get-started-with-akiles-locks.md
+++ b/docs/device-and-system-integration-guides/akiles-locks/get-started-with-akiles-locks.md
@@ -857,7 +857,7 @@ if (frontDoor.CanRemotelyUnlock == true) {
{% endtab %}
{% endtabs %}
-You can track the status of the unlock operation to confirm that the device unlocked successfully. Query the `locked` status of the device, [retrieve the action attempt](../../api-clients/action_attempts/get.md) by ID, or look for a [`lock.unlocked` event](../../api-clients/events/#event-types).
+You can track the status of the unlock operation to confirm that the device unlocked successfully. Query the `locked` status of the device, [retrieve the action attempt](../../api/action_attempts/get.md) by ID, or look for a [`lock.unlocked` event](../../api-clients/events/#event-types).
To query the `locked` status of the device:
diff --git a/docs/device-and-system-integration-guides/google-nest-thermostats/get-started-with-nest-thermostats.md b/docs/device-and-system-integration-guides/google-nest-thermostats/get-started-with-nest-thermostats.md
index ea767a586..4052468d3 100644
--- a/docs/device-and-system-integration-guides/google-nest-thermostats/get-started-with-nest-thermostats.md
+++ b/docs/device-and-system-integration-guides/google-nest-thermostats/get-started-with-nest-thermostats.md
@@ -919,7 +919,7 @@ if ($living_room_thermostat->can_hvac_heat) {
{% endtab %}
{% endtabs %}
-You can track the status of the operation to confirm that the device was set to heat mode successfully. Query `properties.current_climate_setting.hvac_mode_setting` for the device, [retrieve the action attempt](../../api-clients/action_attempts/get.md) by ID, or look for a [`thermostat.manually_adjusted` event](../../api-clients/events/#event-types). Further, if you wanted to find out whether the HVAC system was currently heating, you could inspect `properties.is_heating` for the device.
+You can track the status of the operation to confirm that the device was set to heat mode successfully. Query `properties.current_climate_setting.hvac_mode_setting` for the device, [retrieve the action attempt](../../api/action_attempts/get.md) by ID, or look for a [`thermostat.manually_adjusted` event](../../api-clients/events/#event-types). Further, if you wanted to find out whether the HVAC system was currently heating, you could inspect `properties.is_heating` for the device.
To query `properties.current_climate_setting.hvac_mode_setting` for the device:
diff --git a/docs/device-and-system-integration-guides/honeywell-thermostats/get-started-with-honeywell-thermostats.md b/docs/device-and-system-integration-guides/honeywell-thermostats/get-started-with-honeywell-thermostats.md
index 192fac37f..efdcb13b4 100644
--- a/docs/device-and-system-integration-guides/honeywell-thermostats/get-started-with-honeywell-thermostats.md
+++ b/docs/device-and-system-integration-guides/honeywell-thermostats/get-started-with-honeywell-thermostats.md
@@ -919,7 +919,7 @@ if ($living_room_thermostat->can_hvac_heat) {
{% endtab %}
{% endtabs %}
-You can track the status of the operation to confirm that the device was set to heat mode successfully. Query `properties.current_climate_setting.hvac_mode_setting` for the device, [retrieve the action attempt](../../api-clients/action_attempts/get.md) by ID, or look for a [`thermostat.manually_adjusted` event](../../api-clients/events/#event-types). Further, if you wanted to find out whether the HVAC system was currently heating, you could inspect `properties.is_heating` for the device.
+You can track the status of the operation to confirm that the device was set to heat mode successfully. Query `properties.current_climate_setting.hvac_mode_setting` for the device, [retrieve the action attempt](../../api/action_attempts/get.md) by ID, or look for a [`thermostat.manually_adjusted` event](../../api-clients/events/#event-types). Further, if you wanted to find out whether the HVAC system was currently heating, you could inspect `properties.is_heating` for the device.
To query `properties.current_climate_setting.hvac_mode_setting` for the device:
diff --git a/docs/device-and-system-integration-guides/sensi-thermostats/get-started-with-sensi-thermostats.md b/docs/device-and-system-integration-guides/sensi-thermostats/get-started-with-sensi-thermostats.md
index ac1d08362..5de69deb2 100644
--- a/docs/device-and-system-integration-guides/sensi-thermostats/get-started-with-sensi-thermostats.md
+++ b/docs/device-and-system-integration-guides/sensi-thermostats/get-started-with-sensi-thermostats.md
@@ -912,7 +912,7 @@ if ($living_room_thermostat->can_hvac_heat) {
{% endtab %}
{% endtabs %}
-You can track the status of the operation to confirm that the device was set to heat mode successfully. Query `properties.current_climate_setting.hvac_mode_setting` for the device, [retrieve the action attempt](../../api-clients/action_attempts/get.md) by ID, or look for a [`thermostat.manually_adjusted` event](../../api-clients/events/#event-types). Further, if you wanted to find out whether the HVAC system was currently heating, you could inspect `properties.is_heating` for the device.
+You can track the status of the operation to confirm that the device was set to heat mode successfully. Query `properties.current_climate_setting.hvac_mode_setting` for the device, [retrieve the action attempt](../../api/action_attempts/get.md) by ID, or look for a [`thermostat.manually_adjusted` event](../../api-clients/events/#event-types). Further, if you wanted to find out whether the HVAC system was currently heating, you could inspect `properties.is_heating` for the device.
To query `properties.current_climate_setting.hvac_mode_setting` for the device:
diff --git a/docs/device-and-system-integration-guides/smartthings-hubs-+-devices/get-started-with-smartthings-hubs-+-thermostats.md b/docs/device-and-system-integration-guides/smartthings-hubs-+-devices/get-started-with-smartthings-hubs-+-thermostats.md
index c4c1efb75..722bb73f1 100644
--- a/docs/device-and-system-integration-guides/smartthings-hubs-+-devices/get-started-with-smartthings-hubs-+-thermostats.md
+++ b/docs/device-and-system-integration-guides/smartthings-hubs-+-devices/get-started-with-smartthings-hubs-+-thermostats.md
@@ -922,7 +922,7 @@ if ($living_room_thermostat->can_hvac_heat) {
{% endtab %}
{% endtabs %}
-You can track the status of the operation to confirm that the device was set to heat mode successfully. Query `properties.current_climate_setting.hvac_mode_setting` for the device, [retrieve the action attempt](../../api-clients/action_attempts/get.md) by ID, or look for a [`thermostat.manually_adjusted` event](../../api-clients/events/#event-types). Further, if you wanted to find out whether the HVAC system was currently heating, you could inspect `properties.is_heating` for the device.
+You can track the status of the operation to confirm that the device was set to heat mode successfully. Query `properties.current_climate_setting.hvac_mode_setting` for the device, [retrieve the action attempt](../../api/action_attempts/get.md) by ID, or look for a [`thermostat.manually_adjusted` event](../../api-clients/events/#event-types). Further, if you wanted to find out whether the HVAC system was currently heating, you could inspect `properties.is_heating` for the device.
To query `properties.current_climate_setting.hvac_mode_setting` for the device:
diff --git a/docs/device-guides/get-started-with-august-locks.md b/docs/device-guides/get-started-with-august-locks.md
index 6ed00eff6..7013ab8bd 100644
--- a/docs/device-guides/get-started-with-august-locks.md
+++ b/docs/device-guides/get-started-with-august-locks.md
@@ -878,7 +878,7 @@ if (frontDoor.CanRemotelyUnlock == true) {
{% endtab %}
{% endtabs %}
-You can track the status of the unlock operation to confirm that the device unlocked successfully. Query the `locked` status of the device, [retrieve the action attempt](../api-clients/action_attempts/get.md) by ID, or look for a [`lock.unlocked` event](../api-clients/events/#event-types).
+You can track the status of the unlock operation to confirm that the device unlocked successfully. Query the `locked` status of the device, [retrieve the action attempt](../api/action_attempts/get.md) by ID, or look for a [`lock.unlocked` event](../api-clients/events/#event-types).
To query the `locked` status of the device:
diff --git a/docs/device-guides/get-started-with-ecobee-thermostats.md b/docs/device-guides/get-started-with-ecobee-thermostats.md
index 68049aecd..18dc34ede 100644
--- a/docs/device-guides/get-started-with-ecobee-thermostats.md
+++ b/docs/device-guides/get-started-with-ecobee-thermostats.md
@@ -917,7 +917,7 @@ if ($living_room_thermostat->can_hvac_heat) {
{% endtab %}
{% endtabs %}
-You can track the status of the operation to confirm that the device was set to heat mode successfully. Query `properties.current_climate_setting.hvac_mode_setting` for the device, [retrieve the action attempt](../api-clients/action_attempts/get.md) by ID, or look for a [`thermostat.manually_adjusted` event](../api-clients/events/#event-types). Further, if you wanted to find out whether the HVAC system was currently heating, you could inspect `properties.is_heating` for the device.
+You can track the status of the operation to confirm that the device was set to heat mode successfully. Query `properties.current_climate_setting.hvac_mode_setting` for the device, [retrieve the action attempt](../api/action_attempts/get.md) by ID, or look for a [`thermostat.manually_adjusted` event](../api-clients/events/#event-types). Further, if you wanted to find out whether the HVAC system was currently heating, you could inspect `properties.is_heating` for the device.
To query `properties.current_climate_setting.hvac_mode_setting` for the device:
diff --git a/docs/device-guides/get-started-with-smartthings-hubs-+-smart-locks.md b/docs/device-guides/get-started-with-smartthings-hubs-+-smart-locks.md
index 23136267c..6a0566a2c 100644
--- a/docs/device-guides/get-started-with-smartthings-hubs-+-smart-locks.md
+++ b/docs/device-guides/get-started-with-smartthings-hubs-+-smart-locks.md
@@ -879,7 +879,7 @@ if (frontDoor.CanRemotelyUnlock == true) {
{% endtab %}
{% endtabs %}
-You can track the status of the unlock operation to confirm that the device unlocked successfully. Query the `locked` status of the device, [retrieve the action attempt](../api-clients/action_attempts/get.md) by ID, or look for a [`lock.unlocked` event](../api-clients/events/#event-types).
+You can track the status of the unlock operation to confirm that the device unlocked successfully. Query the `locked` status of the device, [retrieve the action attempt](../api/action_attempts/get.md) by ID, or look for a [`lock.unlocked` event](../api-clients/events/#event-types).
To query the `locked` status of the device:
diff --git a/docs/device-guides/get-started-with-ttlock-devices.md b/docs/device-guides/get-started-with-ttlock-devices.md
index 4e0c8db8b..60dcf9a92 100644
--- a/docs/device-guides/get-started-with-ttlock-devices.md
+++ b/docs/device-guides/get-started-with-ttlock-devices.md
@@ -875,7 +875,7 @@ if (frontDoor.CanRemotelyUnlock == true) {
{% endtab %}
{% endtabs %}
-You can track the status of the unlock operation to confirm that the device unlocked successfully. Query the `locked` status of the device, [retrieve the action attempt](../api-clients/action_attempts/get.md) by ID, or look for a [`lock.unlocked` event](../api-clients/events/#event-types).
+You can track the status of the unlock operation to confirm that the device unlocked successfully. Query the `locked` status of the device, [retrieve the action attempt](../api/action_attempts/get.md) by ID, or look for a [`lock.unlocked` event](../api-clients/events/#event-types).
To query the `locked` status of the device:
diff --git a/docs/products/smart-locks/lock-and-unlock.md b/docs/products/smart-locks/lock-and-unlock.md
index ccf7fae3f..5d4115d57 100644
--- a/docs/products/smart-locks/lock-and-unlock.md
+++ b/docs/products/smart-locks/lock-and-unlock.md
@@ -10,7 +10,7 @@ Seam enables you to lock or unlock your door lock remotely. This guide walks you
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.md), 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-clients/action_attempts/get.md). Once Seam has successfully confirmed the action, the action attempt's `status` will indicate `success`.
+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.md). Once Seam has successfully confirmed the action, the action attempt's `status` will indicate `success`.
For those who prefer using webhooks to verify the success of an action, we'll soon introduce events that confirm an action's success.
@@ -687,7 +687,7 @@ seam.Locks.LockDoor(deviceId: "11111111-1111-1111-1111-444444444444");
### 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-clients/action_attempts/get.md). When the action attempt's `status` changes to `success`, it indicates the action has been successful.
+Use the `action_attempt_id` from the prior response to make a [Get Action Attempt request](../../api/action_attempts/get.md). When the action attempt's `status` changes to `success`, it indicates the action has been successful.
{% tabs %}
{% tab title="Python" %}
diff --git a/docs/products/thermostats/configure-current-climate-settings.md b/docs/products/thermostats/configure-current-climate-settings.md
index 6a04a4290..a6a1ba3b5 100644
--- a/docs/products/thermostats/configure-current-climate-settings.md
+++ b/docs/products/thermostats/configure-current-climate-settings.md
@@ -1134,7 +1134,7 @@ $seam->thermostats->set_fan_mode(
## Poll the Action Attempt
-The imperative HVAC or fan mode setting request returns an [action attempt](../../core-concepts/action-attempts.md). Use the `action_attempt_id` from this response to poll the associated action attempt using the [`/action_attempts/get`](../../api-clients/action_attempts/get.md) request. When the setting modification completes successfully, the `status` of the action attempt changes to `success`.
+The imperative HVAC or fan mode setting request returns an [action attempt](../../core-concepts/action-attempts.md). Use the `action_attempt_id` from this response to poll the associated action attempt using the [`/action_attempts/get`](../../api/action_attempts/get.md) request. When the setting modification completes successfully, the `status` of the action attempt changes to `success`.
{% tabs %}
{% tab title="Python" %}
diff --git a/src/data/paths.yaml b/src/data/paths.yaml
index 852f6b2ab..6012e44a1 100644
--- a/src/data/paths.yaml
+++ b/src/data/paths.yaml
@@ -163,6 +163,11 @@
/devices/simulate:
title: Device Simulations
+/action_attempts:
+ title: Action Attempts
+ resources:
+ - action_attempt
+
/locks:
title: Locks
resources:
diff --git a/src/lib/layout/api-endpoint.ts b/src/lib/layout/api-endpoint.ts
index 34c579a2f..abf5739bd 100644
--- a/src/lib/layout/api-endpoint.ts
+++ b/src/lib/layout/api-endpoint.ts
@@ -192,6 +192,9 @@ export function setEndpointLayoutContext(
name: actionAttempt.actionAttemptType,
description: actionAttempt.description,
hidePreamble: false,
+ errorGroups: [],
+ warningGroups: [],
+ resourceSamples: [],
propertyGroups: groupProperties(
actionAttempt.properties.filter(
({ isUndocumented }) => !isUndocumented,
diff --git a/src/lib/layout/api-route.ts b/src/lib/layout/api-route.ts
index 42f7843b5..db9bd48db 100644
--- a/src/lib/layout/api-route.ts
+++ b/src/lib/layout/api-route.ts
@@ -20,13 +20,7 @@ export interface ApiRouteLayoutContext {
path: string
isAlpha: boolean
alphaMessage: string | undefined
- resources: Array<
- ApiRouteResource & {
- warningGroups: ApiRouteVariantGroup[]
- errorGroups: ApiRouteVariantGroup[]
- resourceSamples: ResourceSampleContext[]
- }
- >
+ resources: ApiRouteResource[]
endpoints: ApiRouteEndpoint[]
events: ApiRouteEvent[]
}
@@ -77,6 +71,9 @@ export interface ApiRouteResource {
events: ApiRouteEvent[]
hidePreamble: boolean
endpoints?: ApiRouteEndpoint[]
+ warningGroups: ApiRouteVariantGroup[]
+ errorGroups: ApiRouteVariantGroup[]
+ resourceSamples: ResourceSampleContext[]
}
interface ApiRouteVariantGroup {
@@ -135,6 +132,11 @@ export const setApiRouteLayoutContext = (
(r) => r.resourceType === resourceType,
)
+ if (resourceType === 'action_attempt') {
+ processActionAttemptResource(blueprint, file.resources, eventsByRoutePath)
+ continue
+ }
+
if (resource == null) {
throw new Error(
`Path metadata for ${route.path} has invalid resource type ${resourceType}`,
@@ -432,8 +434,6 @@ const groupEventsByRoutePath = (
const eventsByRoutePath = new Map()
for (const event of events) {
- if (event.routePath == null) continue
-
const routeEvents = eventsByRoutePath.get(event.routePath) ?? []
routeEvents.push({
name: event.eventType,
@@ -622,3 +622,80 @@ const getParentVariantResourceType = (
if (key == null) return null
return keyMap[key] ?? null
}
+
+function processActionAttemptResource(
+ blueprint: Blueprint,
+ resources: ApiRouteResource[],
+ eventsByRoutePath: Map,
+): void {
+ const blueprintActionAttemptDef = blueprint.actionAttempts[0]
+ if (blueprintActionAttemptDef == null) {
+ throw new Error(
+ 'Cannot process action attempt resource: blueprint.actionAttempts is empty.',
+ )
+ }
+
+ const idPropKey = 'action_attempt_id'
+ const idPropDef = blueprintActionAttemptDef.properties.find(
+ (p) => p.name === idPropKey,
+ )
+ if (idPropDef == null) {
+ throw new Error(
+ `Blueprint action attempt is missing "${idPropKey}" property.`,
+ )
+ }
+
+ const statusPropKey = 'status'
+ const statusPropDef = blueprintActionAttemptDef.properties.find(
+ (p) => p.name === statusPropKey,
+ )
+ if (statusPropDef == null) {
+ throw new Error(
+ `Blueprint action attempt is missing "${statusPropKey}" property.`,
+ )
+ }
+
+ const actionTypes = blueprint.actionAttempts.map(
+ (attempt) => attempt.actionAttemptType,
+ )
+
+ const properties: ApiRouteProperty[] = [
+ mapBlueprintPropertyToRouteProperty(idPropDef),
+ mapBlueprintPropertyToRouteProperty(statusPropDef),
+ {
+ name: 'action_type',
+ description: 'Type of the action attempt.',
+ format: 'String',
+ isDeprecated: false,
+ deprecationMessage: '',
+ enumValues: actionTypes,
+ },
+ {
+ name: 'error',
+ description:
+ 'Errors associated with the action attempt. Null for pending action attempts.',
+ format: 'Object',
+ isDeprecated: false,
+ deprecationMessage: '',
+ },
+ {
+ name: 'result',
+ description:
+ 'Result of the action attempt. Null for pending action attempts.',
+ format: 'Object',
+ isDeprecated: false,
+ deprecationMessage: '',
+ },
+ ]
+
+ resources.push({
+ name: 'action_attempt',
+ description: 'Represents an attempt to perform an action against a device.',
+ propertyGroups: [{ propertyGroupKey: null, properties }],
+ hidePreamble: false,
+ errorGroups: [],
+ warningGroups: [],
+ resourceSamples: [],
+ events: eventsByRoutePath.get('/action_attempts') ?? [],
+ })
+}
diff --git a/src/lib/reference.ts b/src/lib/reference.ts
index acfa10744..07b487932 100644
--- a/src/lib/reference.ts
+++ b/src/lib/reference.ts
@@ -75,6 +75,7 @@ export const reference = (
!path.startsWith('/devices') &&
!path.startsWith('/locks') &&
!path.startsWith('/noise_sensors') &&
+ !path.startsWith('/action_attempts') &&
!path.startsWith('/access_codes')
) {
return false