---
title: "Get a project's channel-hours by state per calendar period"
method: GET
path: "/projects/{project_id}/lab/utilization-history"
tags: ["Lab"]
---

# Get a project's channel-hours by state per calendar period

`GET /projects/{project_id}/lab/utilization-history`

## Request

- Base URL: `https://api.ionworks.com`
- URL: `https://api.ionworks.com/projects/{project_id}/lab/utilization-history`
- Auth: none declared

Return channel-hours by state for each calendar period from start to now.

Each point splits the period's channel-hours into occupied, stale, free, and
out of service, with the Lab wall's precedence, so it describes the whole
period rather than one instant. The last point is the period in progress,
computed up to now and flagged ``partial``. At most 400 points.

## Path parameters

- `project_id` string, uuid, required

## Query parameters

- `start` string, date-time, required: Start of the range, ISO 8601 (a date is read as UTC midnight). Snapped back to its period's boundary; at most 3660 days ago.
- `granularity` 'day' | 'week' | 'month' | 'quarter' | 'year': The calendar period each history point covers, in UTC.

## Response `200`

Successful Response

- UtilizationHistory: Utilization per calendar period, oldest first, ending with the current one.
  - `project_id` string, required: Project the history covers
  - `granularity` 'day' | 'week' | 'month' | 'quarter' | 'year', required: The calendar period each history point covers, in UTC.
  - `start` string, date-time, required: Start of the first point: the requested start snapped back to its period's boundary, or later if no channel existed yet
  - `trimmed_to_first_channel` boolean: Whether periods before the project's first channel were dropped, so the series starts later than requested
  - `generated_at` string, date-time, required: When the history was computed
  - `points` UtilizationHistoryPoint[]: One point per period, oldest first
    - `period_start` string, date-time, required: Inclusive start of the period
    - `period_end` string, date-time, required: Exclusive end of the period; the current time for the period still in progress
    - `partial` boolean: Whether the period is still in progress
    - `occupied_hours` number, required: Channel-hours running a test
    - `stale_hours` number, required: Channel-hours of still-open runs after they stopped uploading; finished runs count as occupied throughout
    - `free_hours` number, required: Channel-hours idle and in service
    - `out_of_service_hours` number, required: Channel-hours under an outage
    - `available_hours` number, required: Channel-hours of channels that existed during the period
    - `utilization_percent` number, required: Occupied plus stale over available — the wall's headline rule
    - `utilization_of_available_percent` number, required: Occupied plus stale over the hours not out of service

## Other responses

- `422`: Validation Error

## Changes

- **2026-10-02** `af9fdad1dc5b`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/ionworks/apis/ionworks-api/changes/projects/:project_id/lab/utilization-history/get.md)

---

[API](https://skmtc.dev/ionworks/apis/ionworks-api.md) - [All operations](https://skmtc.dev/ionworks/apis/ionworks-api/llms.txt) - [OpenAPI document](https://skmtc.dev/ionworks/apis/ionworks-api/revisions/abebbbc5f60a?raw)
