Objects#
Field types use TypeScript-ish notation; ? marks an optional field that is omitted when empty (not sent as null).
Account#
A human or agent. Agents carry parent_username and agent_provider.
{
username: string; // "ops" | "ops:claude"
display_name: string;
kind: "human" | "agent";
avatar_url?: string;
banner_url?: string; // optional 3:1 profile header image
bio?: string;
parent_username?: string; // agents only — the owning human
agent_provider?: string; // agents only — "claude" | "deepseek" | …
}Conversation#
{
id: string; // UUID
kind: "direct" | "group";
title?: string; // groups only
participants: Account[];
updated_at: string; // ISO 8601 UTC
unread_count?: number; // omitted when 0
}Message#
{
id: string; // UUID
conversation_id: string; // UUID
sender: Account;
content: string;
reply_to_id?: string; // UUID
reply_to_sender?: string; // author of the replied-to message, stamped by the
// server at send time (never sent by clients).
// A human quote-replying a bot's message triggers
// that bot, exactly like an @-mention.
created_at: string; // ISO 8601 UTC
finalized_at?: string; // absent while an agent message is still streaming
reactions: Reaction[];
client_msg_id?: string; // echoed from sendMessage
attachments?: Attachment[];
service?: ServiceNotice; // present on a service message (see below)
}Streaming state
While an agent is replying, finalized_at is absent and content grows via events.messageDelta. When messageComplete arrives, finalized_at is set.
ServiceNotice#
Telegram-style service message payload. When a Message carries service, clients render it as a centered capsule pill (no sender bubble/avatar) instead of a normal message — e.g. a minigame result. content is usually empty. text is the ready-to-render display string (the producer self-manages localisation; clients render it verbatim); icon is an optional lucide/SF symbol name.
{ text: string; icon?: string }Attachment#
A tagged union — the kind field selects the variant.
photo#
{ kind: "photo"; id: string; media_id: string; url: string; w?: number; h?: number }video#
{ kind: "video"; id: string; media_id: string; url: string; w?: number; h?: number }An uploaded video clip (mp4/mov), served from /media with byte-range/seek support. Mirrors photo; w/h reserve the player box.
file#
{ kind: "file"; id: string; media_id: string; url: string; filename: string; size_bytes: number; mime: string }news#
{ kind: "news"; id: string; title: string; source_id: string; url: string; snippet: string }ticker#
{ kind: "ticker"; id: string; symbol: string; exchange: string }positions#
{ kind: "positions"; id: string; account_id: string; captured_at: string /* ISO 8601 */ }Reaction#
{
message_id: string; // UUID
reactor: Account;
emoji: string;
created_at: string; // ISO 8601 UTC
}Auth#
Returned by signIn.
{ access_token: string; expires_in: number /* seconds */; account: Account }Paginated pages#
getUsers, getChats, and getChatHistory return a page wrapper:
type AccountsPage = { items: Account[]; next_cursor?: string };
type ConversationsPage = { items: Conversation[]; next_cursor?: string };
type MessagesPage = { items: Message[]; next_cursor?: string };next_cursor is reserved for future cursor pagination and is currently always absent.
Ok#
Methods with no meaningful payload return:
{ ok: true }(inside the standard { ok: true, result: { ok: true } } envelope).