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

# Understanding Time Frame Options

> Learn about manufacturer- and device-specific limits on the time frame of an access code.

Some devices only accept access codes whose time frame—its duration and, sometimes, its time of day or calendar dates—falls within limits that the lock or its manufacturer enforces. When creating a time-bound access code, [get the device](/api/devices/get) and review two `device.properties` so that you can build a valid time frame **before** you call [`/access_codes/create`](/api/access_codes/create), rather than discovering the constraint from an error.

* `device.properties.offline_time_frame_options` applies to **offline** access codes.
* `device.properties.online_time_frame_options` applies to **online** access codes.

Each property is an **array of options**. An option is one self-contained way to make a code: a duration band plus any time-of-day and date rules that apply within it. To create a valid code, pick **one** option and satisfy **all** of its rules.

These properties are split by code type because you always know which kind of code you are creating, so you read the matching property directly. Splitting them also lets a provider express different limits per code type—for example, a device that allows a longer duration for online codes than for offline codes.

<Info>
  Read these options from the device at request time and build your time frame from the values you find—do not hardcode limits per manufacturer. Providers gain support and adjust their bounds over time, so a device's current `time_frame_options` are always the source of truth.
</Info>

<Info>
  When a property is `undefined`, any time frame works for that code type on that device—there are no time-frame limits to observe. A device may define one property and leave the other `undefined`. For example, a lock that only programs online codes exposes `online_time_frame_options` and leaves `offline_time_frame_options` unset. Standard online locks and thermostats leave both `undefined`.
</Info>

## The Time Frame Option Object

