App Utilization Timeseries
This endpoint is approved but has not been implemented yet. See the App Usage Dashboard Spec for full context.
GET /clients/{client_id}/analytics/apps/utilization/timeseries
Returns a time-series of app counts classified into mutually exclusive buckets: unused, unapproved, AI, and other. Serves the stacked bar chart on the App Usage Dashboard.
Each data point represents one granularity unit (typically a month) and contains the count of distinct apps in each classification bucket.
For the paginated app metrics table, use App Utilization. For aggregate card counts, use App Utilization Summary.
Use Case
Use this endpoint to:
- Render a stacked bar chart showing how app usage composition changes over time
- Track growth or decline of unapproved or AI app usage
- Identify months with spikes in unused apps (potential license waste)
Path Parameters
| Parameter | Type | Description |
|---|---|---|
client_id | string (uuid) | Unique identifier for the client organization |
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
granularity | string | Yes | - | Time bucket size: daily, weekly, monthly, quarterly. Determines the grouping of each data point. |
start_date | string | Yes | - | Start of period (YYYY-MM-DD) |
end_date | string | Yes | - | End of period, inclusive (YYYY-MM-DD) |
department_ids | string | No | - | Comma-separated department UUIDs to scope usage data to |
Granularity
granularity determines the time bucket for each data point. For a 12-month stacked bar chart, use monthly. Each bucket counts distinct apps classified in that period.
Response
| Field | Type | Description |
|---|---|---|
period | Period | Resolved date range |
data | TrendDataPoint[] | One entry per granularity unit in the range |
Example Requests
Monthly timeseries for the past year
curl -X GET "https://api.example.com/v2/clients/aa7cf840-9ca9-46a3-9778-9015d6580d50/analytics/apps/utilization/timeseries?granularity=monthly&start_date=2025-06-01&end_date=2026-05-31" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Scoped to a department
curl -X GET "https://api.example.com/v2/clients/aa7cf840-9ca9-46a3-9778-9015d6580d50/analytics/apps/utilization/timeseries?granularity=monthly&start_date=2025-06-01&end_date=2026-05-31&department_ids=d1a2b3c4-e5f6-7890-abcd-ef1234567890" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Example Response
{
"period": {
"start_date": "2025-06-01",
"end_date": "2026-05-31"
},
"data": [
{
"date": "2025-06-01",
"unused_apps": 18,
"unapproved_apps": 14,
"ai_apps": 3,
"other_apps": 55
},
{
"date": "2025-07-01",
"unused_apps": 10,
"unapproved_apps": 12,
"ai_apps": 4,
"other_apps": 62
},
{
"date": "2025-08-01",
"unused_apps": 8,
"unapproved_apps": 10,
"ai_apps": 5,
"other_apps": 68
},
{
"date": "2025-09-01",
"unused_apps": 7,
"unapproved_apps": 11,
"ai_apps": 5,
"other_apps": 70
},
{
"date": "2025-10-01",
"unused_apps": 12,
"unapproved_apps": 15,
"ai_apps": 5,
"other_apps": 65
},
{
"date": "2025-11-01",
"unused_apps": 6,
"unapproved_apps": 9,
"ai_apps": 6,
"other_apps": 72
}
]
}
Period
| Field | Type | Nullable | Description |
|---|---|---|---|
start_date | string | No | Start of the period (YYYY-MM-DD) |
end_date | string | No | End of the period (YYYY-MM-DD) |
This endpoint does not support comparison periods. The time-series itself shows change over time.
TrendDataPoint
| Field | Type | Description |
|---|---|---|
date | string | Start date of the granularity bucket (YYYY-MM-DD). For monthly, this is the first day of the month. |
unused_apps | integer | Apps known to the client with prior activity but zero activity in this bucket |
unapproved_apps | integer | Apps with activity, is_approved=false, not AI-categorized |
ai_apps | integer | Apps with activity that have an AI catalog category |
other_apps | integer | Apps with activity that are approved and not AI-categorized |
Classification Logic
Each app is assigned to exactly one bucket per time period. The classification is mutually exclusive and uses the following priority:
| Priority | Bucket | Criteria |
|---|---|---|
| 1 | unused_apps | App has prior usage with this client but zero rows in app_usage_reports for this time bucket |
| 2 | ai_apps | App has activity AND has at least one AI catalog category (any approval status) |
| 3 | unapproved_apps | App has activity AND is_approved = false AND not AI-categorized |
| 4 | other_apps | App has activity AND is_approved = true AND not AI-categorized |
An app that is both AI-categorized and unapproved is classified as ai_apps (the more specific classification wins).
The sum unused_apps + unapproved_apps + ai_apps + other_apps equals the total number of distinct apps known to the client for that time bucket.
DB source:
| Bucket | DB Aggregation |
|---|---|
unused_apps | Apps in apps table for this client with at least one historical app_usage_reports row but zero rows where activity_date falls within this bucket |
ai_apps | COUNT(DISTINCT application_id) from app_usage_reports in this bucket, joined to AI category |
unapproved_apps | COUNT(DISTINCT application_id) from app_usage_reports in this bucket, where apps.is_approved = false AND not AI-categorized |
other_apps | COUNT(DISTINCT application_id) from app_usage_reports in this bucket, where apps.is_approved = true AND not AI-categorized |
Constraints
- Max date range: 366 days. Requests exceeding this return
400. granularityis required. There is no default.- Zero-fill: Granularity buckets with no data return all counts as
0. - Timezone: All dates are in the client's configured timezone.
- No comparison period. This endpoint shows change over time natively via the time-series itself.
Error Responses
| Status | Description |
|---|---|
| 400 | Invalid parameters (bad date format, range exceeds 366 days, missing granularity) |
| 401 | Authentication required |
| 403 | Insufficient permissions for this client |
| 404 | Client not found |
| 500 | Server error |
Example Error Response
{
"error": {
"code": "invalid_parameter",
"message": "granularity is required",
"details": null
}
}
Related Endpoints
- App Utilization -- Paginated per-app metrics table
- App Utilization Summary -- Aggregate card counts
- App Utilization Rankings -- Top app by various metrics