---
title: "Read the review of an exception"
method: GET
path: "/reconciliation_exceptions/{id}/review"
---

# Read the review of an exception

`GET /reconciliation_exceptions/{id}/review`

## Request

- Base URL: `https://api.endclose.com/v1`
- URL: `https://api.endclose.com/v1/reconciliation_exceptions/{id}/review`
- Auth: API key in header `X-API-KEY`

Returns the exception's findings with each line's derived status, filtered and paged. Lines sort `to_look_at` first, then `looks_right`, then `done`; within a status, newest record date first. `sort` puts a column in front of that order.

## Path parameters

- `id` string, required

## Query parameters

- `status` 'all' | 'to_look_at' | 'looks_right' | 'done'
- `q` string
- `category` string[]
- `sort` 'date' | 'description' | 'category' | 'amount' | 'other_amount' | 'difference' | 'quantity' | 'other_quantity' | 'quantity_difference' | 'status'
- `dir` 'asc' | 'desc'
- `page` integer
- `per_page` integer

## Response `200`

A page of the review

- ReviewPage
  - `rows` ReviewRow[]
    - `record` ReconciliationEntry: A record's entry in one reconciliation. Match status, escalation, and matched records are all scoped to that reconciliation; a record has one entry per reconciliation it participates in. `id` is the record id.
      - `id` string, uuid
      - `amount` integer, required: The monetary amount in cents (e.g., 1234 = $12.34)
      - `currency` string: Three-letter ISO 4217 currency code (e.g. USD, EUR). **Optional on create — defaults to `USD` when omitted.** Case-insensitive on input; always returned uppercase.
      - `decimal_places` integer: Number of decimal places for this currency (2 for USD)
      - `direction` 'credit' | 'debit', required
      - `description` string
      - `date` string, date, required
      - `metadata` object
      - `external_id` string
      - `data_stream_key` string, required
      - `reconciliation_id` string, uuid
      - `reconciliation_name` string
      - `status` 'reconciled' | 'unreconciled': Whether the record is matched in this reconciliation. Read-only.
      - `escalated` boolean: Unmatched and past its `overdue_at`.
      - `overdue_at` string, date-time, nullable
      - `matched_records` object[]: Records matched with this record in this reconciliation
        - `id` string, uuid
        - `amount` integer: Amount in cents
        - `currency` string: Three-letter ISO 4217 currency code (e.g. USD, EUR)
        - `decimal_places` integer
        - `direction` 'credit' | 'debit'
        - `description` string
        - `date` string, date
        - `external_id` string
        - `data_stream_key` string
        - `reconciliation_id` string, uuid: The reconciliation in which this match was made
        - `reconciliation_name` string: Name of the reconciliation in which this match was made
      - `days_unreconciled` integer, nullable: Number of days since the record's date. Null when the record is reconciled.
      - `exception_id` string, uuid, nullable: Open exception covering this entry's data stream when the entry is escalated. Null otherwise.
    - `finding` Finding: A stored finding: the `FindingInput` fields as saved, plus provenance.
      - `id` string
      - `record_id` string
      - `looks_right` boolean
      - `note` string
      - `suggestion` object: As `FindingInput.suggestion`, with `record_ids` resolved to record ids and `difference_cents` recomputed.
      - `evidence` object[]: As `FindingInput.evidence`, each quote with the `check` End Close ran against its document.
        - `quote` string
        - `source` string, nullable
        - `url` string, nullable
        - `check` object: Whether the document says what the quote says. Written by End Close shortly after the finding, for quotes whose `url` is a PDF in Files.
          - `status` 'pending' | 'found' | 'found_elsewhere' | 'not_found' | 'no_text' | 'no_document' | 'external' | 'unsupported' | 'unreadable': `pending`: not checked yet. `found`: on the page the `url` names (or anywhere, if it names none). `found_elsewhere`: in the document, on `page` rather than the cited one. `not_found`: not in the document as quoted. `no_text`: the PDF has no text to search, such as a scan. `no_document`: the quote has no `url`. `external`: the `url` isn't a file in Files. `unsupported`: the file isn't a PDF. `unreadable`: the PDF can't be read.
          - `page` integer: The page the quote is on, from 1. Present when `found` or `found_elsewhere`.
          - `boxes` object[]: Where the quote is on `page`: one box per line, each as fractions of the page's width and height from its top-left corner.
            - `left` number
            - `top` number
            - `width` number
            - `height` number
          - `checked_at` string, date-time
      - `precedent` string, nullable
      - `other_side` object: What the other column shows: `{ amount_cents, count, record_ids }` derived from the suggested records on the opposite side, or `{}`. `count` is the sum of those records' counts (`metadata.quantity`, `qty`, `count`, `event_qty` or `units`, first present) and is only there when one of them carries one. You may send `amount_cents` and `count` yourself; a `count` you leave out is still derived.
      - `category` string, nullable
      - `labels` object
      - `source` 'api' | 'agent': `api` when written through this API; `agent` when written by End Close's own review.
      - `created_at` string, date-time
    - `status` 'to_look_at' | 'looks_right' | 'done': Derived on read: `done` once the record is matched, else `looks_right` or `to_look_at` from the finding.
    - `difference_cents` integer: |this line's amount| − |finding.other_side.amount_cents|, in cents. Zero when nothing was found on the other side.
    - `quantity` number, nullable: The line's count, read from the record's `metadata.quantity`, `qty`, `count`, `event_qty` or `units` (first present). Null when the record carries none.
    - `other_quantity` number, nullable: `finding.other_side.count`, or null.
    - `quantity_difference` number, nullable: `quantity` − `other_quantity`; null unless both sides carry a count.
  - `counts` ReviewCounts: Counts of review lines by status. A line is `done` once its record is matched, `looks_right` when its finding says so and it is not yet matched, and `to_look_at` otherwise.
    - `all` integer
    - `to_look_at` integer
    - `looks_right` integer
    - `done` integer
  - `categories` object[]: Every finding category on the exception with how many lines carry it, most common first — counted over the whole exception, not the current filter.
    - `name` string
    - `count` integer
  - `page` integer
  - `per_page` integer
  - `total` integer: Rows matching the current `status`, `category` and `q` filters.
  - `sides` object: `{ a: { data_stream_id, name }, b: { data_stream_id, name } }`
  - `row_side` 'a' | 'b': Which side the exception's lines are on.
  - `pending_notes` integer: Overdue lines of this exception that have no finding yet.
  - `notes_state` 'writing' | 'failed' | 'off' | 'idle': Why `pending_notes` lines have no finding. `writing`: a `row_review` session is queued or running. `failed`: the latest `row_review` session failed or died mid-run. `off`: End Close's row review isn't enabled for this account (this wins over any earlier run), so only findings you post through `PUT /reconciliation_exceptions/{id}/findings` appear. `idle`: no run is in flight.

