Sync
Your own copy of what you can see: groups, bootstrap, records by id and each group's changes in order.
Privacy and analytics
We use necessary technical cookies and, only with your consent, analytics and marketing pixels to improve the website and measure campaigns.
Your own copy of what you can see: groups, bootstrap, records by id and each group's changes in order.
Updated on January 1, 1970
Read-only in every door.
The frames of one sync group after a cursor, in order and contiguous (seq). cursor_expired means bootstrap the group again; group_forbidden means you may not hold it (any more): drop it locally. The server decides group membership.
| Field | Value |
|---|---|
| Kind | Read |
| HTTP method | POST /api/v1/sync.deltas |
| MCP tool | sync_deltas |
| Scope | sync.read |
| Minimum role | self |
| Human confirmation | No |
| Doors | Screens, Apps, API |
| Status | Available |
Input
{
group: string // `<kind>:<uuid>` (person, workspace, brand, brand-staff, conversation, team, team-space, mailbox).
after?: integer // 0–9007199254740991 · default 0 · The last `seq` applied; 0 right after a bootstrap at seq 0.
limit?: integer // 1–500 · default 200
shapes?: Record<string, integer> // Shape versions the client understands (served N and N-1).
}Output
{
group: string
frames: Array<{
type: "delta"
group: string
seq: integer // 1–9007199254740991
event: {
id: string
type: string
occurredAt: string
actor?: {
kind: "person" | "agent" | "system" | "service"
id: string | null
}
idempotencyKey?: string | null
}
changes: Array<{
op: "put" | "patch" | "delete" | "stale"
entity: string
id: string
version: string
}>
}>
head: integer // 0–9007199254740991
hasMore: boolean
}The sync groups the person may hold now (their own inbox, their workspaces and brands) with each group's policy: whether a copy may be kept on the device and how many records fit. Conversations open from a list the person already reads. The database decides membership; the client never infers it.
| Field | Value |
|---|---|
| Kind | Read |
| HTTP method | POST /api/v1/sync.groups.list |
| MCP tool | sync_groups_list |
| Scope | sync.read |
| Minimum role | self |
| Human confirmation | No |
| Doors | Screens, Apps, API |
| Status | Available |
Input
{}Output
{
groups: Array<{
group: string
persist: boolean
maxRecords: integer // -9007199254740991–9007199254740991
}>
}One page of a group's records and its sequence number, read in the same database snapshot. Page with nextPageToken; the group's cursor is the lowest seq of all pages, after which sync.deltas follows. Refused (forbidden, detail group_forbidden) when the person is not in the group.
| Field | Value |
|---|---|
| Kind | Read |
| HTTP method | POST /api/v1/sync.bootstrap |
| MCP tool | sync_bootstrap |
| Scope | sync.read |
| Minimum role | self |
| Human confirmation | No |
| Doors | Screens, Apps, API |
| Status | Available |
Input
{
group: string // A sync group: `<kind>:<uuid>` (person, workspace, brand, brand-staff, conversation, team, team-space, mailbox).
pageToken?: string | null // `nextPageToken` of the previous page; absent for the first.
shapes?: Record<string, integer> // Shape versions the client understands, by entity. A version the server no longer serves answers `shape_unsupported`.
limit?: integer // 1–1000 · Records per page (500 by default).
}Output
{
group: string
seq: integer // 0–9007199254740991
records: Array<{
entity: string
id: string // uuid
version: string
data: Record<string, unknown>
}>
nextPageToken: string | null
shapes: Record<string, integer>
bytes?: integer // -9007199254740991–9007199254740991
}Current records of one entity by id, only those the person may read: missing ids are gone or hidden. Used for stale changes (too large, or fields that differ per reader).
| Field | Value |
|---|---|
| Kind | Read |
| HTTP method | POST /api/v1/sync.records.read |
| MCP tool | sync_records_read |
| Scope | sync.read |
| Minimum role | self |
| Human confirmation | No |
| Doors | Screens, Apps, API |
| Status | Available |
Input
{
entity: "notification" | "read_mark" | "conversation" | "message" | "inbox_item" | "work" | "task" | "calendar_event" | "library_asset" | "internal_note" | "team_space" | "team_message" | "mail_thread" | "person"
ids: string[] // ≤ 200 items
group?: string // The group the ids belong to, when the caller knows it: refused unless the person is in it.
}Output
{
records: Array<{
entity: string
id: string // uuid
version: string
data: Record<string, unknown>
}>
}