# List reviews

Source: https://docs.coderhelm.com/api/reference/reviews/list-reviews

`GET /api/reviewer/reviews`

Lists the reviewer's pull request reviews, newest first, one page at a time, for the whole team or one repository. Bodies are cut to about 4,000 characters and findings are left out; get a review by its `sk` for both.

## Authentication

A team API key: `Authorization: Bearer chk_...`. The key needs the `view` scope. See [Authentication](https://docs.coderhelm.com/api/authentication).

## Parameters

### Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `repo` | string | no | Only this repository, `owner/name`. Omit for the whole team. |
| `limit` | integer | no | Reviews per page, 1 to 200. Default 50. |
| `cursor` | string | no | `next` from the previous page. |

## Responses

### 200

A page of reviews.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `next` | string or null | no | Pass as `cursor` to read the next page; null on the last page. |
| `reviews` | array of Review | yes | Reviews, newest first. Findings are left out here. |
| `reviews[].action_summary` | string | yes | What the reviewer did besides reviewing, such as arming auto-merge. |
| `reviews[].applied_standards` | array of string | yes | The team standards the review was given in full ("always apply"). |
| `reviews[].body` | string | yes | The review as posted, in Markdown. Cut to about 4,000 characters in a list. |
| `reviews[].created_at` | string | yes | When it was written (RFC 3339). |
| `reviews[].findings` | array of ReviewFinding or null | no | The structured findings. Null in a list (get the review for them) and on older reviews. |
| `reviews[].findings[].blocks` | boolean or null | no | For a question: whether the change's correctness depends on the answer. |
| `reviews[].findings[].body` | string | yes | The explanation, in Markdown. |
| `reviews[].findings[].category` | string | yes | What kind of finding, such as `bug`, `security` or `manual-check`. |
| `reviews[].findings[].end_line` | integer or null | no | The last line, when it spans several. |
| `reviews[].findings[].evidence` | string or null | no | What it rests on: `verified-defect`, `unverified-concern` or `question`. Only a verified defect holds the merge. |
| `reviews[].findings[].file` | string | yes | The file, relative to the repository root. |
| `reviews[].findings[].line` | integer | yes | The line it is about. |
| `reviews[].findings[].lookups` | array of string | yes | The lookups the finding rests on. |
| `reviews[].findings[].severity` | string | yes | `blocking`, `high`, `medium`, `low` or `nit`. |
| `reviews[].findings[].suggestion` | string or null | no | Replacement text for the line(s), when there is a concrete fix. |
| `reviews[].findings[].title` | string | yes | One line on what is wrong. |
| `reviews[].head_sha` | string | yes | The commit reviewed. |
| `reviews[].posted_as` | string | yes | The GitHub review event it was posted as: `APPROVE`, `REQUEST_CHANGES` or `COMMENT`. |
| `reviews[].pr_number` | integer | yes | The pull request number. |
| `reviews[].pr_title` | string | yes | The pull request's title. Empty on older reviews. |
| `reviews[].rating_comments` | array of RatingComment | yes | Ratings with comments. |
| `reviews[].rating_comments[].at` | string | yes | When (RFC 3339). |
| `reviews[].rating_comments[].by` | string | yes | Who rated it. |
| `reviews[].rating_comments[].rating` | string | yes | `up`, `down` or `none` (a comment without a rating). |
| `reviews[].rating_comments[].text` | string | yes | What they said. |
| `reviews[].repo` | string | yes | The repository, `owner/name`. |
| `reviews[].risk` | string | yes | The risk the reviewer gave the change: `LOW`, `MEDIUM` or `HIGH`. |
| `reviews[].sk` | string | yes | The review's key: pass it as `sk` to get the review. |
| `reviews[].thumbs_down` | integer | yes | Thumbs down from the team. |
| `reviews[].thumbs_up` | integer | yes | Thumbs up from the team. |
| `reviews[].trigger` | string | yes | What asked for it, such as `label`, `rerequest`, `reply` or `sweep`. |
| `reviews[].verdict` | string | yes | The reviewer's verdict: `APPROVE` or `REQUEST_CHANGES`. |

Headers: `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset`.

### 400

`repo` is not `owner/name`.

### 401

The key is missing, malformed, revoked or expired, or the person who made it left the team.

### 403

The key lacks the scope this endpoint needs (`missing_scope`).

### 429

Over the key's rate limit (`rate_limited`), or, for endpoints that start work, over the team's monthly token limit (`token_limit_reached`).

Headers: `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset`, `Retry-After`.

### 500

Something failed on CoderHelm's side. Safe to retry reads.

## Example request

cURL:

```bash
curl -X GET 'https://api.coderhelm.com/api/reviewer/reviews' \
  -H "Authorization: Bearer $CODERHELM_API_KEY"
```

TypeScript:

```ts
const res = await fetch("https://api.coderhelm.com/api/reviewer/reviews", {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CODERHELM_API_KEY}`,
  },
});
if (!res.ok) {
  const { error, code } = await res.json();
  throw new Error(`${res.status} ${code}: ${error}`);
}
const data = await res.json();
```

Python:

```python
import os
import requests

headers = {
    "Authorization": f"Bearer {os.environ['CODERHELM_API_KEY']}",
}
res = requests.request("GET", "https://api.coderhelm.com/api/reviewer/reviews", headers=headers)
if not res.ok:
    raise RuntimeError(f"{res.status_code}: {res.json().get('error')}")
data = res.json()
```

## Example response

```json
{
  "next": "1729605605|REVIEW#acme/web#318#2026-10-22T14:20:05Z",
  "reviews": [
    {
      "action_summary": "Requested changes; auto-merge stays off until they are fixed.",
      "applied_standards": [
        "api-error-format"
      ],
      "body": "**Request changes.** The attempt counter is never reset after a successful login, so a user who mistypes their password nine times is locked out on their next good attempt.",
      "created_at": "2026-10-22T14:20:05Z",
      "findings": [
        {
          "blocks": false,
          "body": "After a good password the counter for the IP stays where it was.",
          "category": "bug",
          "end_line": 44,
          "evidence": "verified-defect",
          "file": "src/auth/login.ts",
          "line": 42,
          "lookups": [],
          "severity": "high",
          "suggestion": "attempts.delete(ip);",
          "title": "The attempt counter is never reset after a successful login"
        }
      ],
      "head_sha": "9fceb02d0ae598e95dc970b74767f19372d61af8",
      "posted_as": "REQUEST_CHANGES",
      "pr_number": 318,
      "pr_title": "Rate-limit the login form",
      "rating_comments": [
        {
          "at": "2026-10-22T15:01:44+00:00",
          "by": "octocat",
          "rating": "up",
          "text": "Good catch on the counter."
        }
      ],
      "repo": "acme/web",
      "risk": "MEDIUM",
      "sk": "REVIEW#acme/web#318#2026-10-22T14:20:05Z",
      "thumbs_down": 0,
      "thumbs_up": 2,
      "trigger": "label",
      "verdict": "REQUEST_CHANGES"
    }
  ]
}
```