## Other responses

- `401`: Unauthorized
- `404`: Exception not found
- `422`: The exception's data stream is no longer on the reconciliation

## Changes

- **2026-10-30** `f1074e68bb01`: 4 info
  - added the optional property `rows/items/finding/evidence/items/check` to the response with the `200` status
  - added the optional property `rows/items/finding/evidence/items/quote` to the response with the `200` status
  - added the optional property `rows/items/finding/evidence/items/source` to the response with the `200` status
  - added the optional property `rows/items/finding/evidence/items/url` to the response with the `200` status
- **2026-10-29** `159f9ed3dbf4`: 5 breaking
  - the `rows/items/record/allOf[#/components/schemas/ReconciliationEntry]/allOf[#/components/schemas/Record]/id` response's property type changed from `integer` to `string`, and format from no format to `uuid` for status `200`
  - the `rows/items/record/allOf[#/components/schemas/ReconciliationEntry]/allOf[subschema #2]/exception_id` response's property type changed from `integer` to `string`, and format from no format to `uuid` for status `200`
  - the `rows/items/record/allOf[#/components/schemas/ReconciliationEntry]/allOf[subschema #2]/matched_records/items/id` response's property type changed from `integer` to `string`, and format from no format to `uuid` for status `200`
  - the `rows/items/record/allOf[#/components/schemas/ReconciliationEntry]/allOf[subschema #2]/matched_records/items/reconciliation_id` response's property type changed from `integer` to `string`, and format from no format to `uuid` for status `200`
  - …1 more
- …earlier changes not shown

[Operation history](https://skmtc.dev/endclose/apis/end-close-api/changes/reconciliation_exceptions/:id/review/get.md)

---

[API](https://skmtc.dev/endclose/apis/end-close-api.md) - [All operations](https://skmtc.dev/endclose/apis/end-close-api/llms.txt) - [OpenAPI document](https://skmtc.dev/endclose/apis/end-close-api/revisions/dfe0fde00f12?raw)
