Skip to content
Beta

Reference Changes feed

Changes feed

One endpoint that copies a team and then returns every change, page by page.

Overview

GET /v1/sync/changes returns a team's changes, page by page, in the order Totem recorded them. Without cursor, it starts an initial sync of every record. With the next_cursor of your last page, it returns what changed since. Each item is the current state of one record, or a removal that tells you to delete it. New kinds of record can appear in the feed in any version: store or skip an item whose kind you do not know, and keep syncing.

Store next_cursor after you apply each page, even an empty one, and send it on your next request. A cursor expires 30 days after the point in the feed it reached; a team you poll every few minutes never gets there.

This page is the reference: the parameters, the item object and the errors. Keep a copy in sync is the guide: how to apply a page, recover from each error, and run a sync client that Totem tests.

Read the changes feed of one team

GET /v1/sync/changes

Returns the next page of one team's changes, in the order Totem recorded them: each item is a record's current state or its removal. Without cursor it starts an initial sync of every record; after applying each page, store its next_cursor and send it on the next call, even when the page is empty. A cursor expires 30 days after the point in the feed it reached or, while an initial sync is still running, 30 days after that sync started.

Scopes
crm:readcalls:readmessages:readcalendar:read
Rate limit
Sync

Query parameters

  • cursor string 1–512 chars

    The next_cursor of the previous page. Omit it to start an initial sync from the beginning.

  • limit integer Range 1–100 Default 25

    Items per page, 1–100. Defaults to 25.

Headers

  • Totem-Team string Conditional ID prefix team_…

    The team to read, as a team_… id. Omit it when the key reads one team; it is required when the key reads several (400 team_required). When you send it, it must name a team the key reads: a malformed id gets 400 invalid_request, and a team outside the key gets 404 team_not_accessible, as does a request without it once the key reads no team at all.

Returns

Returns a list of FeedItem objects.

  • object string

    Always list.

  • data Array<FeedItem>

    Changes in the order Totem recorded them. A record can appear more than once during an initial sync.

  • has_more boolean

    true when more changes are ready now; false once you have caught up.

  • next_cursor string

    Always present, even on an empty page. Store it after applying the page and send it on the next call.

Errors

+ 12 common errors

GET /v1/sync/changes
curl 'https://api.totemstudio.ai/v1/sync/changes?limit=25' \
  -H "Authorization: Bearer $TOTEM_API_KEY" \
  -H "Totem-Team: $TOTEM_TEAM_ID"
Response · 200JSON
{
  "object": "list",
  "data": [
    {
      "kind": "lead",
      "id": "lead_r72EfbRNUzuqORFJR0O8HxAwEXd93jGUTYMaMMXKSF0QbLS8CiUKJpEP34LFQG",
      "version": 3,
      "object": {
        "id": "lead_r72EfbRNUzuqORFJR0O8HxAwEXd93jGUTYMaMMXKSF0QbLS8CiUKJpEP34LFQG",
        "object": "lead",
        "livemode": false,
        "team": "team_r9uYrIW4gSFJJ6hZQ9ip1UIpPaAD1CF7NR",
        "record_kind": "lead",
        "name": "Alex",
        "surname": "Rivera",
        "email": "alex.rivera@example.com",
        "company": "Example Dental",
        "phone": "+12025550123",
        "phone_status": "valid",
        "status": "contacted",
        "status_set_by": "ai",
        "archive_reason": null,
        "archived_from_status": null,
        "contact_permissions": {
          "do_not_contact": false,
          "email_opt_out": false,
          "email_opt_out_at": null,
          "whatsapp_consent": null,
          "provenance": {
            "do_not_contact": null,
            "email_opt_out": null,
            "whatsapp_consent": null
          }
        },
        "merged_into": null,
        "transferred_to": null,
        "revived_at": null,
        "pipeline_cleared": false,
        "converted_at": null,
        "value_at_conversion": null,
        "priority": "high",
        "tags": [
          "spring-check-up"
        ],
        "board": "brd_r72EfbRNUzuqORFJR0O8HxAwEXd93jGUTYMaMMX3trzsVUZQuHcMSuDh1aRIst",
        "stage": "stg_r72EfbRNUzuqORFJR0O8HxAwEXd93jGUTYMaMMXWBYWcKwVTY3CRZlVS3oYvs0",
        "assignees": [
          "mem_h548E7UiYhutHhucVrQCzkM0eaea0"
        ],
        "estimated_value": 1200,
        "estimated_value_currency": null,
        "source": "meta_lead_ads",
        "source_channel": null,
        "source_detail": null,
        "source_provenance": "member_editable",
        "created_at": "2026-09-28T10:15:00.000Z",
        "version": 3,
        "updated_at": "2026-09-28T10:20:01.250Z"
      }
    },
    {
      "kind": "call",
      "id": "call_m1pf4APjJWVi3Z7ulyNaW8y3lUi7V",
      "version": 5,
      "removed": {
        "reason": "deleted"
      }
    },
    {
      "kind": "lead_response",
      "id": "lead_r72EfbRNUzuqORFJR0O8HxAwEXd93jGUTYMaMMXKSF0QbLS8CiUKJpEP34LFQG",
      "version": 7,
      "object": {
        "id": "lead_r72EfbRNUzuqORFJR0O8HxAwEXd93jGUTYMaMMXKSF0QbLS8CiUKJpEP34LFQG",
        "object": "lead_response",
        "livemode": false,
        "team": "team_r9uYrIW4gSFJJ6hZQ9ip1UIpPaAD1CF7NR",
        "last_inbound_at": "2026-10-01T08:58:00.000Z",
        "last_outbound_at": "2026-10-01T08:59:30.000Z",
        "awaiting_reply": false,
        "last_answered_call_at": "2026-09-28T10:17:00.000Z",
        "last_whatsapp_delivery_status": "read",
        "coverage": {
          "conversations": 2,
          "calls": 1,
          "channels_without_delivery_data": [
            "email"
          ],
          "truncated": false
        },
        "version": 7,
        "updated_at": "2026-10-01T08:59:31.040Z"
      }
    }
  ],
  "has_more": false,
  "next_cursor": "eyJ2IjoxLCJ0ZWFtIjoidGVhbV9yOXVZcklXNGdTRkpKNmhaUTlpcDFVSXBQYUFEMUNGN05SIiwiZXBvY2giOjAsInQiOnsicyI6MTc5MDg0NTE3MSwibnMiOjQwMDAwMDAwfSwibiI6IjVkMjJhMTVlM2E5MmNmYTE4NzUzZTVmYzkyZmVjNzI0MjQyNjIzZDE2MGIxZTUxMzRiYTM1ODE5MmUzNzM0ZjEiLCJicyI6bnVsbH01ZPX02"
}

