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

# Resuming a Thermostat Schedule

> Release a hold and return a thermostat to its native weekly program using the Seam API.

Use [`/thermostats/activate_weekly_program`](/docs/api/thermostats/activate_weekly_program) to release a hold set by Seam and resume the schedule already configured on the thermostat. For example, after temporarily changing a set point for a demand-response event, you can return the thermostat to the schedule that the user configured in the manufacturer's app.

This native weekly program is the schedule stored on the device. Resuming it does not create or replace its daily periods or temperature settings. You only need the thermostat's `device_id`.

<Info>
  To create or change a weekly program through Seam, see [Creating and Managing
  Thermostat Programs](/docs/capability-guides/thermostats/creating-and-managing-thermostat-programs).
  Use `activate_weekly_program` when you want to resume the program already on
  the device.
</Info>

## Before You Begin

Connect the thermostat to Seam and make sure that the desired schedule is configured on the device or in the manufacturer's app.

Resuming a native weekly program is supported through the Honeywell Resideo, ecobee, and Sensi integrations. Check the device's top-level `can_activate_weekly_program` capability flag before making the request. This flag must be present and `true`. Google Nest and SmartThings thermostats do not support this operation through Seam.

Set `SEAM_API_KEY` in your environment and replace the sample device ID. Reuse the client initialized in the first example for the following steps. Java and Go snippets belong inside your application method or function, with the imports at the top of the file.

<Note>
  The JavaScript examples use `@seamapi/http` 2.35.0 or later. The native Ruby and
  PHP examples require `seam` 2.160.0 or later and `seamapi/seam` 4.15.0 or later,
  respectively. Python, C#, and Go use their SDK's request interface to support
  the new endpoint and response fields. Java uses a Java 11+ HTTP fallback
  because its released SDK does not expose this operation. The Seam CLI
  examples refresh its API schema with `--update`.
</Note>

