# Findings API

> The latest result of each legal check for a site, with citations, evidence references and remediation.

| Operation | Endpoint |
|---|---|
| [List findings](#listFindings) | `GET /v1/findings` |
| [Retrieve a finding](#retrieveFinding) | `GET /v1/findings/{finding}` |
| [Triage a finding](#updateFinding) | `POST /v1/findings/{finding}` |

## The Finding object

The latest result of one legal check for a site.

| Field | Type | Description |
|---|---|---|
| `id` | string | Unique identifier of the finding (fnd_…). |
| `object` | enum | String representing the object's type. Always "finding". |
| `livemode` | boolean | true for live-mode objects, false for test mode (ck_test_ keys act on an isolated sandbox). |
| `site` | string | The site. |
| `check_id` | string | Stable id of the legal check. |
| `title` | string | Short title. |
| `detail` | string | What was observed. |
| `stage` | enum | Lifecycle stage. One of `signup`, `confirmation`, `reminder`, `cancellation`, `config`. |
| `severity` | enum | Strictest severity among the applicable requirements. One of `critical`, `high`, `medium`, `low`. |
| `status` | enum | Latest check result. One of `pass`, `fail`, `needs_review`, `not_applicable`. |
| `state` | enum | Triage state. One of `open`, `acknowledged`, `resolved`, `accepted_risk`. |
| `note` | string \| null | Triage note. |
| `jurisdictions` | array of enum | Jurisdictions whose laws this check applies. |
| `requirements` | array of RequirementRefs | The legal requirements behind the check, with citations. |
| `remediation` | Remediation \| null | How to fix the finding (see also the fixes resource and compliance plans). |
| `confidence` | number | Confidence 0-1 of the check result. |
| `evidence_refs` | array of strings | Ids of the captures / emails / evidence records supporting the result. |
| `details` | object | Check-specific details (failing regions/devices/URLs, measurements, quotes). |
| `evidence` | VerdictEvidence | What a verdict was based on. Never a pass without it; needs_review says what is missing. |
| `compliance_status` | enum | User-facing status. needs_fix (a requirement is clearly not met: `compliance.fix` is the one change), pending_live_check (everything Checkbox can see is right; the live event has not been observed yet — counts as compliant), verified_live (observed live: proof run, real BCC'd send, Stripe-confirmed cancellation), your_call (a real decision for a person: `compliance.question`), compliant (passes; grey areas carry a `compliance.note`), not_applicable, not_set_up (no sign the email or setting exists yet: `compliance.fix` is the one-click way to set it up; never counts as compliant), not_checked (Checkbox has not tried it yet, e.g. the cancel flow: `compliance.fix` says how; never counts as compliant). One of `needs_fix`, `pending_live_check`, `verified_live`, `your_call`, `compliant`, `not_applicable`, `not_set_up`, `not_checked`. |
| `compliance` | ComplianceInfo | What a person should do about one check (the user-facing layer over `status`). |
| `scan` | string \| null | Scan that produced the latest result. |
| `first_seen` | integer | First time the check was evaluated. Unix timestamp in seconds. |
| `last_seen` | integer | Latest evaluation. Unix timestamp in seconds. |
| `resolved_at` | integer \| null | When it was resolved. Unix timestamp in seconds. |

## List findings {#listFindings}

`GET /v1/findings`

Findings ordered by urgency (failing first, then by severity). Filter by site, status (fail, needs_review, pass, not_applicable) and state (open, acknowledged, resolved, accepted_risk). Fix the open `fail` findings to become compliant.

**Scope** `findings:read` · **Operation** `listFindings`

SDK: `checkbox.findings.list()` (Node) · `checkbox.findings.list()` (Python). MCP / agents: operation `listFindings`.

#### Parameters

| Parameter | In | Type | Description |
|---|---|---|---|
| `limit` | query | integer | Number of objects to return, 1-100 (default 10). |
| `starting_after` | query | string | Cursor: an object id; returns the objects after it (older). |
| `ending_before` | query | string | Cursor: an object id; returns the objects before it (newer). |
| `site` | query | string | Only objects of this site (site_…). |
| `status` | query | enum | Only this check status. One of `pass`, `fail`, `needs_review`, `not_applicable`. |
| `state` | query | enum | Only this triage state. One of `open`, `acknowledged`, `resolved`, `accepted_risk`. |

#### Returns

Returns a list (`{ object: "list", data, has_more, url }`) of [Finding](https://checkbox.site/docs/api/findings#the-finding-object) objects.

Errors use the [standard envelope](https://checkbox.site/docs/api/errors) with a stable `code` and, where useful, `next_action`.

```curl
curl -G https://app.checkbox.site/v1/findings \
  -u "$CHECKBOX_SECRET_KEY:" \
  -d limit=3
```
```node
import Checkbox from '@checkbox-site/node';

const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);

const findings = await checkbox.findings.list({ limit: 3 });
console.log(findings.data);
```
```python
import os
from checkbox import Checkbox

checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])

findings = checkbox.findings.list(limit=3)
print(findings.data)
```

```json title="Response"
{
  "object": "list",
  "data": [
    {
      "id": "fnd_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
      "object": "finding",
      "livemode": false,
      "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
      "check_id": "signup.disclosure_clear_conspicuous",
      "title": "Auto-renewal terms are not shown before purchase",
      "detail": "The checkout page in US-CA (mobile) shows no renewal terms near the subscribe button.",
      "stage": "signup",
      "severity": "high",
      "status": "fail",
      "state": "open",
      "note": null,
      "jurisdictions": [
        "US-CA"
      ],
      "requirements": [
        {
          "id": "US-CA.17602.a.1",
          "jurisdiction": "US-CA",
          "citation": "Cal. Bus. & Prof. Code § 17602(a)(1)",
          "title": "Clear and conspicuous auto-renewal terms before purchase",
          "source_url": "https://leginfo.legislature.ca.gov/…"
        }
      ],
      "remediation": {
        "summary": "Show the auto-renewal terms next to the subscribe button.",
        "steps": [
          "Add the disclosure above the button"
        ],
        "platform": "stripe",
        "suggested_copy": "Your subscription renews automatically every month at $9.99 until you cancel.",
        "snippet": {
          "language": "html",
          "code": "<p class=\"renewal-terms\">…</p>"
        }
      },
      "confidence": 0.9,
      "evidence_refs": [],
      "details": {
        "failingRegions": [
          "US-CA"
        ]
      },
      "evidence": {
        "summary": "The checkout says “every week”, but the plan is billed every 2 weeks.",
        "items": [
          {
            "source": "page",
            "ref": "cap_123",
            "url": "https://shop.example/checkout",
            "quote": "renews automatically every month at $19.99 until you cancel",
            "selector": "form > p.terms",
            "rect": {},
            "field": "cancellation.selfServeOnline",
            "value": true,
            "label": "US-CA desktop",
            "status": "fail",
            "detail": "no statement that the subscription renews automatically",
            "screenshot_ref": "ev_123",
            "at": "2026-11-01T10:00:00.000Z"
          }
        ],
        "missing": "A test cancellation, or a captured account page with the cancel option."
      },
      "compliance_status": "pending_live_check",
      "compliance": {
        "status": "pending_live_check",
        "label": "Looks compliant — live check pending",
        "reason": "template_only",
        "tier": "required",
        "fix": "Add \"until you cancel\" to the renewal line.",
        "note": null,
        "pending_live_check": {
          "what": "Your acknowledgment email, seen sent for a real sign-up",
          "completes": "Run a proof, or BCC your real acknowledgment emails to your Checkbox inbound address.",
          "action": "bcc_real_sends",
          "due": "2026-11-20"
        },
        "question": {
          "text": "Your terms include a notice period. Keep it?",
          "recommended": "Remove it: let subscribers cancel online any time.",
          "why": "Commitments are legal in some states only when disclosed and agreed to."
        }
      },
      "scan": "scan_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
      "first_seen": 1793318400,
      "last_seen": 1793318400,
      "resolved_at": 1793318400
    }
  ],
  "has_more": false,
  "url": "/v1/sites"
}
```

## Retrieve a finding {#retrieveFinding}

`GET /v1/findings/{finding}`

One finding with its legal requirements (citations), evidence references and remediation.

**Scope** `findings:read` · **Operation** `retrieveFinding`

SDK: `checkbox.findings.retrieve()` (Node) · `checkbox.findings.retrieve()` (Python). MCP / agents: operation `retrieveFinding`.

#### Parameters

| Parameter | In | Type | Description |
|---|---|---|---|
| `finding` **required** | path | string | Unique identifier of the finding (fnd_…). |

#### Returns

Returns a [Finding](https://checkbox.site/docs/api/findings#the-finding-object) object.

Errors use the [standard envelope](https://checkbox.site/docs/api/errors) with a stable `code` and, where useful, `next_action`.

```curl
curl https://app.checkbox.site/v1/findings/fnd_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b \
  -u "$CHECKBOX_SECRET_KEY:"
```
```node
import Checkbox from '@checkbox-site/node';

const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);

const finding = await checkbox.findings.retrieve('fnd_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b');
console.log(finding);
```
```python
import os
from checkbox import Checkbox

checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])

finding = checkbox.findings.retrieve("fnd_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b")
print(finding)
```

```json title="Response"
{
  "id": "fnd_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "object": "finding",
  "livemode": false,
  "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "check_id": "signup.disclosure_clear_conspicuous",
  "title": "Auto-renewal terms are not shown before purchase",
  "detail": "The checkout page in US-CA (mobile) shows no renewal terms near the subscribe button.",
  "stage": "signup",
  "severity": "high",
  "status": "fail",
  "state": "open",
  "note": null,
  "jurisdictions": [
    "US-CA",
    "US-NY"
  ],
  "requirements": [
    {
      "id": "US-CA.17602.a.1",
      "jurisdiction": "US-CA",
      "citation": "Cal. Bus. & Prof. Code § 17602(a)(1)",
      "title": "Clear and conspicuous auto-renewal terms before purchase",
      "source_url": "https://leginfo.legislature.ca.gov/…"
    }
  ],
  "remediation": {
    "summary": "Show the auto-renewal terms next to the subscribe button.",
    "steps": [
      "Add the disclosure above the button"
    ],
    "platform": "stripe",
    "suggested_copy": "Your subscription renews automatically every month at $9.99 until you cancel.",
    "snippet": {
      "language": "html",
      "code": "<p class=\"renewal-terms\">…</p>"
    }
  },
  "confidence": 0.9,
  "evidence_refs": [],
  "details": {
    "failingRegions": [
      "US-CA"
    ]
  },
  "evidence": {
    "summary": "The checkout says “every week”, but the plan is billed every 2 weeks.",
    "items": [
      {
        "source": "page",
        "ref": "cap_123",
        "url": "https://shop.example/checkout",
        "quote": "renews automatically every month at $19.99 until you cancel",
        "selector": "form > p.terms",
        "rect": {
          "x": 680,
          "y": 592,
          "width": 480,
          "height": 63
        },
        "field": "cancellation.selfServeOnline",
        "value": true,
        "label": "US-CA desktop",
        "status": "fail",
        "detail": "no statement that the subscription renews automatically",
        "screenshot_ref": "ev_123",
        "at": "2026-11-01T10:00:00.000Z"
      }
    ],
    "missing": "A test cancellation, or a captured account page with the cancel option."
  },
  "compliance_status": "pending_live_check",
  "compliance": {
    "status": "pending_live_check",
    "label": "Looks compliant — live check pending",
    "reason": "template_only",
    "tier": "required",
    "fix": "Add \"until you cancel\" to the renewal line.",
    "note": null,
    "pending_live_check": {
      "what": "Your acknowledgment email, seen sent for a real sign-up",
      "completes": "Run a proof, or BCC your real acknowledgment emails to your Checkbox inbound address.",
      "action": "bcc_real_sends",
      "due": "2026-11-20"
    },
    "question": {
      "text": "Your terms include a notice period. Keep it?",
      "recommended": "Remove it: let subscribers cancel online any time.",
      "why": "Commitments are legal in some states only when disclosed and agreed to."
    }
  },
  "scan": "scan_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "first_seen": 1793318400,
  "last_seen": 1793318400,
  "resolved_at": 1793318400
}
```

## Triage a finding {#updateFinding}

`POST /v1/findings/{finding}`

Sets the triage state (open, acknowledged, accepted_risk, resolved) and an optional note. Triage does not change the check result; fixing the issue and re-scanning does.

**Scope** `findings:write` · **Idempotent** (send `Idempotency-Key`) · **Operation** `updateFinding`

SDK: `checkbox.findings.update()` (Node) · `checkbox.findings.update()` (Python). MCP / agents: operation `updateFinding`.

#### Parameters

| Parameter | In | Type | Description |
|---|---|---|---|
| `finding` **required** | path | string | Unique identifier of the finding (fnd_…). |

#### Body

| Field | Type | Description |
|---|---|---|
| `state` **required** | enum | New triage state. One of `open`, `acknowledged`, `resolved`, `accepted_risk`. |
| `note` | string | Why (kept with the finding). |

#### Returns

Returns a [Finding](https://checkbox.site/docs/api/findings#the-finding-object) object.

Errors use the [standard envelope](https://checkbox.site/docs/api/errors) with a stable `code` and, where useful, `next_action`.

```curl
curl https://app.checkbox.site/v1/findings/fnd_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b \
  -u "$CHECKBOX_SECRET_KEY:" \
  -H "Content-Type: application/json" \
  -d '{
  "state": "acknowledged"
}'
```
```node
import Checkbox from '@checkbox-site/node';

const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);

const finding = await checkbox.findings.update('fnd_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b', { state: 'acknowledged' });
console.log(finding);
```
```python
import os
from checkbox import Checkbox

checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])

finding = checkbox.findings.update("fnd_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b", state="acknowledged")
print(finding)
```

```json title="Response"
{
  "id": "fnd_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "object": "finding",
  "livemode": false,
  "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "check_id": "signup.disclosure_clear_conspicuous",
  "title": "Auto-renewal terms are not shown before purchase",
  "detail": "The checkout page in US-CA (mobile) shows no renewal terms near the subscribe button.",
  "stage": "signup",
  "severity": "high",
  "status": "fail",
  "state": "open",
  "note": null,
  "jurisdictions": [
    "US-CA",
    "US-NY"
  ],
  "requirements": [
    {
      "id": "US-CA.17602.a.1",
      "jurisdiction": "US-CA",
      "citation": "Cal. Bus. & Prof. Code § 17602(a)(1)",
      "title": "Clear and conspicuous auto-renewal terms before purchase",
      "source_url": "https://leginfo.legislature.ca.gov/…"
    }
  ],
  "remediation": {
    "summary": "Show the auto-renewal terms next to the subscribe button.",
    "steps": [
      "Add the disclosure above the button"
    ],
    "platform": "stripe",
    "suggested_copy": "Your subscription renews automatically every month at $9.99 until you cancel.",
    "snippet": {
      "language": "html",
      "code": "<p class=\"renewal-terms\">…</p>"
    }
  },
  "confidence": 0.9,
  "evidence_refs": [],
  "details": {
    "failingRegions": [
      "US-CA"
    ]
  },
  "evidence": {
    "summary": "The checkout says “every week”, but the plan is billed every 2 weeks.",
    "items": [
      {
        "source": "page",
        "ref": "cap_123",
        "url": "https://shop.example/checkout",
        "quote": "renews automatically every month at $19.99 until you cancel",
        "selector": "form > p.terms",
        "rect": {
          "x": 680,
          "y": 592,
          "width": 480,
          "height": 63
        },
        "field": "cancellation.selfServeOnline",
        "value": true,
        "label": "US-CA desktop",
        "status": "fail",
        "detail": "no statement that the subscription renews automatically",
        "screenshot_ref": "ev_123",
        "at": "2026-11-01T10:00:00.000Z"
      }
    ],
    "missing": "A test cancellation, or a captured account page with the cancel option."
  },
  "compliance_status": "pending_live_check",
  "compliance": {
    "status": "pending_live_check",
    "label": "Looks compliant — live check pending",
    "reason": "template_only",
    "tier": "required",
    "fix": "Add \"until you cancel\" to the renewal line.",
    "note": null,
    "pending_live_check": {
      "what": "Your acknowledgment email, seen sent for a real sign-up",
      "completes": "Run a proof, or BCC your real acknowledgment emails to your Checkbox inbound address.",
      "action": "bcc_real_sends",
      "due": "2026-11-20"
    },
    "question": {
      "text": "Your terms include a notice period. Keep it?",
      "recommended": "Remove it: let subscribers cancel online any time.",
      "why": "Commitments are legal in some states only when disclosed and agreed to."
    }
  },
  "scan": "scan_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "first_seen": 1793318400,
  "last_seen": 1793318400,
  "resolved_at": 1793318400
}
```
