# Look up a session later: verdict, evidence, identity and decisions

`GET /api/v1/sessions/{sessionId}` · operationId `getSession`

For developers: your server sends this request with a server key; it is not a button in the dashboard. To see the same information without code, open **Sessions** in the dashboard.

For a backend that stored the session ID with its own record (an exam attempt, an order) and checks it afterwards. Server key only, this Site only: another Site’s session, an unknown, erased or deleted one and one past retention are the same 404. Available while the session is kept: the Site’s session retention from its last activity (default 8 days, 1 to 400; at most 8 days after consent withdrawal). A read: it never extends the session or changes its verdict.

## Authentication

Send `Authorization: Bearer YOUR_SERVER_KEY` (siteServerKey: Site server key in Authorization: Bearer <key> (the scheme is case-insensitive and required; a bare key is 401). Shown once on creation or rotation. Publishable keys cannot authenticate). Keep the server key in server-only configuration; never send it to a browser.

## Parameters

- `sessionId` (path, string, required): The session ID the browser SDK returns (getSessionId()). A reference, not a credential.

## Responses

- **200**: Session · body `SessionLookup` · headers `Cache-Control`
- **400**: bad_request: the request is invalid; message says what to fix and field names the request field · body `Error`
- **401**: unauthorized (missing or invalid server key, missing Bearer scheme) · body `Error`
- **403**: forbidden: the call came from a browser page or another Site; call from your server with this Site’s server key · body `Error`
- **404**: not_found: nothing with this ID on this Site (or it is past retention), or an unknown path · body `Error`
- **429**: rate_limited: wait for Retry-After · body `Error` · headers `Retry-After`
- **500**: internal_error: fail the protected action; do not retry automatically · body `Error`
- **503**: service_unavailable: temporarily unavailable; only verify retries · body `Error`

### Success body fields

