# Get a Workflow's Category Counts

Source: https://docs.pitchpointsolutions.com/api/findings/get_workflow_category_counts/

**Beta**

Each of the workflow's configured categories, with review and severity tallies only, never the findings themselves. Use this when you only need counts (for example, a summary dashboard); use [Get a Workflow's Findings by Category](https://docs.pitchpointsolutions.com/api/findings/get_workflow_findings_by_category) when you need the findings themselves.

These are per-category counts only. The workflow-wide `score` and `severityCounts` are on [Get a Workflow's Findings Summary](https://docs.pitchpointsolutions.com/api/findings/get_workflow_findings): call both if you need both.

Read-only and safe to poll.

### Sample

```bash
url="https://api.pointservices.com/riskinsight-services-ws/resources/v1/findings/workflows/wfpop_0000000000002082611/categories"
curl -X GET "${url}" \
  -H "Authorization: Bearer your_access_token_here"
```

#### Header Properties

| Property | Value | Required? |
|----------|-------|-----------|
| Authorization | Bearer *your token* | true |

#### Path Parameters

| Property | Description | Type |
|----------|-------------|------|
| workflowId | The workflow's id, exactly as this API returned it. | string |

> **Warning:** `workflowId`, `findingId` and `attachmentId` are opaque. Send each one back exactly as this API returned it: don't parse it, build one yourself, or add or remove its prefix. A `findingId` or `attachmentId` that isn't exactly as published, including one with its prefix removed, returns a 404 as if it didn't exist.

### Responses

**200**

| Property | Description | Type |
|----------|-------------|------|
| workflowId | The workflow's id. | string |
| categories | Every configured category's counts, in configured order. Always an array, never null. | array |

##### categories entry

| Property | Description | Type |
|----------|-------------|------|
| category | The display name, exactly as configured: the same name as the matching category in [Get a Workflow's Findings by Category](https://docs.pitchpointsolutions.com/api/findings/get_workflow_findings_by_category), so you can correlate the two by name. Not a closed set. Treat it as a label for a person, never a key to switch on. | string |
| orderIndex | The category's configured presentation order, the same order the categorized view uses. A bucket for findings with no configured category, when present, sorts last. | integer |
| reviewedCount | How many of this category's findings have `reviewed` set to `true`, whether or not they required review. Because it includes findings that didn't require review, it can be larger than `reviewRequiredCount`. It is not "required reviews completed". | integer |
| reviewOutstandingCount | How many of this category's findings still need review: `reviewRequired` is `true` and `reviewed` is `false`. `0` means nothing in this category is waiting on a reviewer. | integer |
| reviewRequiredCount | How many of this category's findings have `reviewRequired` set to `true`, reviewed or not. `reviewRequiredCount` minus `reviewOutstandingCount` is the number of required reviews already done. | integer |
| severityCounts | This category's findings, tallied by `(severity, reviewed)`. Always an array, `[]` when the category has no findings. | array |

```json
{
  "workflowId": "wfpop_0000000000002082611",
  "categories": [
    {
      "category": "Income",
      "orderIndex": 0,
      "reviewedCount": 3,
      "reviewOutstandingCount": 1,
      "reviewRequiredCount": 4,
      "severityCounts": [
        { "severity": "HIGH", "reviewed": false, "count": 1 },
        { "severity": "MEDIUM", "reviewed": true, "count": 3 }
      ]
    },
    {
      "category": "Assets",
      "orderIndex": 1,
      "reviewedCount": 2,
      "reviewOutstandingCount": 0,
      "reviewRequiredCount": 2,
      "severityCounts": [
        { "severity": "CLEAR", "reviewed": true, "count": 2 }
      ]
    }
  ]
}
```

> **Warning:** An **empty `categories` array doesn't mean "nothing to review"**: a workflow with no categories configured returns one too. To tell whether anything is outstanding across the whole workflow, read the findings themselves ([List a Workflow's Findings](https://docs.pitchpointsolutions.com/api/findings/get_workflow_findings_list)) and look for `reviewRequired` `true` with `reviewed` `false`.

See [Reading reviewed with reviewRequired](https://docs.pitchpointsolutions.com/api/findings/get_workflow_findings_list#reading-reviewed-with-reviewrequired) for what each state means.

**401**

No credential the service could accept reached it. The body is an RFC 9457 problem document, served as `application/problem+json`, and the response carries a `WWW-Authenticate` challenge. The request body is never read, so a 401 says nothing about whether the rest of your request would have been accepted.

Two problem types tell the cases apart:

| `type` | Meaning | `WWW-Authenticate` |
|--------|---------|--------------------|
| `about:blank` | No credential was presented. | `Bearer realm="Helix"` |
| `https://pointservices.com/problems/invalid-token` | A credential was presented and rejected. The response doesn't say why: an expired, revoked, badly signed and malformed token all look the same. | `Bearer realm="Helix", error="invalid_token"` |

```json
{
  "type": "https://pointservices.com/problems/invalid-token",
  "title": "The access token was not accepted",
  "status": 401,
  "detail": "The access token was rejected.",
  "instance": "urn:pps:request:0000000000000000000000000000000000000000000000000000"
}
```

> **Warning:** Refresh your token on a 401, and only on a 401. An expiring token moves a call from 200 to 401, never to 403, so a fresh token is the fix here and never the fix for a 403.

**403**

You may not read this workflow.

You are authenticated, and the answer is still no. This is an authorization decision, not a statement about your token, so refreshing the token won't turn it into a 200. 

The body is an RFC 9457 problem document, served as `application/problem+json`. Two problem types tell the cases apart:

| `type` | Meaning |
|--------|---------|
| `about:blank` | The request was refused before the operation ran. |
| `https://pointservices.com/problems/not-authorized` | The operation ran, and policy won't let you act on the workflow or finding you named. |

```json
{
  "type": "https://pointservices.com/problems/not-authorized",
  "title": "Not authorized",
  "status": 403,
  "detail": "The authenticated identity is not permitted to perform this action.",
  "instance": "urn:pps:request:0000000000000000000000000000000000000000000000000000"
}
```

A 403 can also come from the edge, before the service is reached: for example, when a request value resembles SQL injection or cross-site scripting. Those refusals carry no problem document. Write your client to handle an error response it can't parse, rather than assuming every failure has a JSON body.

**404**

Unknown `workflowId`.

The body is an RFC 9457 problem document, served as `application/problem+json`. Two problem types tell the cases apart:

| `type` | Meaning |
|--------|---------|
| `https://pointservices.com/problems/not-found` | An id in the path isn't one this API knows. Check that you sent it exactly as the API returned it. |
| `about:blank` | The URL or method isn't one this API serves at all. Check the path. |

| Property | Description | Type |
|----------|-------------|------|
| type | An absolute URI identifying the problem type. This is the stable value to match on; compare it as a string. | string |
| title | A short summary, written for a person. | string |
| status | The HTTP status code, repeated in the body. | number |
| detail | An explanation of this occurrence, written for your logs. Never match on it. | string |
| instance | A URI identifying this occurrence, written as `urn:pps:request:<id>`. The id is the same value as the `x-pps-request-id` response header. Quote it when you report a problem to PPS. | string |

```json
{
  "type": "https://pointservices.com/problems/not-found",
  "title": "No such resource",
  "status": 404,
  "detail": "Workflow[wfpop_0000000000002082611] not found",
  "instance": "urn:pps:request:8d3a1f56-6c94-4e20-b7f8-0a5e9c2d4b73"
}
```

> **Warning:** Branch on `type`, never on the text of `title` or `detail`.
