Subcore AI Docs
Telemetry read API

Sessions

What a session actually is, how to list them, and how to read one conversation end to end.

A session is every event sharing a sid

This is the concept that trips people, so it is worth stating before the endpoints.

There is no session object. Nothing creates a session, nothing closes one, and there is no row you can fetch that is a session. A session is a view: every telemetry event carries a session id (sid), and a session is the set of all events that share one.

Three consequences follow, and all three surprise people at least once.

Reusing a session id appends to that conversation. It does not start a new one. If you pass the same id on ten unrelated calls, you have not made ten sessions — you have made one conversation with ten turns in it, and the agent will reason about the tenth turn in the context of the previous nine.

A session's timestamps are derived. first_at and last_at are the first and last event that carried the id, so a conversation that goes quiet for a day and then resumes is one session spanning that day, not two sessions.

A session cannot be empty. Listing sessions is a query over events, so an id with no events behind it does not appear anywhere.

The list_sessions and get_session MCP tools answer over exactly the same data, and the MCP session semantics are the write-side consequence of the same rule.

List sessions

GET /telemetry/sessions

One row per session, most recently active first.

Parameters

ParameterTypeDescription
coreSlugstringConfine to one agent. Omit to span every agent the key may read
channelstringvoice, sms, chat, email, …
runTypestringproduction is customer traffic, test is playground and MCP turns, eval is evaluation runs
fromISO 8601Sessions still active at or after this instant
toISO 8601Sessions that had already started by this instant
cursorstringnextCursor from the previous page
limitintegerPage size. Default 25, maximum 100

from and to select sessions that were active in the window, not sessions that started in it. from is compared against the session's last event and to against its first. So "yesterday's sessions" correctly includes a conversation that opened the evening before and was still running yesterday morning. A window filter on start time would have dropped it.

Response

{
  "items": [
    {
      "sid": "chat_01J9Z2K8QW",
      "core_slug": "support-agent",
      "channel": "chat",
      "run_type": "production",
      "first_at": "2026-09-03T14:02:11.418Z",
      "last_at": "2026-09-03T14:09:52.006Z",
      "event_count": 24
    }
  ],
  "nextCursor": null
}
FieldTypeDescription
sidstringThe session id. Pass it to GET /telemetry/sessions/{sid}
core_slugstringThe agent this conversation ran on
channelstring | nullThe channel it arrived through
run_typestring | nullproduction, test or eval
first_atstringTimestamp of the earliest event with this sid
last_atstringTimestamp of the latest
event_countintegerHow many events share this sid

Example

Production chat conversations on one agent, for one day:

curl -H "Authorization: Bearer $SUBCORE_API_KEY" \
  "https://api.subcore.ai/telemetry/sessions?\
coreSlug=support-agent&channel=chat&runType=production&\
from=2026-09-03T00:00:00Z&to=2026-09-04T00:00:00Z"

Get one session

GET /telemetry/sessions/{sid}

Every event of one conversation in the order it happened — the transcript plus the tool calls the agent made along the way.

Parameters

ParameterTypeDescription
sidpathThe session id
cursorstringnextCursor from the previous page
limitintegerPage size. Default 25, maximum 100

There is no coreSlug parameter: a sid already belongs to one core.

Response

{ items, nextCursor }, where each item is an event. The event fields are documented under events.

curl -H "Authorization: Bearer $SUBCORE_API_KEY" \
  "https://api.subcore.ai/telemetry/sessions/chat_01J9Z2K8QW?limit=100"

When it 404s

{ "error": "Session not found", "code": "NOT_FOUND", "timestamp": 1788566031707 }

You get a 404 when the organization has no events under that sid or when the key's permissions.cores does not reach the core that owns it. The two are deliberately indistinguishable: a key that cannot see a core should not be able to learn that the core has a session by that name.

An empty page reached past a cursor is not a 404. Once you are paging, a final empty page just means you have read everything; only a first request that matches nothing is treated as "no such session".

On this page