The FeedItem object

One change: the record's current state, or its removal.

Attributes of every variant

  • kind string

    The kind of the record, such as lead or call.

    Possible values
    • lead
    • lead_attribution
    • lead_response
    • activity
    • call
    • conversation
    • booking
    • board
  • version integer Range ≥ 1

    The record's version. Apply the item only when it is greater than the version you hold.

Variants

Each FeedItem is exactly one of these 2 variants.

With object

  • id string ID prefix lead_… act_… call_… conv_… bkg_… brd_…

    Public id of the record; the facets lead_attribution and lead_response use their lead's id.

  • object one of 8 objects

    The record as it is now.

    Matches kind:

With removed

  • id string ID prefix lead_… act_… call_… conv_… bkg_… brd_…

    Public id of the removed record.

  • removed object

    Present only on a removal.

FeedItem · exampleJSON
{
  "kind": "lead",
  "id": "lead_r72EfbRNUzuqORFJR0O8HxAwEXd93jGUTYMaMMXKSF0QbLS8CiUKJpEP34LFQG",
  "version": 3,
  "object": {
    "id": "lead_r72EfbRNUzuqORFJR0O8HxAwEXd93jGUTYMaMMXKSF0QbLS8CiUKJpEP34LFQG",
    "object": "lead",
    "livemode": false,
    "team": "team_r9uYrIW4gSFJJ6hZQ9ip1UIpPaAD1CF7NR",
    "record_kind": "lead",
    "name": "Alex",
    "surname": "Rivera",
    "email": "alex.rivera@example.com",
    "company": "Example Dental",
    "phone": "+12025550123",
    "phone_status": "valid",
    "status": "contacted",
    "status_set_by": "ai",
    "archive_reason": null,
    "archived_from_status": null,
    "contact_permissions": {
      "do_not_contact": false,
      "email_opt_out": false,
      "email_opt_out_at": null,
      "whatsapp_consent": null,
      "provenance": {
        "do_not_contact": null,
        "email_opt_out": null,
        "whatsapp_consent": null
      }
    },
    "merged_into": null,
    "transferred_to": null,
    "revived_at": null,
    "pipeline_cleared": false,
    "converted_at": null,
    "value_at_conversion": null,
    "priority": "high",
    "tags": [
      "spring-check-up"
    ],
    "board": "brd_r72EfbRNUzuqORFJR0O8HxAwEXd93jGUTYMaMMX3trzsVUZQuHcMSuDh1aRIst",
    "stage": "stg_r72EfbRNUzuqORFJR0O8HxAwEXd93jGUTYMaMMXWBYWcKwVTY3CRZlVS3oYvs0",
    "assignees": [
      "mem_h548E7UiYhutHhucVrQCzkM0eaea0"
    ],
    "estimated_value": 1200,
    "estimated_value_currency": null,
    "source": "meta_lead_ads",
    "source_channel": null,
    "source_detail": null,
    "source_provenance": "member_editable",
    "created_at": "2026-09-28T10:15:00.000Z",
    "version": 3,
    "updated_at": "2026-09-28T10:20:01.250Z"
  }
}

API version 1.0a