> ## Documentation Index
> Fetch the complete documentation index at: https://docs.noresponse.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Assessment counts

> Count assessments by time, decision, reason and network, and find the assessments behind each count.

`POST /v1/assessments/aggregate` counts the assessments of the calling key's environment. Use it to draw charts of your traffic. Show decisions over time, the reasons that fire most and the networks and countries that send risk. Show the decisions that change after the first answer. It needs `investigate` or `history`.

Choose the population that matches your question:

* `first_answers`, the default, uses anonymous counts kept as each assessment gets its first answer. A window that may contain deleted contributions answers `409 aggregate_deleted_data`.
* `retained_first_answers` computes exact filter combinations from retained first answers. It excludes deleted detail and supports at most 31 days and 100,000 matching records.

## Make a request

```http Count signups by decision for one week theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
POST /v1/assessments/aggregate
Content-Type: application/json

{
  "from": "2026-10-19T00:00:00Z",
  "to": "2026-10-26T00:00:00Z",
  "bucket": "day",
  "group_by": ["decision"],
  "metrics": ["count", "score_histogram", "late_flips"],
  "flow": "account_creation"
}
```

| Member | What it does |
| - | - |
| `from`, `to` | The range `[from, to)`. Each one must start a bucket. The range is at most 366 days, and at most 31 days for `hour`. With a `time_zone` other than `UTC`, `day` and `week` ranges are at most 92 days. `from` must be inside your retention period. |
| `bucket` | `hour`, `day` or `week`. A day starts at midnight in `time_zone`, and a week starts on Monday at that midnight. An hour is always a whole UTC hour. |
| `time_zone` | An IANA time zone name such as `Europe/London`, `America/New_York` or `Asia/Kolkata`. The default is `UTC`. Send your viewer's zone so that "today" is their day. A day in a zone with daylight saving time can have 23 or 25 hours. An unknown name gets `400 invalid_request` for `time_zone`. Day and week ranges in a zone other than `UTC` are at most 92 days. A longer range gets `400 invalid_request` for `to`. |
| `group_by` | At most two dimensions. In the default population, at most one is `reason`, `lane`, `country` or `asn`. |
| `metrics` | `count` (the default), `score_histogram`, `score_outcomes` and `late_flips`. Retained first answers do not support `late_flips`. |
| `limit` | The number of groups, 1 to 100, default 20. The largest groups over the whole range come first. `groups_truncated` is `true` when there were more. |
| `flow`, `status`, `recommendation`, `decision` | The same filters as [search](https://docs.noresponse.org/reference/investigation.md). They apply to the first answer. |

Select `retained_first_answers` to combine `band`, `reason`, `impact`, incomplete `lane`, `country`, `asn`, `score_min`, `score_max` and `list_match` filters. These use the same rules as [search](https://docs.noresponse.org/reference/investigation.md#search-and-get-exact-decisions). `impact` requires a reason. Score bounds are inclusive, and missing scores do not match.

This population also permits any pair of supported group dimensions. It refuses work beyond its record or time budget instead of returning a partial count. Narrow the range or filters when it refuses the request.

### Time zones with a half-hour offset

The default population keeps its counts by the UTC hour. In a zone whose midnight is not on a UTC hour, such as `Asia/Kolkata` (UTC+05:30) or `Australia/Adelaide`, it cannot split an hour into two days. So a `day` or `week` request in such a zone gets `400 invalid_request` for `time_zone`. Send `"population": "retained_first_answers"` for up to 31 days, or use `hour` buckets.

When the range starts on the day that holds the start of your retention period, that day counts from `coverage.retained_from` only.

## What one count is

Each assessment counts one time, by its first answer: the answer that NoResponse served when the assessment first had an answer. A later revision, a late result or the end of a hold does not count the assessment again.

If the first answer was `pending`, it has no decision, recommendation, band or score. A group then leaves that dimension out.

| Dimension | Value |
| - | - |
| `decision` | `block` when the first answer's `risk.block` was `true`, otherwise its recommendation. |
| `flow` | The assessment's flow. |
| `recommendation`, `band` | The first answer's. |
| `list_match` | `block` or `allow` when an entry of your [list](https://docs.noresponse.org/reference/lists.md) decided the account at the first answer. In retained results, `none` means a captured absence of a match. |
| `reason` | Each reason that the first answer fired, with its impact band in `impact`. An assessment counts once in each of its reasons. |
| `lane` | Each evidence lane that the first answer listed in `incomplete_sources`. An assessment counts once in each lane. |
| `country`, `asn` | The country and network of the submitted IP address, from the IP data. |

A count for a reason or a lane can be more than the count of its bucket. The counts show reasons by code and impact band only. They do not show weights.

## The answer

The answer has one entry in `buckets` for each bucket of the range, with the empty buckets too. It repeats `time_zone`. `from`, `to` and each bucket's `start` are UTC instants: in `Asia/Tokyo`, the day of 20 October starts at `2026-10-19T15:00:00Z`. Each bucket has these members:

* `count`: the number of assessments created in the bucket. You get it with the `count` metric.
* `groups`: the count of each group in the bucket, largest group first.
* `score_histogram`: for each flow, the first answers whose score is in each 5-point range (`score_min` to `score_max`, 0-4 up to 95-100).
* `score_outcomes`: the first answers of `score_histogram` whose assessment has a reported [outcome](https://docs.noresponse.org/guides/outcomes.md), by flow, 5-point range and the latest outcome you reported. A range's `score_histogram` count minus its `score_outcomes` is the first answers with no outcome reported. Use it to see how many abuse reports and false positives each threshold would have caught or let through.
* `late_flips`: the changes to the account decision for the assessment's flow after the first answer. Each change has its `from` decision, its `to` decision and its `delay` after the creation of the assessment: `under_10s`, `under_1m`, `under_10m`, `under_1h`, `under_1d` or `over_1d`.

An assessment counts under one outcome at a time, the latest you reported. A new outcome moves it from the old one. `coverage.score_outcomes_started_at` states when capture began. The default population does not reconstruct outcomes reported before that time.

A late flip is the change that `account.risk_changed` announces, put in the bucket of the assessment's creation. `from` is `allow` before the first announcement. An assessment that changes two times counts two times. The change that the first answer itself made is not a late flip.

`coverage` describes the same database snapshot as the counts. It reports capture start times, `as_of`, `retained_from`, the population and whether deleted records remain in the counts. `overlapping_groups` identifies reason or lane groups that can overlap. `late_flip_unit` is `decision_transitions`, not unique accounts or assessments.

## Find the assessments behind a count

The aggregate and search use the same filters. To list the assessments of one count, send [search](https://docs.noresponse.org/reference/investigation.md) the same filters with `"revision": "first"`, and use the bucket's start and end as `from` and `to`:

```json Search the first answers behind one count theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
{
  "from": "2026-10-19T00:00:00Z",
  "to": "2026-10-20T00:00:00Z",
  "flow": "account_creation",
  "decision": "block",
  "revision": "first"
}
```

With `revision: "first"`, search filters on the first answer and returns that answer, version 1. Without it, search filters on the latest revision, so an assessment that changed after its first answer moves to its new decision.

## Retention and deletion

A deleted assessment can reveal attributes through a small count, even without its identifier.
The default population refuses windows that overlap an deleted assessment's hour with `409 aggregate_deleted_data`.
Older deletions have no exact contribution record, so earlier windows for those workspaces are also refused.
The stored counters stay intact. Search and `retained_first_answers` exclude deleted assessments.

NoResponse keeps the counts by hour, day and month. Each count stays until its whole hour, day or month is older than your retention period. When you delete your workspace, NoResponse deletes its counts.

## Errors

The aggregate returns `400 invalid_request` in these cases, and `invalid_params` names the field:

* The body does not match the request schema.
* `from` or `to` does not start a bucket.
* The range is too long, or it starts before your retention period.
* The default population has two of `reason`, `lane`, `country` and `asn` in `group_by`.
* Facet filters are supplied without `retained_first_answers`.
* Retained first answers are requested with `late_flips` or a range longer than 31 days.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.