Sessions
A session is one ongoing conversation between an agent and one contact on one channel: a customer in your Telegram group, a colleague in Slack, a caller on WhatsApp. The project’s runtime keeps every session’s transcript so the agent can carry context from message to message and so you can review what was said.
Sessions belong to a project. Any active member of the project can view them.
Today, sessions are viewed in the Console by signed-in members and are not available through API keys. In an agent loop you write yourself, the “session” is simply the messages array you send with each request, and storing it is up to you. A Sessions API is being built; its design is in Sessions API below.
What a session shows
| Field | Meaning |
|---|---|
| ID | The session’s identifier. Use it to filter executions and to pick a session in Live activity. |
| Channel | The service the conversation happens on, such as telegram, slack or whatsapp. |
| Contact | Who the agent is talking to: their identity on that channel (a handle, number or user ID) and a display name when the channel provides one. |
| Messages | How many messages have been exchanged so far. |
| Started | When the first message arrived. |
| Last message | When the most recent message was sent. |
| Status | active, idle or closed. |
Status
| Status | Meaning |
|---|---|
active | The conversation is under way. |
idle | Open, but nothing has been said for a while. A new message makes it active again. |
closed | Finished. A new message from the same contact starts or reopens a conversation. |
The transcript
Opening a session shows every message in order. Each entry has a role and a time:
| Role | What it is |
|---|---|
user | A message from the contact. |
assistant | The agent’s reply. |
tool | A tool the agent called during the conversation, with the tool’s name and its result. |
system | A note from the runtime, such as instructions added at the start. |
Seeing tool entries in line with the conversation makes it easy to tell why the agent said something.
Browse sessions
Sessions are listed most recent first and load in pages as you scroll, 25 at a time by default and at most 100 per page. They can be narrowed to one channel.
Watch a session live
Each agent’s page has a Live activity panel that streams what the agent is doing in one session as it happens.
Open the agent
Go to AI Agents and select the agent.
Expand Live activity
Select Live activity to open the panel. Its badge shows the connection state: connecting, open, reconnecting or disconnected.
Pick a session
Choose from the most recent sessions (each listed with the contact, channel, status and last message time), or paste a session ID. The most recent session is selected for you if you have not picked one.
Read the stream
Two kinds of event appear as they happen:
- Message events show the role, the first part of the text, the model’s response time, the prompt and completion token counts and the cost.
- Tool events show the tool’s name, its status and how long it took.
The panel keeps the last 100 events. Reconnect reopens the stream and Clear empties the panel.
The stream reconnects by itself about once a minute and resumes from the last event it received, so a long session can be watched without gaps.
Sessions and executions
A session is the conversation; an execution is the record of one run that the conversation triggered. A long conversation can produce many runs.
To see every run a conversation caused:
- Copy the session ID.
- Open Executions, choose AI Agent runs and paste the ID into Session ID.
- Select Apply.
Privacy
Session transcripts can contain personal details sent by your contacts. Limit who has access to the project, and do not paste transcripts into public tickets.
Sessions API
The Sessions API lets your code do what a channel does today: open a conversation with an agent, send it messages, follow what it does as it happens, step in when it needs approval, and stop it. The agent runs on Syntic’s side, so your code does not have to host a loop, store history or execute built-in tools.
Use it when an agent should be part of your own product (a web app, a back-office job, a CI step) rather than reached through a messaging channel.
Endpoints
| Method | Path | Purpose |
|---|---|---|
POST | /v1/sessions | Start a session with an agent. |
GET | /v1/sessions | List sessions, newest first. |
GET | /v1/sessions/{session_id} | Read a session’s status, usage and outcome. |
POST | /v1/sessions/{session_id}/events | Send events: a user message, a tool result, an approval decision. |
GET | /v1/sessions/{session_id}/events | Read the full event history, paginated. |
GET | /v1/sessions/{session_id}/stream | Follow events live as server-sent events. |
POST | /v1/sessions/{session_id}/interrupt | Stop the current turn. The session stays open. |
POST | /v1/sessions/{session_id}/archive | Close the session. No more events are accepted. |
DELETE | /v1/sessions/{session_id} | Delete an archived session and its event history. |
Base URL https://app.syntic.ai/v1 (the paths above already include /v1). Authenticate with a private key (Authorization: Bearer sk_live_...) and send syntic-beta: agents-2026-11-01 while the API is in preview. A key sees only sessions in its own workspace.
Start a session
POST /v1/sessions
| Field | Required | Type | Notes |
|---|---|---|---|
agent_id | Yes | string | An active agent definition. |
agent_version | No | integer | Pin a version. Default: the latest. |
input | No | array | Events to send straight away, same format as POST /events. Saves a round trip. |
title | No | string | Shown in the Console session list. Up to 200 characters. |
contact | No | object | { "id": "...", "display_name": "..." }: who the agent is talking to, for your own tracking. |
environment_id | No | string | Override the agent’s environment. |
memory_scope | No | string | Which scope of the agent’s memory stores this session reads and writes, such as customer:4821. Without it the agent can read only the global scope and cannot write. |
limits | No | object | Lower the agent’s max_turns, session_token_budget or session_cost_budget_usd for this session. Higher values are refused. |
metadata | No | object | Up to 16 string pairs. |
Response 201 Created:
{
"id": "sesn_01JC7M2K4P6R8T0V2X4Z",
"type": "session",
"agent_id": "agt_01JC4R8W6Q2N9X3T5V7Y",
"agent_version": 4,
"status": "running",
"channel": "api",
"title": "Refund for order 88123",
"usage": { "input_tokens": 0, "cached_input_tokens": 0, "output_tokens": 0, "cost_usd": "0.0000" },
"outcome": null,
"created_at": "2026-11-05T10:00:00Z",
"last_event_at": "2026-11-05T10:00:00Z",
"metadata": {}
}status | Meaning |
|---|---|
running | The agent is working on a turn. |
requires_action | The agent is waiting for you: a tool result from your code or an approval decision. |
idle | The turn finished; the agent waits for the next message. |
archived | Closed. Read-only. |
outcome is filled in when a turn ends: { "reason": "end_turn" | "max_turns" | "budget_exhausted" | "interrupted" | "error", "message": "..." }.
Send events
POST /v1/sessions/{session_id}/events with { "events": [ ... ] }. Up to 20 events per call.
Event type | Fields | Use |
|---|---|---|
user.message | content: a string, or an array of content parts as in chat completions | Say something to the agent. Starts a new turn if the session is idle; queued if running. |
user.tool_result | tool_call_id, content, optional is_error | Return the result of a function tool your code runs. |
user.approval | tool_call_id, decision (approve or reject), optional reason | Answer an approval request. |
user.interrupt | none | Same as POST /interrupt. |
Response 202 Accepted with the stored events and their ids. Sending a user.tool_result or user.approval for a call that is not waiting gives 409 tool_call_not_pending.
Stream events
GET /v1/sessions/{session_id}/stream returns Content-Type: text/event-stream. Each event has an id: line (the event id) and a data: line with JSON. Reconnect with the Last-Event-ID header to resume without gaps; events are kept for replay for 24 hours. A comment line (: keep-alive) is sent every 15 seconds so proxies do not drop an idle connection. The stream ends when the session is archived; otherwise the server closes it after 10 minutes and you reconnect.
Event type | Payload | Meaning |
|---|---|---|
status.changed | status, outcome | The session’s status changed. |
message.delta | message_id, delta (text fragment) | Part of the agent’s reply as it is written. |
message.completed | message_id, content | The full reply. Always sent, even if you ignore deltas. |
tool_call.started | tool_call_id, name, arguments, executor (syntic or client) | The agent called a tool. If executor is client, the session moves to requires_action and waits for your user.tool_result. |
tool_call.completed | tool_call_id, output (truncated to 8 KB), is_error, duration_ms | A Syntic-run tool finished. |
approval.required | tool_call_id, name, arguments | A tool on the agent’s approval list wants to run. |
usage.updated | usage | Running totals after each model call. |
error | error (same envelope as HTTP errors) | Something failed inside the turn. Followed by status.changed. |
Example stream:
id: evt_01JC7M3A
data: {"type":"status.changed","status":"running","outcome":null}
id: evt_01JC7M3B
data: {"type":"tool_call.started","tool_call_id":"call_7","name":"lookup_order","arguments":{"order_id":"88123"},"executor":"client"}
id: evt_01JC7M3C
data: {"type":"status.changed","status":"requires_action","outcome":null}# Start a session with a first message
curl -sS https://app.syntic.ai/v1/sessions \
-H "Authorization: Bearer $SYNTIC_API_KEY" \
-H "Content-Type: application/json" \
-H "syntic-beta: agents-2026-11-01" \
-d '{"agent_id": "agt_01JC4R8W6Q2N9X3T5V7Y",
"input": [{"type": "user.message", "content": "Please refund order 88123."}]}'
# Follow it
curl -sSN https://app.syntic.ai/v1/sessions/sesn_01JC7M2K4P6R8T0V2X4Z/stream \
-H "Authorization: Bearer $SYNTIC_API_KEY" \
-H "syntic-beta: agents-2026-11-01"List and read history
GET /v1/sessions takes limit (1 to 100, default 20), after_id, before_id, agent_id, status and channel (api, telegram, slack, whatsapp and so on, so API and channel sessions appear in one list). GET /v1/sessions/{id}/events returns stored events oldest first with the same pagination; message.delta events are not stored, only message.completed.
Errors
Errors use the error envelope.
| Status | type | code | When |
|---|---|---|---|
| 400 | invalid_request | beta_required | syntic-beta header missing. |
| 400 | invalid_request | limit_above_agent | A session limit is higher than the agent’s. |
| 402 | quota_exhausted | quota_exhausted | Plan allowance and credits cannot cover the next model call. The session moves to idle with outcome budget_exhausted. |
| 404 | not_found | session_not_found, agent_not_found | No such id in this workspace. |
| 409 | invalid_request | agent_archived | The agent is archived. |
| 409 | invalid_request | session_archived | Events sent to an archived session. |
| 409 | invalid_request | tool_call_not_pending | Tool result or approval for a call that is not waiting. |
| 429 | rate_limit | rate_limited | Too many requests. |
Limits
| Limit | Value |
|---|---|
Concurrent running sessions per workspace | 50 (raised with rate-limit tier) |
Events per POST /events | 20 |
| Size of one event | 1 MB |
| Wait for a client tool result or approval | 24 hours, then the turn ends with outcome error |
| Open stream connections per session | 5 |
Replay window for Last-Event-ID | 24 hours |
Model tokens are billed exactly like chat completions, to the workspace of the key that started the session. Built-in tools add their own line items.
Build notes for the platform team
- Back the API with the existing runtime and the execution store: each turn opens an execution with
session_idset, so the Console’s Executions and Live activity views keep working unchanged. - The event type list above is the contract SDKs will wrap. Add new types only; never rename one.
- Raw upstream error text must never appear in an
errorevent; map it to the envelope first.
Related
- Channels: where sessions come from.
- Executions: run history and traces.
- Tools & skills.
- Agent definitions API
- Stream format