Retrieve the device using [`/devices/get`](/docs/api/devices/get):

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  import { SeamHttp } from '@seamapi/http'

  const seam = new SeamHttp()
  const device = await seam.devices.get({
    device_id: '11111111-1111-1111-2222-444444444444',
  })

  if (device.can_activate_weekly_program !== true) {
    throw new Error('This thermostat cannot resume its native weekly program.')
  }
  ```

  ```bash cURL theme={"dark"}
  curl --request POST \
    --url 'https://connect.getseam.com/devices/get' \
    --header "Authorization: Bearer ${SEAM_API_KEY}" \
    --header 'Content-Type: application/json' \
    --data '{"device_id": "11111111-1111-1111-2222-444444444444"}'
  ```

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

  seam = Seam()
  # Use the SDK's request client to preserve the new capability field.
  device = seam.client.post(
      "/devices/get",
      json={"device_id": "11111111-1111-1111-2222-444444444444"},
  )["device"]

  if device.get("can_activate_weekly_program") is not True:
      raise ValueError("This thermostat cannot resume its native weekly program.")
  ```

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

  seam = Seam.new
  device = seam.devices.get(
    device_id: "11111111-1111-1111-2222-444444444444"
  )

  unless device.can_activate_weekly_program == true
    raise "This thermostat cannot resume its native weekly program."
  end
  ```

  ```php PHP theme={"dark"}
  require 'vendor/autoload.php';

  $seam = new Seam\Seam();
  $device = $seam->devices->get(
      device_id: "11111111-1111-1111-2222-444444444444"
  );

  if ($device->can_activate_weekly_program !== true) {
      throw new RuntimeException("This thermostat cannot resume its native weekly program.");
  }
  ```

  ```csharp C# theme={"dark"}
  using System;
  using Seam.Client;
  using Newtonsoft.Json.Linq;

  var seam = new SeamClient(Environment.GetEnvironmentVariable("SEAM_API_KEY"));
  var deviceResponse = await seam.PostAsync<JObject>(
      "/devices/get",
      new RequestOptions {
          Data = new { device_id = "11111111-1111-1111-2222-444444444444" }
      }
  );
  var device = deviceResponse.EnsureData("/devices/get")["device"]!;

  if ((bool?)device["can_activate_weekly_program"] != true) {
      throw new InvalidOperationException("This thermostat cannot resume its native weekly program.");
  }
  ```

  ```java Java theme={"dark"}
  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;
  import java.time.Duration;

  // Java 11+ HTTP fallback. Run these statements in a method that
  // declares throws IOException, InterruptedException (or catches them).
  HttpClient client = HttpClient.newBuilder()
      .connectTimeout(Duration.ofSeconds(30))
      .build();
  HttpRequest deviceRequest = HttpRequest.newBuilder()
      .uri(URI.create("https://connect.getseam.com/devices/get"))
      .timeout(Duration.ofSeconds(30))
      .header("Authorization", "Bearer " + System.getenv("SEAM_API_KEY"))
      .header("Content-Type", "application/json")
      .POST(HttpRequest.BodyPublishers.ofString(
          "{\"device_id\":\"11111111-1111-1111-2222-444444444444\"}"
      ))
      .build();
  HttpResponse<String> deviceResponse = client.send(
      deviceRequest, HttpResponse.BodyHandlers.ofString()
  );
  if (deviceResponse.statusCode() < 200 || deviceResponse.statusCode() >= 300) {
      throw new IllegalStateException(deviceResponse.body());
  }
  // Check device.can_activate_weekly_program in this JSON before continuing.
  System.out.println(deviceResponse.body());
  ```

  ```go Go theme={"dark"}
  import (
      "context"
      "fmt"
      "net/http"
      "os"
      "time"

      "github.com/seamapi/go/core"
  )

  caller := core.NewCaller(&core.CallerParams{
      Client: &http.Client{Timeout: 30 * time.Second},
      MaxAttempts: 1,
  })
  headers := http.Header{
      "Authorization": []string{"Bearer " + os.Getenv("SEAM_API_KEY")},
  }
  deviceID := "11111111-1111-1111-2222-444444444444"
  var deviceResponse map[string]interface{}
  err := caller.Call(context.Background(), &core.CallParams{
      URL: "https://connect.getseam.com/devices/get",
      Method: http.MethodPost,
      Headers: headers,
      Request: map[string]string{"device_id": deviceID},
      Response: &deviceResponse,
  })
  if err != nil {
      panic(err)
  }
  device := deviceResponse["device"].(map[string]interface{})
  if device["can_activate_weekly_program"] != true {
      panic("This thermostat cannot resume its native weekly program.")
  }
  ```

  ```bash Seam CLI theme={"dark"}
  SEAM_CLI_TOKEN="$SEAM_API_KEY" seam devices get \
    --device-id '11111111-1111-1111-2222-444444444444' \
    --non-interactive --json --update
  ```
</CodeGroup>

For cURL, Java, and Seam CLI, inspect the response and confirm that `device.can_activate_weekly_program` is `true` before continuing.

## Resume the Native Weekly Program

Call [`/thermostats/activate_weekly_program`](/docs/api/thermostats/activate_weekly_program) with the thermostat's `device_id`. No program ID, set points, or end time are required.

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  const actionAttempt = await seam.thermostats.activateWeeklyProgram(
    { device_id: device.device_id },
    { waitForActionAttempt: false },
  )
  ```

  ```bash cURL theme={"dark"}
  curl --request POST \
    --url 'https://connect.getseam.com/thermostats/activate_weekly_program' \
    --header "Authorization: Bearer ${SEAM_API_KEY}" \
    --header 'Content-Type: application/json' \
    --data '{"device_id": "11111111-1111-1111-2222-444444444444"}'
  ```

  ```python Python theme={"dark"}
  # Request fallback for SDK versions without the generated method.
  action_attempt = seam.client.post(
      "/thermostats/activate_weekly_program",
      json={"device_id": device["device_id"]},
  )["action_attempt"]
  ```

  ```ruby Ruby theme={"dark"}
  action_attempt = seam.thermostats.activate_weekly_program(
    device_id: device.device_id,
    wait_for_action_attempt: false
  )
  ```

  ```php PHP theme={"dark"}
  $actionAttempt = $seam->thermostats->activate_weekly_program(
      device_id: $device->device_id,
      wait_for_action_attempt: false
  );
  ```

  ```csharp C# theme={"dark"}
  // Use the SDK's request client until its generated method is available.
  var activationResponse = await seam.PostAsync<JObject>(
      "/thermostats/activate_weekly_program",
      new RequestOptions {
          Data = new { device_id = (string)device["device_id"]! }
      }
  );
  var actionAttempt = activationResponse.EnsureData(
      "/thermostats/activate_weekly_program"
  )["action_attempt"]!;
  ```

  ```java Java theme={"dark"}
  HttpRequest activationRequest = HttpRequest.newBuilder()
      .uri(URI.create("https://connect.getseam.com/thermostats/activate_weekly_program"))
      .timeout(Duration.ofSeconds(30))
      .header("Authorization", "Bearer " + System.getenv("SEAM_API_KEY"))
      .header("Content-Type", "application/json")
      .POST(HttpRequest.BodyPublishers.ofString(
          "{\"device_id\":\"11111111-1111-1111-2222-444444444444\"}"
      ))
      .build();
  HttpResponse<String> activationResponse = client.send(
      activationRequest, HttpResponse.BodyHandlers.ofString()
  );
  if (activationResponse.statusCode() < 200 || activationResponse.statusCode() >= 300) {
      throw new IllegalStateException(activationResponse.body());
  }
  System.out.println(activationResponse.body());
  ```

  ```go Go theme={"dark"}
  var activationResponse map[string]interface{}
  err = caller.Call(context.Background(), &core.CallParams{
      URL: "https://connect.getseam.com/thermostats/activate_weekly_program",
      Method: http.MethodPost,
      Headers: headers,
      Request: map[string]string{"device_id": deviceID},
      Response: &activationResponse,
  })
  if err != nil {
      panic(err)
  }
  actionAttempt := activationResponse["action_attempt"].(map[string]interface{})
  actionAttemptID := actionAttempt["action_attempt_id"].(string)
  fmt.Println(actionAttemptID)
  ```

  ```bash Seam CLI theme={"dark"}
  SEAM_CLI_TOKEN="$SEAM_API_KEY" seam thermostats activate-weekly-program \
    --device-id '11111111-1111-1111-2222-444444444444' \
    --non-interactive --json --update
  ```
