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

# Configuring Ultraloq Device Timezones

> Configure device timezones for Ultraloq locks to enable time-bound access codes

Ultraloq devices require timezone configuration before you can create time-bound access codes. This guide explains why this is necessary and how to configure timezones for your Ultraloq devices.

***

## Why Timezone Configuration is Required

Ultraloq devices have a unique characteristic that requires manual timezone configuration:

**The Problem:**

* Ultraloq devices schedule access codes using **device-local time** (e.g., "2024-01-15 14:30")
* The Ultraloq API returns timestamps **without timezone information**
* Without knowing the device's timezone, Seam cannot correctly convert UTC timestamps to device-local time

**The Solution:**

* You must manually configure each device's timezone using the `/devices/report_provider_metadata` API
* This tells Seam what timezone the device is in so it can correctly schedule time-bound access codes

<Info>
  This is a **one-time configuration** per device. Once set, the timezone
  persists until you change it.
</Info>

***

## What Works Without Timezone

You can use the following features **without** configuring the device's timezone:

* ✅ **Permanent access codes** — Codes without `starts_at` and `ends_at` work immediately
* ✅ **Lock and unlock operations** — Remote lock/unlock commands work immediately
* ✅ **Device monitoring** — Battery level, lock status, and online/offline state

***

## What Requires Timezone

The following feature **requires** timezone configuration:

* ❌ **Time-bound access codes** — Codes with `starts_at` and `ends_at` require timezone

If you attempt to create a time-bound access code without configuring the timezone, you'll receive a validation error:

```json theme={null}
{
  "error": {
    "type": "invalid_input",
    "message": "Time zone required for time-bound access codes on Ultraloq devices"
  }
}
```

***

## Detecting Unconfigured Devices