- `sessionId` (string, required) · pattern `^session_[A-Za-z0-9_-]{8,64}$`
- `status` ("active" | "ended" | "consent_withdrawn", required)
- `started` (number, required): Unix epoch milliseconds.
- `lastActivity` (number, required): Unix epoch milliseconds.
- `ended` (number | null, required): When the session expired (ended) or consent was withdrawn, if recorded; null while active.
- `verdict` ("human" | "agent" | "unknown", required): While active, the reading now (as /api/v1/verify computes it); once ended, the reading at the last activity, which is final; unknown after consent withdrawal. Unknown is not human.
- `actionVerdict` ("human" | "agent" | "unknown", required): The stricter verdict used for protection and billing. It differs from verdict only when the session is analytics-only: it counts as AI agent in reports, but the evidence is not strong enough to act on, so actionVerdict stays unknown.
- `verdictAt` (number | null, required): The time the verdict was read at (now, or the last activity); null after withdrawal.
- `agentEvidence` ("verified" | "automation-trace" | "injected-input" | "sustained-behaviour" | "behaviour-change" | "behaviour-corroborated" | "cursor-driven" | "behaviour" | null, required): What backs an AI agent action verdict; null otherwise. It sets the confidence band exactly as on verify: every value but behaviour is high confidence (follows the AI agent rule, Deny included, and is chargeable); behaviour (one behaviour family) is medium confidence (held for review by default, never chargeable).
- `agentEvidenceLabel` ("Verified" | "Strong evidence" | "Behaviour" | "Unknown", required): The label the dashboard shows for agentEvidence: Verified and Strong evidence are high confidence, Behaviour is medium confidence, Unknown means no AI agent action verdict.
- `everAgent` (boolean | null, required): Whether the action verdict ever read AI agent in this session; null after consent withdrawal (withheld).
- `agentFirstSeen` (number | null, required)
- `agentLastSeen` (number | null, required)
- `agent` (object | null, required): The named agent and how we know, only when evidence names one beside an AI agent verdict.
- `agent.name` (string, required)
- `agent.operator` (string | null, required)
- `agent.howWeKnow` (object, required)
- `agent.howWeKnow.strength` (string, required)
- `agent.howWeKnow.label` (string, required)
- `identity` (object | null, required)
- `identity.userId` (string | null, required)
- `identity.accountId` (string | null, required)
- `identity.verified` (boolean, required): true: asserted by your server (identify); false: a browser claim.
- `detectorVersion` (string | null, required): The classifier that produced the verdict (its name, such as heuristic-v4.33); null after withdrawal.
- `reasons` (string[], required)
- `decisions` (object[], required): Newest first, at most 100; GET /api/v1/decisions.json?sessionId= reads every one.
- `decisions[].decisionId` (string, required)
- `decisions[].actionId` (string, required) · pattern `^[A-Za-z0-9_-]{1,64}$`
- `decisions[].decision` ("allow" | "review" | "deny", required)
- `decisions[].purpose` ("protect" | "display", required)
- `decisions[].created` (number, required): Unix epoch milliseconds.
- `decisions[].outcome` ("performed" | "blocked" | "failed" | null, required)
- `decisions[].review` (string | null, required)
- `decisionsComplete` (boolean, required)
- `goals` (object[], required): What the session tried to do and whether it worked, one plain line each, newest first. Derived from tool runs, protected-action checks and their outcomes, work your server reported and refused tool calls; fixed templates, never page text. status is a category: succeeded, blocked, failed, waiting, abandoned or unconfirmed (no result reported, never counted as success).
- `goals[].actionId` (string, required)
- `goals[].label` (string, required)
- `goals[].status` ("succeeded" | "blocked" | "failed" | "waiting" | "abandoned" | "unconfirmed", required)
- `goals[].cause` (string, required)
- `goals[].line` (string, required)
- `goals[].attempts` (integer, required)
- `goals[].via` ("tool" | "protected" | "page" | "unknown"[], required)
- `goals[].httpStatus` (integer, optional)
- `goals[].firstAt` (number, required): Unix epoch milliseconds.
- `goals[].lastAt` (number, required): Unix epoch milliseconds.
- `goalSummary` (string | null, required): The top line: the one goal, or how many were tried and how they ended.
- `retainedUntil` (number, required): After this time the lookup is 404: from the last activity, the plan’s history period for a session with AI agent activity (never less than the session setting), else the Site’s session retention (default 8 days); at most 8 days after consent withdrawal.

Failures are not verdicts. Error bodies follow the `Error` schema: `code` is one of `bad_request`, `unauthorized`, `session_reinit_required`, `forbidden`, `not_found`, `conflict`, `identity_required`, `payload_too_large`, `rate_limited`, `internal_error`, `service_unavailable`, `request_failed`, `approval_invalid`, `approval_used`, `approval_expired`, `approval_mismatch`, `step_up_not_held`, `step_up_mismatch`, `step_up_settled`, `step_up_expired`, `step_up_superseded`, `agent_tokens_disabled`, `tool_not_approved`, `tool_not_read_only`. [Errors and retries](/docs/errors) explains each code and what to do.

## Example

```sh tab=curl
curl -sS -X GET 'https://app.trytelltale.dev/api/v1/sessions/session_PASTE_SESSION_ID' \
  -H "Authorization: Bearer $TELLTALE_SERVER_KEY"
```

```js tab=fetch
const response = await fetch("https://app.trytelltale.dev/api/v1/sessions/session_PASTE_SESSION_ID", {
  method: "GET",
  headers: {
    Authorization: 'Bearer ' + process.env.TELLTALE_SERVER_KEY
  },
  signal: AbortSignal.timeout(5000)
});
const result = await response.json();
```

Machine-readable contract: [openapi.json](https://app.trytelltale.dev/openapi.json). Request builder: the [API explorer](/docs/api-explorer) shows every operation as curl; it sends requests only on a local dashboard.