</CodeGroup>

The HTTP response includes an [action attempt](/docs/core-concepts/action-attempts) with `action_type` set to `ACTIVATE_WEEKLY_PROGRAM`. The following example shows a pending response, with other response fields omitted:

```json theme={"dark"}
{
  "action_attempt": {
    "action_attempt_id": "22222222-2222-2222-3333-555555555555",
    "action_type": "ACTIVATE_WEEKLY_PROGRAM",
    "status": "pending",
    "result": null,
    "error": null
  }
}
```

## Confirm Completion

These examples return the action attempt without waiting for completion. An accepted HTTP request does not mean that the thermostat has finished resuming its schedule. Poll [`/action_attempts/get`](/docs/api/action_attempts/get) using the returned `action_attempt_id` until `status` is `success` or `error`. The following examples retrieve its current status once; repeat this check while it is `pending`. For cURL, Java, and Seam CLI, replace the sample action attempt ID with the ID returned by your activation request.

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  const latestActionAttempt = await seam.actionAttempts.get(
    { action_attempt_id: actionAttempt.action_attempt_id },
    { waitForActionAttempt: false },
  )
  console.log(latestActionAttempt.status)
  ```

  ```bash cURL theme={"dark"}
  curl --request POST \
    --url 'https://connect.getseam.com/action_attempts/get' \
    --header "Authorization: Bearer ${SEAM_API_KEY}" \
    --header 'Content-Type: application/json' \
    --data '{"action_attempt_id": "22222222-2222-2222-3333-555555555555"}'
  ```

  ```python Python theme={"dark"}
  latest_action_attempt = seam.client.post(
      "/action_attempts/get",
      json={"action_attempt_id": action_attempt["action_attempt_id"]},
  )["action_attempt"]
  print(latest_action_attempt["status"])
  ```

  ```ruby Ruby theme={"dark"}
  latest_action_attempt = seam.action_attempts.get(
    action_attempt_id: action_attempt.action_attempt_id,
    wait_for_action_attempt: false
  )
  puts latest_action_attempt.status
  ```

  ```php PHP theme={"dark"}
  $latestActionAttempt = $seam->action_attempts->get(
      action_attempt_id: $actionAttempt->action_attempt_id,
      wait_for_action_attempt: false
  );
  echo $latestActionAttempt->status;
  ```

  ```csharp C# theme={"dark"}
  var actionAttemptResponse = await seam.PostAsync<JObject>(
      "/action_attempts/get",
      new RequestOptions {
          Data = new { action_attempt_id = (string)actionAttempt["action_attempt_id"]! }
      }
  );
  var latestActionAttempt = actionAttemptResponse.EnsureData(
      "/action_attempts/get"
  )["action_attempt"]!;
  Console.WriteLine(latestActionAttempt["status"]);
  ```

  ```java Java theme={"dark"}
  // Replace the sample ID with action_attempt.action_attempt_id from the response.
  HttpRequest actionAttemptRequest = HttpRequest.newBuilder()
      .uri(URI.create("https://connect.getseam.com/action_attempts/get"))
      .timeout(Duration.ofSeconds(30))
      .header("Authorization", "Bearer " + System.getenv("SEAM_API_KEY"))
      .header("Content-Type", "application/json")
      .POST(HttpRequest.BodyPublishers.ofString(
          "{\"action_attempt_id\":\"22222222-2222-2222-3333-555555555555\"}"
      ))
      .build();
  HttpResponse<String> actionAttemptResponse = client.send(
      actionAttemptRequest, HttpResponse.BodyHandlers.ofString()
  );
  if (actionAttemptResponse.statusCode() < 200 || actionAttemptResponse.statusCode() >= 300) {
      throw new IllegalStateException(actionAttemptResponse.body());
  }
  System.out.println(actionAttemptResponse.body());
  ```

  ```go Go theme={"dark"}
  var actionResponse map[string]interface{}
  err = caller.Call(context.Background(), &core.CallParams{
      URL: "https://connect.getseam.com/action_attempts/get",
      Method: http.MethodPost,
      Headers: headers,
      Request: map[string]string{"action_attempt_id": actionAttemptID},
      Response: &actionResponse,
  })
  if err != nil {
      panic(err)
  }
  latestActionAttempt := actionResponse["action_attempt"].(map[string]interface{})
  fmt.Println(latestActionAttempt["status"])
  ```

  ```bash Seam CLI theme={"dark"}
  SEAM_CLI_TOKEN="$SEAM_API_KEY" seam action-attempts get \
    --action-attempt-id '22222222-2222-2222-3333-555555555555' \
    --non-interactive --json --update
  ```
</CodeGroup>

If the status is `error`, inspect the action attempt's `error` for details.

<Note>
  On ecobee thermostats, vacation events and mandatory demand-response events
  are not canceled by this operation.
</Note>

## What Happens After the Schedule Resumes?

Seam releases its hold and lets the thermostat follow its native weekly program. Seam does not change the HVAC mode as part of this operation. For example, resuming the program while the thermostat is off does not turn heating or cooling on.

The thermostat resumes the program currently stored on it. If you previously replaced that program using `/thermostats/update_weekly_program`, this operation does not restore the older program.

While the native program is active, Seam does not reapply a fallback preset or write climate settings when a previously active Seam schedule ends. Seam takes control again when any of the following occurs:

* You [activate a climate preset](/docs/capability-guides/thermostats/creating-and-managing-climate-presets/activating-a-climate-preset).
* You make a [direct HVAC setting change](/docs/capability-guides/thermostats/configure-current-climate-settings), such as calling `heat`, `cool`, `heat_cool`, `off`, or `set_hvac_mode`.
* A [scheduled climate preset](/docs/capability-guides/thermostats/creating-and-managing-thermostat-schedules) reaches its activation time.

Resuming the native program does not delete your Seam thermostat schedules. If you want the thermostat to keep following its own program, review upcoming Seam schedules and [delete any schedules](/docs/capability-guides/thermostats/creating-and-managing-thermostat-schedules#delete-a-thermostat-schedule) that should no longer activate.

For a temporary override workflow, apply the desired climate settings at the start of the event, then call `activate_weekly_program` when the event ends. Schedule that final API call in your application; this endpoint does not accept a future activation time.