When you first connect an Ultraloq device, it will have the `ultraloq_time_zone_unknown` warning:

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

  const seam = new Seam()

  const device = await seam.devices.get({
    device_id: 'your-device-id',
  })

  // Check for timezone warning
  const hasTimezoneWarning = device.warnings.some(
    (w) => w.warning_code === 'ultraloq_time_zone_unknown',
  )

  if (hasTimezoneWarning) {
    console.log('⚠️ Timezone not configured')
    console.log('Configure timezone before creating time-bound access codes')
  }

  // Check timezone value
  const timezone = device.properties.ultraloq_metadata?.time_zone
  console.log(`Current timezone: ${timezone}`) // Will be null if not configured
  ```

  ```bash cURL theme={null}
  device=$(curl -X 'POST' \
    'https://connect.getseam.com/devices/get' \
    -H 'accept: application/json' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d "{
      \"device_id\": \"your-device-id\"
    }")

  # Check for timezone warning
  echo $device | jq '.device.warnings[] | select(.warning_code == "ultraloq_time_zone_unknown")'

  # Check timezone value
  echo $device | jq '.device.properties.ultraloq_metadata.time_zone'
  ```

  ```python Python theme={null}
  from seam import Seam

  seam = Seam()

  device = seam.devices.get(device_id="your-device-id")

  # Check for timezone warning
  has_timezone_warning = any(
    w.warning_code == "ultraloq_time_zone_unknown"
    for w in device.warnings
  )

  if has_timezone_warning:
    print("⚠️ Timezone not configured")
    print("Configure timezone before creating time-bound access codes")

  # Check timezone value
  timezone = device.properties.get("ultraloq_metadata", {}).get("time_zone")
  print(f"Current timezone: {timezone}")  # Will be None if not configured
  ```

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

  seam = Seam.new()

  device = seam.devices.get(device_id: "your-device-id")

  # Check for timezone warning
  has_timezone_warning = device.warnings.any? do |w|
    w.warning_code == "ultraloq_time_zone_unknown"
  end

  if has_timezone_warning
    puts "⚠️ Timezone not configured"
    puts "Configure timezone before creating time-bound access codes"
  end

  # Check timezone value
  timezone = device.properties.dig("ultraloq_metadata", "time_zone")
  puts "Current timezone: #{timezone}"  # Will be nil if not configured
  ```

  ```php PHP theme={null}
  <?php
  require 'vendor/autoload.php';

  use Seam\SeamClient;

  $seam = new SeamClient();

  $device = $seam->devices->get(device_id: "your-device-id");

  // Check for timezone warning
  $hasTimezoneWarning = false;
  foreach ($device->warnings as $warning) {
    if ($warning->warning_code === "ultraloq_time_zone_unknown") {
      $hasTimezoneWarning = true;
      break;
    }
  }

  if ($hasTimezoneWarning) {
    echo "⚠️ Timezone not configured\n";
    echo "Configure timezone before creating time-bound access codes\n";
  }

  // Check timezone value
  $timezone = $device->properties->ultraloq_metadata->time_zone ?? null;
  echo "Current timezone: " . ($timezone ?? "not set") . "\n";
  ```

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

  var seam = new SeamClient();

  var device = seam.Devices.Get(deviceId: "your-device-id");

  // Check for timezone warning
  var hasTimezoneWarning = device.Warnings.Any(
    w => w.WarningCode == "ultraloq_time_zone_unknown"
  );

  if (hasTimezoneWarning)
  {
    Console.WriteLine("⚠️ Timezone not configured");
    Console.WriteLine("Configure timezone before creating time-bound access codes");
  }

  // Check timezone value
  var timezone = device.Properties.UltraloqMetadata?.TimeZone;
  Console.WriteLine($"Current timezone: {timezone ?? "not set"}");
  ```

  ```java Java theme={null}
  import com.seam.api.Seam;
  import com.seam.api.types.Device;

  Seam seam = Seam.builder().build();

  Device device = seam.devices().get(
    DevicesGetRequest.builder()
      .deviceId("your-device-id")
      .build()
  );

  // Check for timezone warning
  boolean hasTimezoneWarning = device.getWarnings().stream()
    .anyMatch(w -> w.getWarningCode().equals("ultraloq_time_zone_unknown"));

  if (hasTimezoneWarning) {
    System.out.println("⚠️ Timezone not configured");
    System.out.println("Configure timezone before creating time-bound access codes");
  }

  // Check timezone value
  String timezone = device.getProperties().getUltraloqMetadata().getTimeZone();
  System.out.println("Current timezone: " + (timezone != null ? timezone : "not set"));
  ```
</CodeGroup>

***

## Configuring Timezones

### Single Device

To configure the timezone for a single device, use the `/devices/report_provider_metadata` endpoint:

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

  const seam = new Seam()

  // Configure timezone for one device
  await seam.devices.reportProviderMetadata({
    devices: [
      {
        device_id: 'your-device-id',
        ultraloq_metadata: {
          time_zone: 'America/New_York',
        },
      },
    ],
  })

  console.log('✓ Timezone configured successfully!')
  ```

  ```bash cURL theme={null}
  curl -X 'POST' \
    'https://connect.getseam.com/devices/report_provider_metadata' \
    -H 'accept: application/json' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d '{
      "devices": [
        {
          "device_id": "your-device-id",
          "ultraloq_metadata": {
            "time_zone": "America/New_York"
          }
        }
      ]
    }'
  ```

  ```python Python theme={null}
  from seam import Seam

  seam = Seam()

  # Configure timezone for one device
  seam.devices.report_provider_metadata(
    devices=[
      {
        "device_id": "your-device-id",
        "ultraloq_metadata": {
          "time_zone": "America/New_York"
        }
      }
    ]
  )

  print("✓ Timezone configured successfully!")
  ```

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

  seam = Seam.new()

  # Configure timezone for one device
  seam.devices.report_provider_metadata(
    devices: [
      {
        device_id: "your-device-id",
        ultraloq_metadata: {
          time_zone: "America/New_York"
        }
      }
    ]
  )

  puts "✓ Timezone configured successfully!"
  ```

  ```php PHP theme={null}
  <?php
  require 'vendor/autoload.php';

  use Seam\SeamClient;

  $seam = new SeamClient();

  // Configure timezone for one device
  $seam->devices->report_provider_metadata(
    devices: [
      [
        "device_id" => "your-device-id",
        "ultraloq_metadata" => [
          "time_zone" => "America/New_York"
        ]
      ]
    ]
  );

  echo "✓ Timezone configured successfully!";
  ```

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

  var seam = new SeamClient();

  // Configure timezone for one device
  seam.Devices.ReportProviderMetadata(
    devices: new[] {
      new DeviceMetadata {
        DeviceId = "your-device-id",
        UltraloqMetadata = new UltraloqMetadata {
          TimeZone = "America/New_York"
        }
      }
    }
  );

  Console.WriteLine("✓ Timezone configured successfully!");
  ```

  ```java Java theme={null}
  import com.seam.api.Seam;

  Seam seam = Seam.builder().build();

  // Configure timezone for one device
  seam.devices().reportProviderMetadata(
    DevicesReportProviderMetadataRequest.builder()
      .devices(List.of(
        DeviceMetadata.builder()
          .deviceId("your-device-id")
          .ultraloqMetadata(UltraloqMetadata.builder()
            .timeZone("America/New_York")
            .build())
          .build()
      ))
      .build()
  );

  System.out.println("✓ Timezone configured successfully!");
  ```
