# Evidence API

> The tamper-evident evidence vault behind every finding: screenshots, HTML, emails, platform configuration, evaluations.

| Operation | Endpoint |
|---|---|
| [List evidence](#listEvidence) | `GET /v1/evidence` |
| [Retrieve evidence metadata](#retrieveEvidence) | `GET /v1/evidence/{evidence}` |
| [Download evidence content](#downloadEvidenceContent) | `GET /v1/evidence/{evidence}/content` |
| [Verify the evidence chain](#verifyEvidenceChain) | `POST /v1/sites/{site}/evidence/verify` |

## The Evidence object

A record in the tamper-evident evidence vault.

| Field | Type | Description |
|---|---|---|
| `id` | string | Unique identifier of the evidence (ev_…). |
| `object` | enum | String representing the object's type. Always "evidence". |
| `livemode` | boolean | true for live-mode objects, false for test mode (ck_test_ keys act on an isolated sandbox). |
| `site` | string | Site the evidence belongs to. |
| `kind` | enum | What was recorded. One of `screenshot`, `html`, `page_capture`, `email_raw`, `platform_config`, `lifecycle_event`, `evaluation`. |
| `content_type` | string | MIME type of the content. |
| `size` | integer | Bytes. |
| `sha256` | string | SHA-256 of the content (hex). |
| `chain_hash` | string | Hash chaining this record to the previous one (tamper evidence). |
| `prev_chain_hash` | string \| null | Chain hash of the previous record. |
| `stored` | integer | When it was stored. Unix timestamp in seconds. |
| `meta` | object | Capture metadata (URL, region, device, scan…). |
| `content_url` | string | Download the raw content (downloadEvidenceContent, same auth). |

## List evidence {#listEvidence}

`GET /v1/evidence`

Evidence records of a site, newest first. Use downloadEvidenceContent for the raw bytes.

**Scope** `evidence:read` · **Operation** `listEvidence`

SDK: `checkbox.evidence.list()` (Node) · `checkbox.evidence.list()` (Python). MCP / agents: operation `listEvidence`.

#### 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` **required** | query | string | Site (site_…). Required. |
| `kind` | query | enum | Only this kind. One of `screenshot`, `html`, `page_capture`, `email_raw`, `platform_config`, `lifecycle_event`, `evaluation`. |

#### Returns

Returns a list (`{ object: "list", data, has_more, url }`) of [Evidence](https://checkbox.site/docs/api/evidence#the-evidence-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/evidence \
  -u "$CHECKBOX_SECRET_KEY:" \
  -d site=site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b \
  -d limit=3
```
```node
import Checkbox from '@checkbox-site/cli';

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

const evidence = await checkbox.evidence.list({ site: 'site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b', limit: 3 });
console.log(evidence.data);
```
```python
import os
from checkbox import Checkbox

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

evidence = checkbox.evidence.list(site="site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b", limit=3)
print(evidence.data)
```

```json title="Response"
{
  "object": "list",
  "data": [
    {
      "id": "ev_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
      "object": "evidence",
      "livemode": false,
      "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
      "kind": "screenshot",
      "content_type": "image/png",
      "size": 183204,
      "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
      "chain_hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
      "prev_chain_hash": null,
      "stored": 1793318400,
      "meta": {
        "url": "https://acme.example/pricing",
        "region": "US-CA"
      },
      "content_url": "/v1/evidence/ev_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/content"
    }
  ],
  "has_more": false,
  "url": "/v1/sites"
}
```

## Retrieve evidence metadata {#retrieveEvidence}

`GET /v1/evidence/{evidence}`

One evidence record (hashes, metadata, content URL).

**Scope** `evidence:read` · **Operation** `retrieveEvidence`

SDK: `checkbox.evidence.retrieve()` (Node) · `checkbox.evidence.retrieve()` (Python). MCP / agents: operation `retrieveEvidence`.

#### Parameters

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

#### Returns

Returns an [Evidence](https://checkbox.site/docs/api/evidence#the-evidence-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/evidence/ev_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b \
  -u "$CHECKBOX_SECRET_KEY:"
```
```node
import Checkbox from '@checkbox-site/cli';

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

const evidence = await checkbox.evidence.retrieve('ev_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b');
console.log(evidence);
```
```python
import os
from checkbox import Checkbox

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

evidence = checkbox.evidence.retrieve("ev_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b")
print(evidence)
```

```json title="Response"
{
  "id": "ev_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "object": "evidence",
  "livemode": false,
  "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "kind": "screenshot",
  "content_type": "image/png",
  "size": 183204,
  "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
  "chain_hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
  "prev_chain_hash": null,
  "stored": 1793318400,
  "meta": {
    "url": "https://acme.example/pricing",
    "region": "US-CA"
  },
  "content_url": "/v1/evidence/ev_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/content"
}
```

## Download evidence content {#downloadEvidenceContent}

`GET /v1/evidence/{evidence}/content`

The raw stored bytes (screenshot, HTML, raw email…). The X-Evidence-Sha256 header carries the hash to check.

**Scope** `evidence:read` · **Operation** `downloadEvidenceContent`

SDK: `checkbox.evidence.downloadContent()` (Node) · `checkbox.evidence.download_content()` (Python). MCP / agents: operation `downloadEvidenceContent`.

#### Parameters

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

#### Returns

Returns the file (`application/octet-stream`).

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/evidence/ev_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/content \
  -u "$CHECKBOX_SECRET_KEY:"
```
```node
import Checkbox from '@checkbox-site/cli';

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

const file = await checkbox.evidence.downloadContent('ev_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b');
console.log(file);
```
```python
import os
from checkbox import Checkbox

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

evidence = checkbox.evidence.download_content("ev_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b")
print(evidence)
```

## Verify the evidence chain {#verifyEvidenceChain}

`POST /v1/sites/{site}/evidence/verify`

Re-reads and re-hashes every evidence record of the site and checks the hash chain and signed anchors.

**Scope** `evidence:read` · **Operation** `verifyEvidenceChain`

SDK: `checkbox.evidence.verifyChain()` (Node) · `checkbox.evidence.verify_chain()` (Python). MCP / agents: operation `verifyEvidenceChain`.

#### Parameters

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

#### Returns

Returns an `EvidenceChainVerification` 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/sites/site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/evidence/verify \
  -u "$CHECKBOX_SECRET_KEY:" \
  -H "Content-Type: application/json" \
  -d '{}'
```
```node
import Checkbox from '@checkbox-site/cli';

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

const evidence = await checkbox.evidence.verifyChain('site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b');
console.log(evidence);
```
```python
import os
from checkbox import Checkbox

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

evidence = checkbox.evidence.verify_chain("site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b")
print(evidence)
```

```json title="Response"
{
  "object": "evidence_chain_verification",
  "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "ok": true,
  "checked": 128,
  "broken_at": null,
  "reason": null,
  "head": "9f86d0…"
}
```
