---
title: "GET /audit/session-chain/{sessionId}"
description: "Verify a session's record chain"
full: true
---

**Auth:** required. Send an `ivy_` API key (`Authorization: Bearer ivy_…` or `X-Ivy-Api-Key`), a Clerk session JWT (`Authorization: Bearer …`) or the Clerk `__session` cookie (browser sessions). See [Authentication](/docs/api/authentication).

Re-checks the tamper-evident hash chain of one of your sessions, the record a signed-in `POST /orchestrate` call (curl, MCP or the terminal) leaves, and reports where, if anywhere, it stops matching. This is the `record.verify.api` link an orchestrate response returns. A broken chain is returned as a normal `200` with `status` set to `broken`; it is a verdict, not an error.

A session that does not exist, was deleted or is not yours answers `404`. Verification is limited per user, so repeated calls can return `429` with a `Retry-After` header. A deployment that writes session records this verifier cannot read yet answers `501`.

## Request

#### Path parameters

- `sessionId` (string (uuid)) —
Session UUID (the `sessionId` an orchestrate response returns).

## Responses

### `200` OK

Verification verdict for the session

Response shape:

- `sessionId` (string (uuid)) —

- `chainKind` (enum (&quot;session&quot;)) —

- `status` (enum (&quot;broken&quot; | &quot;no_record&quot; | &quot;not_verifiable&quot; | &quot;verified_partial&quot; | &quot;verified&quot;)) —
`verified`: every row matched. `verified_partial`: every checked row matched, but some could not be checked or no committed last event proves that no rows are missing from the end. `broken`: the chain stopped matching. `no_record`: the chat has no chained rows. `not_verifiable`: the chat could not be graded.

- `verified` (boolean) —
True only when `status` is `verified`.

- `checkedRows` (integer) —

- `notVerifiableRows` (integer) —

- `headHash` (string) —
Hash at the head of the partition holding the newest chained row.

- `firstBreakAt` (object) —

#### firstBreakAt properties

- `tenantId` (string) —

- `sequenceNumber` (integer) —
Sequence number of the first row that failed, when it maps to one. For `head-mismatch` (the record does not reach its committed last event, so rows at the end are missing or were rewritten) it is that committed last event's sequence number.

- `reason` (string) —

- `kind` (enum (&quot;discontinuous&quot; | &quot;hash-mismatch&quot; | &quot;head-mismatch&quot;)) —

- `actual` (string) —
The stored value that failed verification.

- `partitions` (object[]) —

- `partitionsTruncated` (boolean) —
True when the session has more partitions than are listed.

- `verifiedAt` (string (date-time)) —

- `keyed` (boolean) —
False when the chain was checked with plain SHA-256 because no deployment key is configured.

### `400` Bad Request

Invalid request

Response shape: `object`

### `401` Unauthorized

Authentication required

Response shape: `object`

### `404` Not Found

Resource not found

Response shape: `object`

### `429` Too Many Requests

Rate limit exceeded

Response shape: `object`

**curl**

```bash
curl -X GET 'https://ivybiosciences.com/api/audit/session-chain/{sessionId}' \
  -H "Authorization: Bearer $IVY_API_KEY"
```

**JavaScript**

```js
const res = await fetch('https://ivybiosciences.com/api/audit/session-chain/{sessionId}', {
  method: 'GET',
  headers: {
    'Authorization': `Bearer ${process.env.IVY_API_KEY}`,
  },
});
const data = await res.json();
```

**Python**

```python
import os, requests

res = requests.get(
    "https://ivybiosciences.com/api/audit/session-chain/{sessionId}",
    headers={"Authorization": f"Bearer {os.environ['IVY_API_KEY']}"},
)
data = res.json()
```
