You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
All endpoints live under /api, return JSON, and require a session cookie (Better Auth,
mounted at /api/auth/*) unless noted. Every query is scoped to the signed-in user; ids
belonging to someone else return 404.
Errors: { "error": { "code": string, "message": string } } with status 400/401/404/409/422/500.
Types referenced below (UiMessage, UiPart, SeqEvent, RunStatus, Effect,
ToolOutput, PolicyRule, PolicyDefaults) are exported from @synapse/core and
@synapse/core/ui.
{ chat: { id, title }, runId?: string } (creates a chat; if content is given, also sends it)
GET
/api/chats/:id
{ chat: { id, title }, messages: UiMessage[], run: UiRun | null } — run is the latest run ({ id, status, error, model, tainted, steps, trigger, inputTokens, outputTokens, costUsd, createdAt, finishedAt, lastSeq }); resume the event stream after run.lastSeq
PATCH
/api/chats/:id
{ title }
{ chat }
DELETE
/api/chats/:id
204
POST
/api/chats/:id/messages
{ content: string }
{ runId, queued: "new_run" | "pending_input" }
Only one run is active per chat. A message sent while a run is active is queued and the
agent reads it at its next step; if the run is waiting on approvals, those are denied
("the user moved on") and the run continues with the new message.
{ approvals: { runId, chatId, chatTitle, toolCallId, name, effect, input, reason, preview, createdAt }[] } — preview is a one-line human summary from the tool, reason explains why approval is needed — everything awaiting the user
Event stream
GET /api/runs/:id/events is text/event-stream. Each event:
Resume with Last-Event-ID header or ?after=<seq>; events are replayed from the log
and then streamed live. Applying an event twice is harmless (applyEvent ignores
seq <= lastSeq).
The server closes the stream after a run.status event whose status is waiting,
completed, failed or cancelled. Re-open it when a new run starts or after
approving (the same run continues with new seqs).
: ping comments every 15s keep proxies from closing idle streams.
ModelEntry is { ref, name, provider, creator, contextWindow: number | null, price: { input, output, cacheRead? } | null, tags: string[], released: string | null, available: boolean }.
Prices are USD per million tokens. The list holds every language model in the Vercel AI Gateway
catalog as a gateway:<creator>/<model> ref, the same model as a direct ref when its creator is
Anthropic, OpenAI or Google (e.g. openai:gpt-5.5, anthropic:claude-sonnet-5-5), the built-in
price table and the server's configured chain. available means the server or the user has a key
for that provider. Available models come first, then newest. updatedAt is the last catalog sync
(null if it never synced; built-in prices are used then).
Automations
Prompts that run on a schedule, each in its own chat. Anything that needs approval waits in
the approvals inbox.