MCP

schemas/pagination

All list operations return the same envelope:

{
  "items": ["... resource objects ..."],
  "pagination": {
    "currentPage": "integer — 1-indexed",
    "pageSize": "integer — items in this page",
    "totalItems": "integer — total items matching the query; identical in both offset and cursor paging",
    "nextCursor": "integer or date-time — cursor for the next page (type follows the resource key; messages use date-time)"
  }
}

Page size

limit accepts integers 1–30 on every paginated operation. Omit it and a default page size is applied — 10 on most operations, 30 on the ones whose items are small — and a wrapper_note names the value applied. An integer above 30 is never rejected — the page is served at 30 with a wrapper_note saying so; any other value fails validation.

Both spellings work everywhere: flat page / limit / startingAfter and the dotted pageQuery.page / pageQuery.limit / pageQuery.startingAfter. Whichever an operation's Arguments table lists is the canonical one; the other is accepted as an alias, so a spelling carried over from another operation will not be rejected.

Requests are rate-limited per API key, not per operation (call-contract), so page size is also a budget decision: one limit: 30 call costs a third of three limit: 10 calls. Ask for the largest page you will actually use, and narrow with filters rather than walking many small pages.

Large bodies in list responses

On the list reads that return an email bodymessage/get, prospect/messages_by_id, campaign/get, sequence/get_followups_by_id — each item's body is bounded, so a wide page cannot blow past your context or response limit:

  • 1,500 characters or fewer: returned exactly as stored — unchanged HTML.
  • Longer: a plain-text rendering of that HTML, cut at 1,500 characters on a word boundary and ending in a bracketed note giving the original length. The note describes the preview; it is not part of the message.
  • fullBodies: true turns previewing off for that call — every body comes back complete and unchanged.
  • *_by_id reads never preview: campaign/get_by_id, followup/get_by_id and the other single-object reads always return the full body.

Never write a previewed body back. Saving one into body would replace a real email template with truncated plain text. Read the full body first — a *_by_id read, or the same list call with fullBodies: true — and edit that.

Paging styles

  • Offset: pass page + limit. Campaign operations prefix both arguments: pageQuery.page, pageQuery.limit.
  • Cursor: pass the previous response's pagination.nextCursor as startingAfter.

Cursor caveats

totalItems is the collection total in both paging modes. It reflects the total number of matching items whether you're paging with page/limit or with startingAfter.

Empty sentinel: nextCursor: "0001-01-01T00:00:00.000Z" means there are no more results.

Null and cursor semantics

  • pagination: null on a 2xx response means single page — you already have everything. It stays null even though other null fields are stripped from responses.
  • nextCursor can be present even when the page already contains all items — never treat its presence alone as "more pages"; an empty next page is the true end signal.
  • The sendingStatus filter on prospect/get returns its own pagination object: {pageSize, returned, nextCursor?, exhausted}exhausted: true means the account was fully scanned; a nextCursor (last matched or last scanned prospect id) means "continue with startingAfter", even when fewer than pageSize items were returned.