---
title: "The finished report as JSON plus plain text, paged over the per-page results (offset, limit) or, with failedOnly=true, over the failed pages alone; a failed or cancelled job reports the pages it compared"
method: GET
path: "/jobs/{id}/report"
---

# The finished report as JSON plus plain text, paged over the per-page results (offset, limit) or, with failedOnly=true, over the failed pages alone; a failed or cancelled job reports the pages it compared

`GET /jobs/{id}/report`

## Request

- Base URL: `https://app.difficat.com/api/v1`
- URL: `https://app.difficat.com/api/v1/jobs/{id}/report`
- Auth: one of:
  - HTTP bearer
  - HTTP bearer

## Path parameters

- `id` string, required

## Query parameters

- `failedOnly` boolean
- `view` 'full' | 'digest'
- `offset` integer
- `limit` integer

## Response `200`

OK

- Report
  - `jobId` string, required
  - `status` string, required
  - `cancelled` boolean
  - `summary` Summary: Totals, per-check pass/fail counts and issue counts by severity over every page of the job, whatever slice a report call returns.
    - `totalPages` integer, required
    - `totalDiscovered` integer: Pages discovery found, before any maxPages ceiling.
    - `passed` integer, required
    - `failed` integer, required
    - `duration` number: Seconds.
    - `startedAt` string, date-time
    - `completedAt` string, date-time
    - `byType` object, required: Pass and fail counts for the existence, content and visual checks.
      - `existence` object, required
        - `passed` integer, required
        - `failed` integer, required
      - `content` object, required
        - `passed` integer, required
        - `failed` integer, required
      - `visual` object, required
        - `passed` integer, required
        - `failed` integer, required
    - `issuesBySeverity` object: Issue counts over every page by severity, every key present: the verdict at a glance. Present on every job started after it was introduced.
      - `critical` integer
      - `high` integer
      - `medium` integer
    - `checkMode` 'text-only' | 'existence-only': The checks the job ran when fewer than all; absent on a full job. The byType counts of a check that did not run stay 0.
  - `results` union[]: The requested slice of the per-page results (existence, content and visual checks), in page order.
    - union
      - PageResult: One page of the job: the Site A URL and its Site B counterpart, the verdict, the three checks and the issues they raised.
        - `url` string, uri, required: The Site A page.
        - `targetUrl` string, uri: The Site B page compared against it.
        - `status` 'pass' | 'fail', required
        - `checks` object, required
          - `existence` object, required
            - `status` 'pass' | 'fail' | 'skip', required
            - `sourceStatus` integer: HTTP status of the Site A page.
            - `targetStatus` integer: HTTP status of the Site B page.
            - `blockedBy` object: Present when a side answered with a bot-protection challenge; status stays "fail".
              - …
            - `error` string: Why no status was obtained, e.g. "blocked hostname".
          - `content` object, required
            - `status` 'pass' | 'fail' | 'skip', required
            - `diffs` object[]: The fields whose text differs, with a short account of each side.
              - …
            - `bodyOverlap` number: Share of the body text the two sides have in common.
            - `reason` 'existence-failed' | 'browser-crashed' | 'timeout' | 'error' | 'not-requested': Why the check did not run; status is then "skip".
            - `errorMessage` string: What failed when the check errored.
          - `visual` object, required
            - `status` 'pass' | 'fail' | 'skip', required
            - `diffPercentage` number: Share of pixels that differ; the job threshold decides pass or fail.
            - `truncatedAt` integer: Present when the page was taller than 10,000 CSS px: only the first truncatedAt px were captured and compared. The content check always reads the whole page.
            - `regions` object[]: Where the page changed: groups of neighbouring 32 px cells holding differing pixels, boxed tight in screenshot px of the diff image (the larger screenshot, same top-left origin), most pixels first. Pass one as x, y, width and height to GET /jobs/{id}/files/{filename} to read only that area. Present whenever the pixels were compared; absent on a skip.
              - …
            - `regionCount` integer: Regions found on the page, before the list was cut.
            - `stability` object: Present when Site B was loaded a second time and compared with the first capture (failed visual checks on a live target, at most 30 per job).
              - …
            - `noisePixels` integer: Pixels in isolated specks left out of diffPercentage and the regions; present only when above zero.
            - `screenshots` object: PNG filenames for GET /jobs/{id}/files/{filename}.
              - …
            - `reason` 'existence-failed' | 'browser-crashed' | 'timeout' | 'error' | 'not-requested': Why the check did not run; status is then "skip".
            - `errorMessage` string: What failed when the check errored.
        - `changes` object[]: The page read as separate differences, derived from the checks when the report is read; empty for a page that passed.
          - `kind` 'missing' | 'text' | 'metadata' | 'visual', required
          - `fingerprint` string, required: Equal for the same difference on any page of the job: missing:<status>:<path>, text:<field>:<hash>, metadata:<field>:<hash>, visual:<selector> or visual:<x>,<y>,<w>,<h>.
          - `label` string, required: A short sentence naming the difference.
          - `field` string: The content field, for text and metadata changes.
          - `region` object
            - `x` integer, required: Left edge in screenshot px of the diff image.
            - `y` integer, required: Top edge in screenshot px of the diff image.
            - `width` integer, required: Width in screenshot px.
            - `height` integer, required: Height in screenshot px.
            - `pixels` integer, required: Differing pixels inside the region.
            - `share` number, required: The region's fraction of the page's differing pixels, to 4 decimals.
            - `selector` string: CSS selector of the smallest element on Site B containing the region centre, unique on the page; absent when no element could be named. Pass it in visual.masks to hide the element.
        - `issues` object[], required: Empty for a page that passed.
          - `type` 'missing-page' | 'content-diff' | 'visual-diff' | 'check-skipped', required
          - `severity` 'critical' | 'high' | 'medium', required: critical for a missing page; high for a visual difference or a robots diff where the target gains noindex or none; medium otherwise.
          - `description` string, required
          - `details` object: The check data behind the issue, by issue type.
      - DigestEntry
        - `url` string, required
        - `targetUrl` string
        - `status` 'pass' | 'fail', required
        - `failedChecks` string[], required: Checks whose status is fail; empty for a page whose only issue is check-skipped.
        - `issues` object[], required
          - `type` string, required
          - `severity` 'critical' | 'high' | 'medium', required
          - `description` string, required
        - `diffPercentage` number: Visual difference, from checks.visual.
        - `regions` object[]: The three largest regions of checks.visual.regions.
          - `x` integer, required: Left edge in screenshot px of the diff image.
          - `y` integer, required: Top edge in screenshot px of the diff image.
          - `width` integer, required: Width in screenshot px.
          - `height` integer, required: Height in screenshot px.
          - `pixels` integer, required: Differing pixels inside the region.
          - `share` number, required: The region's fraction of the page's differing pixels, to 4 decimals.
          - `selector` string: CSS selector of the smallest element on Site B containing the region centre, unique on the page; absent when no element could be named. Pass it in visual.masks to hide the element.
        - `regionCount` integer: Regions found on the page, before the list was cut.
        - `fingerprints` string[]: The fingerprint of each change on the page (see PageResult.changes).
        - `flakyShare` number: checks.visual.stability.flakyShare; 0.5 and above is likely the page moving on its own.
        - `screenshots` object: The page's PNG filenames, present beside non-empty regions so one can be cropped.
          - `source` string, required
          - `target` string, required
          - `diff` string, required
        - `bodyOverlap` number: Body text overlap, from checks.content.
        - `blockedBy` object: Present when a side answered with a bot-protection challenge.
          - `side` string
          - `vendor` string
        - `certificate` object: Per side, the certificate problem the unverified retry worked around; the status is unaffected.
          - `source` object
            - `problem` 'self-signed' | 'expired' | 'name-mismatch' | 'untrusted', required
            - `host` string, required
            - `loginSent` true
          - `target` object
            - `problem` 'self-signed' | 'expired' | 'name-mismatch' | 'untrusted', required
            - `host` string, required
            - `loginSent` true
        - `reason` string: The existence check error, cut to 200 characters.
        - `pairing` 'unrelated' | 'different-path': A failed page only: "unrelated" when bodyOverlap is above 0 and below 0.2 with title and h1 diffs non-empty on both sides, else "different-path" when the source and target paths differ. Check that the compared pages match.
  - `total` integer: Page results persisted for the job.
  - `nextOffset` integer: Offset of the slice after this one; absent on the last slice.
  - `text` string: The plain-text report (report.txt) over the slice; absent with view=digest.
  - `error` string: Present for a failed job, with its partial results.

## Other responses

- `401`: Missing job token
- `404`: Unknown job or wrong token
- `409`: Job still running

---

[API](https://skmtc.dev/difficat/apis/difficat-agent-api.md) · [All operations](https://skmtc.dev/difficat/apis/difficat-agent-api/llms.txt) · [OpenAPI document](https://skmtc.dev/difficat/apis/difficat-agent-api/revisions/49c291e77659?raw)
