Skip to main content

App Utilization by Category

Approved

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/categories

Returns a paginated list of catalog categories ranked by app or user count for the requested period. Each row contains a category reference alongside aggregate metrics (app count, user count) and optional comparison-period change percentages.

This endpoint powers the "Categories" tab in the AI Apps and Un-Approved Apps sections of the App Usage Dashboard. It is a dimension view — for per-app metrics, use App Utilization.

Use Case

Use this endpoint to:

  • Render a categories tab showing which app categories are most used
  • Filter to AI-only categories with category_ids
  • Filter to unapproved app categories with is_approved=false
  • Compare category distribution between time periods

Path Parameters

ParameterTypeDescription
client_idstring (uuid)Unique identifier for the client organization

Query Parameters

ParameterTypeRequiredDefaultDescription
granularitystringYes-Aggregation granularity: daily, weekly, monthly, quarterly
start_datestringYes-Start of period (YYYY-MM-DD)
end_datestringYes-End of period, inclusive (YYYY-MM-DD)
compare_start_datestringNo-Comparison period start (YYYY-MM-DD). Must be provided with compare_end_date.
compare_end_datestringNo-Comparison period end, inclusive (YYYY-MM-DD). Must be provided with compare_start_date.
is_approvedbooleanNo-Filter to apps by approval status
category_idsstringNo-Comma-separated catalog category UUIDs. When provided, only apps matching these categories are included, and the response groups by all categories those apps belong to (which may include categories not in the filter).
vendor_idsstringNo-Comma-separated catalog vendor UUIDs to filter by
department_idsstringNo-Comma-separated department UUIDs to scope usage data to
sort_bystringNoapp_countSort field: app_count, user_count, name
sort_orderstringNodescSort direction: asc, desc
page_sizeintegerNo50Items per page. Max: 200
cursorstringNo-Pagination cursor from a previous response

Comparison period

When both compare_start_date and compare_end_date are provided, change_pct fields contain the percentage change from the comparison period to the primary period. When omitted, all change_pct fields are null.

Providing only one of the two comparison parameters returns 400.

Response

FieldTypeDescription
periodPeriodResolved date range
dataCategoryUtilization[]Array of category utilization objects
total_countintegerTotal number of categories matching the current filters
next_cursorstring | nullCursor for the next page. null when on the last page.

Example Requests

AI app categories for February 2026

curl -X GET "https://api.example.com/v2/clients/aa7cf840-9ca9-46a3-9778-9015d6580d50/analytics/apps/utilization/categories?granularity=monthly&start_date=2026-02-01&end_date=2026-02-28&category_ids=a7b8c9d0-e1f2-3456-abcd-789012345678" \
-H "Authorization: Bearer YOUR_API_TOKEN"

Unapproved app categories with comparison

curl -X GET "https://api.example.com/v2/clients/aa7cf840-9ca9-46a3-9778-9015d6580d50/analytics/apps/utilization/categories?granularity=monthly&start_date=2026-02-01&end_date=2026-02-28&compare_start_date=2026-01-01&compare_end_date=2026-01-31&is_approved=false" \
-H "Authorization: Bearer YOUR_API_TOKEN"

Example Responses

With comparison period

{
"period": {
"start_date": "2026-02-01",
"end_date": "2026-02-28",
"compare_start_date": "2026-01-01",
"compare_end_date": "2026-01-31"
},
"data": [
{
"category": {
"id": "a7b8c9d0-e1f2-3456-abcd-789012345678",
"name": "CRM"
},
"app_count": { "value": 4, "change_pct": 33.3, "compare_value": 3 },
"user_count": { "value": 28, "change_pct": 12.0, "compare_value": 25 }
},
{
"category": {
"id": "b8c9d0e1-f2a3-4567-bcde-901234567890",
"name": "Communication"
},
"app_count": { "value": 3, "change_pct": 0.0, "compare_value": 3 },
"user_count": { "value": 22, "change_pct": -5.0, "compare_value": 23 }
},
{
"category": {
"id": "c9d0e1f2-a3b4-5678-cdef-012345678901",
"name": "Development"
},
"app_count": { "value": 2, "change_pct": 100.0, "compare_value": 1 },
"user_count": { "value": 15, "change_pct": null, "compare_value": null }
}
],
"total_count": 5,
"next_cursor": null
}

Without comparison period

{
"period": {
"start_date": "2026-02-01",
"end_date": "2026-02-28",
"compare_start_date": null,
"compare_end_date": null
},
"data": [
{
"category": {
"id": "a7b8c9d0-e1f2-3456-abcd-789012345678",
"name": "CRM"
},
"app_count": { "value": 4, "change_pct": null, "compare_value": null },
"user_count": { "value": 28, "change_pct": null, "compare_value": null }
}
],
"total_count": 5,
"next_cursor": "eyJsYXN0X2lkIjoiYTdiOGM5ZDAifQ"
}

Period

FieldTypeNullableDescription
start_datestringNoStart of the primary period (YYYY-MM-DD)
end_datestringNoEnd of the primary period (YYYY-MM-DD)
compare_start_datestringYesStart of comparison period. null if no comparison requested.
compare_end_datestringYesEnd of comparison period. null if no comparison requested.

CategoryUtilization

FieldTypeNullableDescription
categoryCatalogCategoryNoCategory identity ({ id, name })
app_countMetricWithDeltaDtoNoDistinct apps in this category with activity during the period
user_countMetricWithDeltaDtoNoDistinct users who used apps in this category during the period

An app can belong to multiple categories. When this happens, the app is counted once per category it belongs to. app_count values across all rows may therefore sum to more than the total distinct app count.

DB source:

DTO FieldDB Aggregation
categorycatalog_categories joined via catalog_application_catalog_categories
app_count.valueCOUNT(DISTINCT application_id) grouped by category, filtered to activity_date within the period
user_count.valueCOUNT(DISTINCT user_id) grouped by category, filtered to activity_date within the period
*.change_pct((current - comparison) / comparison) * 100 using the same aggregations over the comparison date range
*.compare_valueThe same aggregation as *.value applied to the comparison date range. null when no comparison period is requested.

Pagination

This endpoint uses cursor-based pagination.

  1. Omit cursor on the first request
  2. If next_cursor is not null, pass its value as cursor on the next request
  3. Repeat until next_cursor is null

Constraints

  • Max date range: 366 days for both primary and comparison periods. Requests exceeding this return 400.
  • Comparison symmetry: Both compare_start_date and compare_end_date must be provided together, or both omitted.
  • Timezone: All dates are in the client's configured timezone.
  • granularity is required. There is no default.

Error Responses

StatusDescription
400Invalid parameters (bad date format, range exceeds 366 days, mismatched comparison params, missing granularity, unknown sort_by value)
401Authentication required
403Insufficient permissions for this client
404Client not found
500Server error