</CodeGroup>

### Multiple Devices (Batch Configuration)

You can configure timezones for multiple devices in a single API call:

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

  const seam = new Seam()

  // Get all Ultraloq devices
  const devices = await seam.devices.list({
    device_type: 'ultraloq_lock',
  })

  // Configure timezone for all devices
  await seam.devices.reportProviderMetadata({
    devices: devices.map((device) => ({
      device_id: device.device_id,
      ultraloq_metadata: {
        time_zone: 'America/Los_Angeles', // Or get from user
      },
    })),
  })

  console.log(`✓ Configured timezone for ${devices.length} devices`)
  ```

  ```bash cURL theme={null}
  # Get all Ultraloq devices
  devices=$(curl -X 'POST' \
    'https://connect.getseam.com/devices/list' \
    -H 'accept: application/json' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d '{
      "device_type": "ultraloq_lock"
    }')

  # Configure timezone for all devices
  # (Requires jq to construct the request)
  curl -X 'POST' \
    'https://connect.getseam.com/devices/report_provider_metadata' \
    -H 'accept: application/json' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d "$(echo $devices | jq '{
      devices: [.devices[] | {
        device_id: .device_id,
        ultraloq_metadata: {
          time_zone: "America/Los_Angeles"
        }
      }]
    }')"
  ```

  ```python Python theme={null}
  from seam import Seam

  seam = Seam()

  # Get all Ultraloq devices
  devices = seam.devices.list(device_type="ultraloq_lock")

  # Configure timezone for all devices
  seam.devices.report_provider_metadata(
    devices=[
      {
        "device_id": device.device_id,
        "ultraloq_metadata": {
          "time_zone": "America/Los_Angeles"  # Or get from user
        }
      }
      for device in devices
    ]
  )

  print(f"✓ Configured timezone for {len(devices)} devices")
  ```

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

  seam = Seam.new()

  # Get all Ultraloq devices
  devices = seam.devices.list(device_type: "ultraloq_lock")

  # Configure timezone for all devices
  seam.devices.report_provider_metadata(
    devices: devices.map do |device|
      {
        device_id: device.device_id,
        ultraloq_metadata: {
          time_zone: "America/Los_Angeles"  # Or get from user
        }
      }
    end
  )

  puts "✓ Configured timezone for #{devices.length} devices"
  ```

  ```php PHP theme={null}
  <?php
  require 'vendor/autoload.php';

  use Seam\SeamClient;

  $seam = new SeamClient();

  // Get all Ultraloq devices
  $devices = $seam->devices->list(device_type: "ultraloq_lock");

  // Configure timezone for all devices
  $deviceMetadata = array_map(function($device) {
    return [
      "device_id" => $device->device_id,
      "ultraloq_metadata" => [
        "time_zone" => "America/Los_Angeles"  // Or get from user
      ]
    ];
  }, $devices);

  $seam->devices->report_provider_metadata(devices: $deviceMetadata);

  echo "✓ Configured timezone for " . count($devices) . " devices";
  ```

  ```csharp C# theme={null}
  using Seam.Client;
  using System.Linq;

  var seam = new SeamClient();

  // Get all Ultraloq devices
  var devices = seam.Devices.List(deviceType: "ultraloq_lock");

  // Configure timezone for all devices
  seam.Devices.ReportProviderMetadata(
    devices: devices.Select(device => new DeviceMetadata {
      DeviceId = device.DeviceId,
      UltraloqMetadata = new UltraloqMetadata {
        TimeZone = "America/Los_Angeles"  // Or get from user
      }
    }).ToArray()
  );

  Console.WriteLine($"✓ Configured timezone for {devices.Count()} devices");
  ```

  ```java Java theme={null}
  import com.seam.api.Seam;
  import com.seam.api.types.Device;
  import java.util.stream.Collectors;

  Seam seam = Seam.builder().build();

  // Get all Ultraloq devices
  List<Device> devices = seam.devices().list(
    DevicesListRequest.builder()
      .deviceType("ultraloq_lock")
      .build()
  );

  // Configure timezone for all devices
  seam.devices().reportProviderMetadata(
    DevicesReportProviderMetadataRequest.builder()
      .devices(devices.stream()
        .map(device -> DeviceMetadata.builder()
          .deviceId(device.getDeviceId())
          .ultraloqMetadata(UltraloqMetadata.builder()
            .timeZone("America/Los_Angeles")  // Or get from user
            .build())
          .build())
        .collect(Collectors.toList()))
      .build()
  );

  System.out.println("✓ Configured timezone for " + devices.size() + " devices");
  ```