| Property                     | Type                       | Description                                                                                                                                                                                                                                               |
| ---------------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `display_name`               | string                     | Human-readable label. Always present. For a single-option device, typically the product name (for example, `algoPIN` or `SmartPIN`); for a multi-option device, a label that distinguishes the options (for example, `Hourly` or `Fixed check-in times`). |
| `min_duration`               | string (ISO 8601 duration) | Shortest duration this option covers, for example `PT1H` or `P29D`. Omitted when there is no minimum.                                                                                                                                                     |
| `max_duration`               | string (ISO 8601 duration) | Longest duration this option covers, for example `PT672H` or `P367D`. Omitted when there is no maximum.                                                                                                                                                   |
| `matching_start_end_time`    | `true`                     | When present, the check-in and check-out must be at the **same time of day** (you choose which). Mutually exclusive with `time_pairs`.                                                                                                                    |
| `time_pairs`                 | array                      | Fixed check-in/check-out pairings to choose from. See [The time pair object](#the-time-pair-object). Mutually exclusive with `matching_start_end_time`.                                                                                                   |
| `start_date_recurrence_rule` | string (RRULE)             | iCalendar recurrence rule that the **check-in date** must fall on, for example `FREQ=MONTHLY;BYDAY=1MO,3MO` for the first and third Monday of each month. Constrains which calendar dates are selectable, independent of the time-of-day rules.           |
| `end_date_recurrence_rule`   | string (RRULE)             | iCalendar recurrence rule that the **check-out date** must fall on.                                                                                                                                                                                       |
| `time_zone`                  | string (IANA time zone)    | Time zone used to interpret `time_pairs` and the date recurrence rules. Present only when the option fixes times or dates.                                                                                                                                |

Every property except `display_name` is optional, and the **absence of a rule means unrestricted on that axis**. An option with only `min_duration` and `max_duration` constrains duration and nothing else—any time of day, any date. An option with only `max_duration` means "any time frame up to that length."

<Info>
  `start_date_recurrence_rule` and `end_date_recurrence_rule` are part of the schema for forward compatibility, but no provider populates them yet. Today, every option either leaves the date axis unrestricted or fixes times of day through `time_pairs`.
</Info>

### The Time Pair Object

| Property       | Type                      | Description                                                                                                                     |
| -------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `display_name` | string                    | Label for the pairing, for example `Standard`, `Late arrival`, or `8 AM – 8 PM`.                                                |
| `start_time`   | string (`HH:MM`, 24-hour) | Start time of day (check-in), interpreted in the option's `time_zone`.                                                          |
| `end_time`     | string (`HH:MM`, 24-hour) | End time of day (check-out). An `end_time` earlier on the clock than `start_time` means that the end falls on a **later date**. |

A time pair is atomic: you pick one whole pairing, and you cannot mix a `start_time` from one pair with an `end_time` from another.

## Choosing an Option

1. **Filter by duration.** Compute your requested duration and keep the options whose `[min_duration, max_duration]` band contains it.
2. **Disambiguate.** How you land on a single option depends on whether the options' duration ranges overlap:
   * **Non-overlapping ranges (the common case):** The requested duration falls into exactly one option, so the duration alone selects it. You just enter dates.
   * **Overlapping ranges:** Duration cannot disambiguate, so the options are genuine alternatives that you choose between by `display_name`.
3. **Satisfy that option's rules.** Honor its time-of-day rule (`matching_start_end_time` or one `time_pairs` entry) and any `start_date_recurrence_rule` or `end_date_recurrence_rule`, interpreting times and dates in `time_zone`.

You do not need a flag to tell these cases apart—it falls out of the ranges. If two options can both accept the requested duration, present them as a choice; otherwise, route by duration.

<Warning>
  When `start_date_recurrence_rule` or `end_date_recurrence_rule` is present, `max_duration` caps the range, but the only valid dates are recurrence dates within that cap. Offer only recurrence dates within the duration bound, not every date up to the cap.
</Warning>

## Examples

### Duration-Only Option

For example, an igloohome `algoPIN` hourly code accepts any time of day, from one hour to 28 days:

```json theme={null}
{ "display_name": "Hourly", "min_duration": "PT1H", "max_duration": "PT672H" }
```

### Matching Start and End Time

For example, an igloohome `algoPIN` daily code covers 29 to 367 days, and the check-in and check-out must be at the same time of day:

```json theme={null}
{
  "display_name": "Daily",
  "min_duration": "P29D",
  "max_duration": "P367D",
  "matching_start_end_time": true
}
```

### Fixed Time Pairs

For example, a Dormakaba Oracode offline code offers the fixed check-in/check-out pairings defined for the door, up to 31 days, in the lock's local time zone:

```json theme={null}
{
  "display_name": "Fixed check-in times",
  "max_duration": "P31D",
  "time_zone": "America/Los_Angeles",
  "time_pairs": [
    { "display_name": "Standard", "start_time": "15:00", "end_time": "11:00" },
    { "display_name": "Late arrival", "start_time": "16:00", "end_time": "10:00" }
  ]
}
```

### Multiple Options on One Property

For example, an igloohome `algoPIN` device exposes two duration-matched offline options. The ranges don't overlap, so Seam selects the option by the requested duration—you never pick. Its online (bridge) codes are unconstrained, so `online_time_frame_options` is `undefined`.

```json theme={null}
"offline_time_frame_options": [
  { "display_name": "Hourly", "min_duration": "PT1H", "max_duration": "PT672H" },
  {
    "display_name": "Daily",
    "min_duration": "P29D",
    "max_duration": "P367D",
    "matching_start_end_time": true
  }
]
```

As another example, a KeyInCode `SmartPIN` device programs online codes only and exposes two duration-matched online options: short-term codes are unrestricted on time of day, while long-term codes are fixed to an 8 AM check-in and 8 PM check-out in the lock's location time zone. Its `offline_time_frame_options` is `undefined`.

```json theme={null}
"online_time_frame_options": [
  { "display_name": "Short-term", "max_duration": "P32D" },
  {
    "display_name": "Long-term",
    "min_duration": "P33D",
    "max_duration": "P365D",
    "time_zone": "America/Los_Angeles",
    "time_pairs": [
      { "display_name": "8 AM – 8 PM", "start_time": "08:00", "end_time": "20:00" }
    ]
  }
]
```

## Related Resources

* [Understanding Code Constraints](/low-level-apis/smart-locks/access-codes/creating-access-codes/understanding-code-constraints)
* [Creating Access Codes](/low-level-apis/smart-locks/access-codes/creating-access-codes/index)
* [API Reference: `device` Properties](/api/devices)
