# Verify the audit trail hash chain

Requires the `audit_log:verify` scope.

`GET /audit-trail/verify`

Scope `audit_log:verify` | Plan **Growth+**

Requires the `audit_log:verify` scope. Needs the `audit_trail` plan feature.

## Returns

The `data` field of the standard `{ data, error, meta }` envelope:

- `acceptedBreakCount`: integer Breaks excused by an approved exception.
- `acceptedBreaks`: array of object Accepted breaks, at most 200.
  - `acceptanceSeq`: integer Sequence number of the acceptance entry in the chain.
  - `approvedAt`: string When the exception was approved (RFC 3339).
  - `breakClass`: optional string manual or concurrent_append.
  - `exceptionId`: string Id of the approved exception.
  - `seqNum`: integer Sequence number of the excused entry.
  - No other fields.
- `breakCount`: integer Total chain breaks found.
- `breaks`: array of object Chain breaks, at most 200.
  - `detail`: string Fixed description of the break kind at this sequence number; never contains hashes.
  - `kind`: string prev_link_mismatch, hash_mismatch, duplicate_seq, corrupt, seq_gap, gap_unaccounted, exception_unused, exception_invalid, exception_missing or exception_superseded.
  - `seqNum`: integer Sequence number of the entry.
  - No other fields.
- `breaksTruncated`: boolean True when breaks lists only the first 200.
- `brokenAt`: optional integer or null Sequence number of the first break, when there is one.
- `chainedEntries`: integer Chained entries scanned.
- `effectiveBoundarySeq`: optional integer or null Sequence number from which strict verification applies.
- `exceptionBoundarySeq`: optional integer or null Highest sequence number covered by exception markers.
- `firstChainedSeq`: optional integer or null Sequence number of the first scanned chained entry.
- `legacyEntries`: integer Entries that predate the hash chain.
- `pendingEntries`: integer Entries recorded but not yet chained.
- `protocolV2Seq`: optional integer or null Sequence number where the current chain protocol starts.
- `scanComplete`: boolean False when the scan ran out of time budget; valid is then false and the counts are partial.
- `seqGapCount`: integer Jumps in the sequence numbering.
- `seqGaps`: array of object Sequence jumps, at most 200.
  - `after`: integer Last sequence number before the jump.
  - `next`: integer First sequence number after the jump.
  - No other fields.
- `totalEntries`: integer Entries in the audit trail.
- `valid`: boolean True when the scan completed and found no unaccepted break.
- `verifiedAt`: string (date-time) When the scan finished (UTC). Results are cached for 60 seconds per organization.
- No other fields.

## Errors

| Status | Code | Retry | Meaning |
|---|---|---|---|
| 400 | - | no | The request is invalid. |
| 401 | - | no | The token is missing, malformed, expired or revoked. |
| 402 | - | no | The organisation's plan does not include the feature this route needs. |
| 403 | - | no | The token may not use this route. |
| 429 | - | yes | Rate limit or row budget exceeded; retry after the time in Retry-After. |
| 500 | - | no | Unexpected server error. |
| 503 | - | yes | A dependency is temporarily unavailable; retry later. |

## Example

### curl

```bash
curl "https://api.autociso.io/api/v1/audit-trail/verify" \
  -H "Authorization: Bearer <your-api-token>"
```

### Python

```python
import requests

response = requests.get(
    "https://api.autociso.io/api/v1/audit-trail/verify",
    headers={"Authorization": "Bearer <your-api-token>"},
)
print(response.json())
```

### JavaScript

```javascript
const response = await fetch("https://api.autociso.io/api/v1/audit-trail/verify", {
  method: "GET",
  headers: { "Authorization": "Bearer <your-api-token>" },
});
console.log(await response.json());
```

## Response (200)

```json
{
  "data": {
    "acceptedBreakCount": 1,
    "acceptedBreaks": [
      {
        "acceptanceSeq": 7420,
        "approvedAt": "2026-09-02T12:00:00Z",
        "breakClass": "concurrent_append",
        "exceptionId": "6702a1f01f4e2b0012ab1203",
        "seqNum": 7311
      }
    ],
    "breakCount": 0,
    "breaks": [],
    "breaksTruncated": false,
    "brokenAt": null,
    "chainedEntries": 10140,
    "effectiveBoundarySeq": 7420,
    "exceptionBoundarySeq": 7420,
    "firstChainedSeq": 1,
    "legacyEntries": 341,
    "pendingEntries": 2,
    "protocolV2Seq": 6200,
    "scanComplete": true,
    "seqGapCount": 0,
    "seqGaps": [],
    "totalEntries": 10483,
    "valid": true,
    "verifiedAt": "2026-10-13T07:30:00Z"
  },
  "error": null
}
```