</CodeGroup>

***

## Valid Timezone Values

You must use **IANA timezone strings** (also called "tz database" timezones). These are standardized timezone identifiers in the format `Continent/City`.

### Examples of Valid Timezones

* `"America/New_York"` — Eastern Time (US)
* `"America/Chicago"` — Central Time (US)
* `"America/Denver"` — Mountain Time (US)
* `"America/Los_Angeles"` — Pacific Time (US)
* `"America/Phoenix"` — Arizona (no DST)
* `"America/Toronto"` — Eastern Time (Canada)
* `"Europe/London"` — UK
* `"Europe/Paris"` — Central European Time
* `"Asia/Tokyo"` — Japan
* `"Australia/Sydney"` — Australian Eastern Time

<Warning>
  **Do not use timezone abbreviations** like `"EST"`, `"PST"`, or `"GMT-5"`.
  These are ambiguous and will cause validation errors. Always use the full IANA
  timezone string.
</Warning>

### Finding the Right Timezone

For a complete list of valid IANA timezones, see:

* [IANA Time Zone Database (Wikipedia)](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)
* [IANA Official Database](https://www.iana.org/time-zones)

Most programming languages also provide timezone lookup utilities:

<CodeGroup>
  ```javascript JavaScript theme={null}
  // Using Intl API (built-in)
  const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone
  console.log(`User's timezone: ${userTimezone}`)
  // Example: "America/Los_Angeles"

  // Or using moment-timezone library
  const moment = require('moment-timezone')
  const allTimezones = moment.tz.names()
  console.log(`Available timezones: ${allTimezones.length}`)
  ```

  ```python Python theme={null}
  import pytz

  # List all available timezones
  all_timezones = pytz.all_timezones
  print(f"Available timezones: {len(all_timezones)}")

  # Search for timezones containing "New"
  ny_timezones = [tz for tz in all_timezones if "New" in tz]
  print(ny_timezones)
  # ['America/New_York', 'America/North_Dakota/New_Salem', ...]
  ```

  ```ruby Ruby theme={null}
  require 'tzinfo'

  # List all available timezones
  all_timezones = TZInfo::Timezone.all_identifiers
  puts "Available timezones: #{all_timezones.length}"

  # Search for timezones containing "New"
  ny_timezones = all_timezones.select { |tz| tz.include?("New") }
  puts ny_timezones
  # ["America/New_York", "America/North_Dakota/New_Salem", ...]
  ```
</CodeGroup>

***

## Verification

After configuring the timezone, verify that the configuration was successful:

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

  const seam = new Seam()

  const device = await seam.devices.get({
    device_id: 'your-device-id',
  })

  // Verify timezone is set
  const timezone = device.properties.ultraloq_metadata.time_zone
  console.log(`Device timezone: ${timezone}`)

  // Verify warning is cleared
  const hasWarning = device.warnings.some(
    (w) => w.warning_code === 'ultraloq_time_zone_unknown',
  )

  if (!hasWarning) {
    console.log('✓ Timezone configured successfully!')
    console.log('✓ Device is ready to create time-bound access codes')
  } else {
    console.log('✗ Warning still present - check timezone configuration')
  }
  ```

  ```bash cURL theme={null}
  device=$(curl -X 'POST' \
    'https://connect.getseam.com/devices/get' \
    -H 'accept: application/json' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d "{
      \"device_id\": \"your-device-id\"
    }")

  # Check timezone
  echo $device | jq -r '.device.properties.ultraloq_metadata.time_zone'

  # Check warnings
  echo $device | jq '.device.warnings[] | select(.warning_code == "ultraloq_time_zone_unknown")'
  ```

  ```python Python theme={null}
  from seam import Seam

  seam = Seam()

  device = seam.devices.get(device_id="your-device-id")

  # Verify timezone is set
  timezone = device.properties["ultraloq_metadata"]["time_zone"]
  print(f"Device timezone: {timezone}")

  # Verify warning is cleared
  has_warning = any(
    w.warning_code == "ultraloq_time_zone_unknown"
    for w in device.warnings
  )

  if not has_warning:
    print("✓ Timezone configured successfully!")
    print("✓ Device is ready to create time-bound access codes")
  else:
    print("✗ Warning still present - check timezone configuration")
  ```

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

  seam = Seam.new()

  device = seam.devices.get(device_id: "your-device-id")

  # Verify timezone is set
  timezone = device.properties["ultraloq_metadata"]["time_zone"]
  puts "Device timezone: #{timezone}"

  # Verify warning is cleared
  has_warning = device.warnings.any? { |w| w.warning_code == "ultraloq_time_zone_unknown" }

  if !has_warning
    puts "✓ Timezone configured successfully!"
    puts "✓ Device is ready to create time-bound access codes"
  else
    puts "✗ Warning still present - check timezone configuration"
  end
  ```

  ```php PHP theme={null}
  <?php
  require 'vendor/autoload.php';

  use Seam\SeamClient;

  $seam = new SeamClient();

  $device = $seam->devices->get(device_id: "your-device-id");

  // Verify timezone is set
  $timezone = $device->properties->ultraloq_metadata->time_zone;
  echo "Device timezone: $timezone\n";

  // Verify warning is cleared
  $hasWarning = false;
  foreach ($device->warnings as $warning) {
    if ($warning->warning_code === "ultraloq_time_zone_unknown") {
      $hasWarning = true;
      break;
    }
  }

  if (!$hasWarning) {
    echo "✓ Timezone configured successfully!\n";
    echo "✓ Device is ready to create time-bound access codes\n";
  } else {
    echo "✗ Warning still present - check timezone configuration\n";
  }
  ```

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

  var seam = new SeamClient();

  var device = seam.Devices.Get(deviceId: "your-device-id");

  // Verify timezone is set
  var timezone = device.Properties.UltraloqMetadata.TimeZone;
  Console.WriteLine($"Device timezone: {timezone}");

  // Verify warning is cleared
  var hasWarning = device.Warnings.Any(
    w => w.WarningCode == "ultraloq_time_zone_unknown"
  );

  if (!hasWarning)
  {
    Console.WriteLine("✓ Timezone configured successfully!");
    Console.WriteLine("✓ Device is ready to create time-bound access codes");
  }
  else
  {
    Console.WriteLine("✗ Warning still present - check timezone configuration");
  }
  ```

  ```java Java theme={null}
  import com.seam.api.Seam;
  import com.seam.api.types.Device;

  Seam seam = Seam.builder().build();

  Device device = seam.devices().get(
    DevicesGetRequest.builder()
      .deviceId("your-device-id")
      .build()
  );

  // Verify timezone is set
  String timezone = device.getProperties().getUltraloqMetadata().getTimeZone();
  System.out.println("Device timezone: " + timezone);

  // Verify warning is cleared
  boolean hasWarning = device.getWarnings().stream()
    .anyMatch(w -> w.getWarningCode().equals("ultraloq_time_zone_unknown"));

  if (!hasWarning) {
    System.out.println("✓ Timezone configured successfully!");
    System.out.println("✓ Device is ready to create time-bound access codes");
  } else {
    System.out.println("✗ Warning still present - check timezone configuration");
  }
  ```
</CodeGroup>

After configuration, the device will also have the timezone in `device.location.timezone`:

```json theme={null}
{
  "device_id": "...",
  "properties": {
    "ultraloq_metadata": {
      "time_zone": "America/New_York"
    }
  },
  "location": {
    "timezone": "America/New_York"
  },
  "warnings": []
}
```

***

## Changing Timezones

You can change a device's timezone at any time by calling `/devices/report_provider_metadata` again with the new timezone.

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

  const seam = new Seam()

  // User moved device from New York to Los Angeles
  await seam.devices.reportProviderMetadata({
    devices: [
      {
        device_id: 'your-device-id',
        ultraloq_metadata: {
          time_zone: 'America/Los_Angeles', // Changed from America/New_York
        },
      },
    ],
  })

  console.log('✓ Timezone updated to Pacific Time')
  ```

  ```bash cURL theme={null}
  curl -X 'POST' \
    'https://connect.getseam.com/devices/report_provider_metadata' \
    -H 'accept: application/json' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d '{
      "devices": [
        {
          "device_id": "your-device-id",
          "ultraloq_metadata": {
            "time_zone": "America/Los_Angeles"
          }
        }
      ]
    }'
  ```

  ```python Python theme={null}
  from seam import Seam

  seam = Seam()

  # User moved device from New York to Los Angeles
  seam.devices.report_provider_metadata(
    devices=[
      {
        "device_id": "your-device-id",
        "ultraloq_metadata": {
          "time_zone": "America/Los_Angeles"  # Changed from America/New_York
        }
      }
    ]
  )

  print("✓ Timezone updated to Pacific Time")
  ```

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

  seam = Seam.new()

  # User moved device from New York to Los Angeles
  seam.devices.report_provider_metadata(
    devices: [
      {
        device_id: "your-device-id",
        ultraloq_metadata: {
          time_zone: "America/Los_Angeles"  # Changed from America/New_York
        }
      }
    ]
  )

  puts "✓ Timezone updated to Pacific Time"
  ```

  ```php PHP theme={null}
  <?php
  require 'vendor/autoload.php';

  use Seam\SeamClient;

  $seam = new SeamClient();

  // User moved device from New York to Los Angeles
  $seam->devices->report_provider_metadata(
    devices: [
      [
        "device_id" => "your-device-id",
        "ultraloq_metadata" => [
          "time_zone" => "America/Los_Angeles"  // Changed from America/New_York
        ]
      ]
    ]
  );

  echo "✓ Timezone updated to Pacific Time";
  ```

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

  var seam = new SeamClient();

  // User moved device from New York to Los Angeles
  seam.Devices.ReportProviderMetadata(
    devices: new[] {
      new DeviceMetadata {
        DeviceId = "your-device-id",
        UltraloqMetadata = new UltraloqMetadata {
          TimeZone = "America/Los_Angeles"  // Changed from America/New_York
        }
      }
    }
  );

  Console.WriteLine("✓ Timezone updated to Pacific Time");
  ```

  ```java Java theme={null}
  import com.seam.api.Seam;

  Seam seam = Seam.builder().build();

  // User moved device from New York to Los Angeles
  seam.devices().reportProviderMetadata(
    DevicesReportProviderMetadataRequest.builder()
      .devices(List.of(
        DeviceMetadata.builder()
          .deviceId("your-device-id")
          .ultraloqMetadata(UltraloqMetadata.builder()
            .timeZone("America/Los_Angeles")  // Changed from America/New_York
            .build())
          .build()
      ))
      .build()
  );

  System.out.println("✓ Timezone updated to Pacific Time");
  ```
</CodeGroup>

**Impact on Existing Access Codes:**

* Existing time-bound access codes maintain their **UTC timestamps**
* They continue working correctly because Seam stores them in UTC internally
* Future access codes will use the new timezone for scheduling

***

## Best Practices

### 1. Set Timezone Immediately After Connection

Configure the timezone as soon as you connect an Ultraloq device, before users try to create time-bound access codes:

```python theme={null}
# Good practice: Configure timezone right after connection
devices = seam.devices.list(connected_account_id=account_id)

