---
title: "Aggregate Projects"
method: POST
path: "/v1/project/aggregate"
tags: ["Projects"]
---

# Aggregate Projects

`POST /v1/project/aggregate`

Aggregate projects with GROUP BY operations.

Allows grouping by name, city, country, site_code, and other fields with aggregation functions
like COUNT, SUM, AVG, MIN, MAX. Uses the same base filters and company scoping
as the search endpoint for consistent behavior.

## Request body

- ProjectAggregationSearchModel — Project aggregation model with project-specific filters. Inherits from ProjectSearchModel to include is_archived and external_ids filters in addition to the standard search parameters.
  - `query` string, nullable — Keywords should be space separated and are `AND`ed together, so all keywords must be present but they can be present in any of the fields specified above.
  - `skip` integer, nullable — Number of records to skip before returning records
  - `limit` integer, nullable — Number of records to return
  - `sort_direction` 'asc' | 'desc' — Direction to sort the `sort_column` - ascending or descending.
  - `date_start` string, date-time, nullable — If sorting on `updated_at` or `created_at`, and `date_cut_off` is provided, return only records that were created or updated (whichever is being sorted on) between `date_start` and `date_cut_off`
  - `date_cut_off` string, date-time, nullable — If sorting on `updated_at` or `created_at`, return only records that were created or updated (whichever is being sorted on) between the initial value (determined by sort order) and the cutoff date. For example, sorting on `created_at` ascending with a `date_cut_off` will return all records from the oldest creation date to the cutoff date. By comparison, sorting on `created_at` descending with a `date_cut_off` will return all records from the most recent creation date to the cutoff date.
  - `sort_column` string, nullable — Column to sort aggregation results by (must be in group_by or an aggregation alias)
  - `external_ids` string, nullable — Return sites with a matching external identifier. Should be a comma-separated list.
  - `is_archived` boolean, nullable — Filter based on the project's archived status. Defaults to False, which returns records that have not been archived
  - `city` string, nullable — Filter by project city.
  - `country` string, nullable — Filter by project country.
  - `is_private` boolean, nullable — Filter by private/public status.
  - `prime_id` integer, nullable — Filter by prime contractor company ID.
  - `user_id` integer, nullable — Return sites that the user with this ID is assigned to.
  - `group_by` string[], required — Column names to group by
  - `aggregations` AggregationFieldLiteralIdSiteCode[], required — Aggregation functions to apply
    - `column` 'id' | 'site_code', required — Column name to aggregate
    - `operator` 'sum' | 'avg' | 'count' | 'min' | 'max' | 'count_distinct', required — Supported aggregation operators for SQL GROUP BY queries.
    - `alias` string, nullable — Optional alias for the result column
  - `date_filter_column` 'created_at' | 'updated_at' — Column to apply date_start/date_cut_off filters on (created_at or updated_at)

## Response `200`

Successful Response

- ApiGenericResponseProjectAggregationResponse
  - `error` boolean — A boolean error indicator.
  - `message` string, nullable — Optional message.
  - `data` ProjectAggregationResponse — Response model for project aggregation queries.
    - `data` object[], required — List of aggregation result rows. Each row contains the group_by column values and computed aggregation values. Keys are the group_by column names and aggregation aliases (or default names like 'count_id' if no alias provided).
    - `total_groups` integer, required — Total number of distinct groups returned by the aggregation query
    - `metadata` AggregationMetadataLiteralNameCityCountrySiteCodeIsPrivateGeoCheckInEnabledPrimeIdCreatedDateCreatedWeekCreatedMonthCreatedYearUpdatedDateUpdatedWeekUpdatedMonthUpdatedYearLiteralIdSiteCode, required
      - `group_by_columns` string[], required — List of column names used for grouping the results
      - `aggregations` AggregationFieldLiteralIdSiteCode[], required — List of aggregation functions that were applied to produce the results
        - `column` 'id' | 'site_code', required — Column name to aggregate
        - `operator` 'sum' | 'avg' | 'count' | 'min' | 'max' | 'count_distinct', required — Supported aggregation operators for SQL GROUP BY queries.
        - `alias` string, nullable — Optional alias for the result column
      - `time_series` TimeSeriesMetadata — Metadata for time-series aggregation results.
        - `time_field` string, required — The time-based column used for grouping (e.g., 'created_month')
        - `granularity` 'date' | 'week' | 'month' | 'year', required — The time granularity of the grouping
        - `category_fields` string[] — Non-time columns used for grouping (e.g., ['status'])

## Other responses

- `400` — Invalid aggregation request
- `403` — Permission denied
- `409` — Integrity Error or Data Conflict
- `422` — Validation Error

---

[API](https://skmtc.dev/salussafety/apis/salus-developer-api.md) · [All operations](https://skmtc.dev/salussafety/apis/salus-developer-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/salussafety/salus-developer-api/revisions/ef065f44da25/schema)
