> For the complete documentation index, see [llms.txt](https://docs.butlr.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.butlr.io/historical-occupancy/reporting-api-overview/query-limits.md).

# Query Limits

On **August 3, 2026**, the Reporting API moved to a new tiered storage backend. The endpoint and request/response formats are unchanged, but queries are now validated against the limits below. A request outside these limits returns a `400` error describing what to change (previously, oversized queries often failed with an unexplained `500`).

{% hint style="success" %}
**Rule of thumb:** `1h` and `1d` intervals work for any time range, at any data age. When in doubt, use those.
{% endhint %}

### Supported intervals

`window.every` must be one of: `1m`, `5m`, `15m`, `30m`, `1h`, `1d`. Other values (e.g. `10m`, `2h`) are rejected.

### Maximum time range per interval

| Interval    | Maximum range (`stop` − `start`) |
| ----------- | -------------------------------- |
| `1m`        | 3 days                           |
| `5m`        | 14 days                          |
| `15m` `30m` | 90 days                          |
| `1h`        | 180 days                         |
| `1d`        | unlimited                        |

For longer periods, use a coarser interval or split the period into multiple queries.

### Interval availability by data age

Data is stored in tiers by age. The tier is selected by the **start** of the queried range:

| Query range starts       | Available intervals   |
| ------------------------ | --------------------- |
| Within the last 3 months | all                   |
| 3–6 months ago           | `15m` `30m` `1h` `1d` |
| More than 6 months ago   | `1h` `1d`             |

### Other changes

* `window.offset` is no longer supported.
* `filter.time_constraints.time_ranges` is evaluated at hour precision (minutes are ignored). Combined with `1d` windows, the range is limited to 1 year.
* `tag_occupancy` requires a `tags` filter and supports only the `max` and `mean` functions; `mean` requires an interval of `15m` or coarser.
* All filters are supported: spatial IDs (`rooms`, `zones`, `spaces`, `buildings`), name-based filters (`room_names`, `building_names`), and sensor/hive filters (`sensors`, `mac_addresses`, `hives`, `hive_serials`). Prefer spatial ID filters where possible — they narrow the query itself, while name and sensor/hive filters are applied to the results.
* Intervals with no data are omitted from the response. To return them, set `"window": { "fill": { "value": 0 } }` — they come back filled with the given value (add `"use_previous": true` to carry the last value forward instead). `create_empty` on its own has no effect. Fill applies once the query returns at least one data point for the series; a range with no data at all returns an empty response.