seam.devices.report_provider_metadata(
  devices=[
    {
      "device_id": device.device_id,
      "ultraloq_metadata": {"time_zone": user_timezone}
    }
    for device in devices
  ]
)
```

### 2. Check Warnings Before Creating Time-Bound Codes

Always check for the `ultraloq_time_zone_unknown` warning before creating time-bound access codes:

```python theme={null}
def can_create_time_bound_codes(device):
  return not any(
    w.warning_code == "ultraloq_time_zone_unknown"
    for w in device.warnings
  )

if can_create_time_bound_codes(device):
  # Safe to create time-bound codes
  seam.access_codes.create(
    device_id=device.device_id,
    starts_at="...",
    ends_at="..."
  )
else:
  # Prompt user to configure timezone
  print("Configure device timezone before creating time-bound codes")
```

### 3. Use device.location.timezone for Reference

After configuration, you can reference the configured timezone from `device.location.timezone`:

```python theme={null}
device = seam.devices.get(device_id="...")

if device.location and device.location.timezone:
  print(f"Device is in {device.location.timezone}")
  # Use this timezone for display or calculations
```

### 4. Provide Clear UI Guidance

In your application UI, guide users to select the correct timezone:

```
┌─────────────────────────────────────────────┐
│ ⚠️  Action Required: Set Device Timezone    │
│                                             │
│ Your Ultraloq device needs a timezone to   │
│ support scheduled access codes.             │
│                                             │
│ Device: Front Door Lock                     │
│                                             │
│ Select timezone: [America/New_York     ▼]  │
│                                             │
│ [ Configure Timezone ]                      │
└─────────────────────────────────────────────┘
```

***

## Troubleshooting

### Invalid Timezone Error

**Problem:** You receive an error like `"Invalid timezone. Must be a valid IANA timezone string."`

**Solution:**

* Verify you're using a valid IANA timezone (e.g., `"America/New_York"`, not `"EST"`)
* Check for typos in the timezone string
* Refer to the [IANA timezone list](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)

### Warning Not Cleared After Configuration

**Problem:** The `ultraloq_time_zone_unknown` warning persists after calling `report_provider_metadata`.

**Solution:**

* Verify the API call succeeded (check for errors in the response)
* Refresh the device by calling `seam.devices.get()` again
* Ensure you used the correct `device_id`
* Wait a few seconds and check again (state updates are usually immediate but may take a moment)

### Time-Bound Codes Still Failing

**Problem:** Time-bound access codes still fail to create after configuring timezone.

**Solution:**

* Verify `device.properties.ultraloq_metadata.time_zone` is not `null`
* Check that `device.warnings` does not contain `ultraloq_time_zone_unknown`
* Ensure you're providing both `starts_at` and `ends_at` in your access code request
* Verify your timestamps are valid ISO 8601 UTC strings

***

## API Reference

For complete API documentation, see:

* [POST /devices/report\_provider\_metadata](/api/devices/report_provider_metadata)

***

## Next Steps

Now that you understand timezone configuration, you can:

* **Create time-bound access codes:** See [Creating Ultraloq Access Codes](./creating-ultraloq-access-codes)
* **Review the setup guide:** See [Ultraloq Setup Guide](./ultraloq-setup-guide)
* **Learn about access code constraints:** See [Understanding Code Constraints](/low-level-apis/smart-locks/access-codes/creating-access-codes/understanding-code-constraints)

***
