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/sessionsOne row per session, most recently active first.
Parameters
| Parameter | Type | Description |
|---|---|---|
coreSlug | string | Confine to one agent. Omit to span every agent the key may read |
channel | string | voice, sms, chat, email, … |
runType | string | production is customer traffic, test is playground and MCP turns, eval is evaluation runs |
from | ISO 8601 | Sessions still active at or after this instant |
to | ISO 8601 | Sessions that had already started by this instant |
cursor | string | nextCursor from the previous page |
limit | integer | Page 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
}| Field | Type | Description |
|---|---|---|
sid | string | The session id. Pass it to GET /telemetry/sessions/{sid} |
core_slug | string | The agent this conversation ran on |
channel | string | null | The channel it arrived through |
run_type | string | null | production, test or eval |
first_at | string | Timestamp of the earliest event with this sid |
last_at | string | Timestamp of the latest |
event_count | integer | How 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
| Parameter | Type | Description |
|---|---|---|
sid | path | The session id |
cursor | string | nextCursor from the previous page |
limit | integer | Page 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".