Pagination

List endpoints return records inside a collection object. Lists that can grow large, such as contacts, threads, and tasks, page with an opaque cursor. Smaller lists page by number or return every record at once.

This page describes the collection object once. Resource pages list only the collection fields that carry information for that list, and the table of page sizes says which model each list uses.

#Cursor pagination

Request the first page without a cursor. The response’s collection.page_info says whether more records follow and gives the cursor that fetches them:

  1. Read collection.records.
  2. If page_info.has_more_after is true, repeat the request with next_cursor set to page_info.next_cursor.
  3. Stop when has_more_after is false. next_cursor is then null.

Send the same filters, sort, and order with every page, and send the cursor exactly as you received it. A cursor works only for the list, sort, and order that issued it. A cursor that was altered, or that came from another list or another sort or order, returns 400 invalid_cursor. A cursor can also stop working after you receive it. On invalid_cursor, request the first page again without a cursor.

Treat cursors as opaque strings. Don’t build, parse, or modify them. Pages are read live, not from a snapshot, so a record created or re-sorted while you page may be missed or returned twice.

The cursor collection

  • recordsarray

    The page of records, in the list’s order. Each resource page documents the record type.

  • page_infopage info

    The page size, the cursors, and whether records exist before and after this page.

  • filtersobject · nullable

    The filter parameters you sent, echoed back. Paging parameters are left out. Null when you sent none.

  • slice_keystring · nullable

    The slice parameter you sent. Null when you sent none.

  • sort, orderstring · nullable

    The sort and order you sent, on lists that take a sort: contacts, organizations, and files. Null when you sent none.

get/contacts
curl "https://api.carom.io/contacts?scope=global" \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response200
{
  "collection": {
    "filters": { "scope": "global" },
    "page_info": {
      "limit": 50,
      "next_cursor": "c1Kq8ZrT4wVn2LmX7pYb3HdJ9sFe6Ga0Qu5Nt",
      "prev_cursor": null,
      "has_more_after": true,
      "has_more_before": false
    },
    "records": [
      {
        "id": "1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41",
        "name": "Priya Natarajan",
        …
      },
      …
    ]
  }
}
Next page
curl https://api.carom.io/contacts \
  -G --data-urlencode "scope=global" \
  --data-urlencode "next_cursor=c1Kq8ZrT4wVn2LmX7pYb3HdJ9sFe6Ga0Qu5Nt" \
  -H "Authorization: Bearer $CAROM_API_KEY"

#Paging backward

Two lists page in both directions: tasks and calendar events. Once you have moved past the first page, page_info.has_more_before is true and page_info.prev_cursor fetches the page before this one. Send it as prev_cursor, and send one cursor per request.

The other cursor lists page forward only. On every page their has_more_before is false and prev_cursor is null, and sending prev_cursor returns 400 unsupported_cursor_direction.

get/tasks
curl https://api.carom.io/tasks \
  -G --data-urlencode "prev_cursor=Rk7T2nWq9XmLb4vPz8JcYh3Df6Us1Ea5Wo0Ki" \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response200
{
  "collection": {
    "page_info": {
      "limit": 25,
      "has_more_before": true,
      "has_more_after": true,
      "prev_cursor": "M4wQz9Lp2VtKc7Xn5Rb8Yh1Jd3Fs6Ge0Ay7Ho",
      "next_cursor": "Rk7T2nWq9XmLb4vPz8JcYh3Df6Us1Ea5Wo0Ki"
    },
    "records": [
      …
    ]
  }
}

#Page-number pagination

Page-number lists take page, starting at 1, and per_page. The collection reports the total, so you can compute how many pages to fetch. It has no page_info.

The page-number collection

  • recordsarray

    The page of records, in the list’s order.

  • pageinteger

    The page returned, starting at 1.

  • per_pageinteger

    The page size in effect.

  • total_resultsinteger

    How many records match across all pages.

  • pagesinteger

    How many pages the matching records fill at this per_page.

  • filters, slice_key, sort, ordernullable

    As in the cursor collection: the parameters you sent, echoed back, on lists that take them. order is asc or desc.

get/deals
curl "https://api.carom.io/deals?page=2&per_page=25" \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response200
{
  "collection": {
    "sort": "created_at",
    "order": "desc",
    "per_page": 25,
    "page": 2,
    "total_results": 61,
    "pages": 3,
    "records": [
      {
        "id": "5e0d8c3b-7a1f-4b2e-9d6c-3f8a1e4b7c20",
        "name": "Wildgrove portfolio renewal",
        "status": "open",
        …
      },
      …
    ]
  }
}

#Lists returned whole

Some lists take no paging parameter and return every record in one response. Don’t send page or a cursor to them.

These lists use the page-number collection. Its records holds every record and total_results is their count. page and pages are 1, and per_page equals total_results, which is 0 when the list is empty.

Other lists returned whole, such as a record’s comments, your drafts, and the account’s pipelines, return a plain array under a named key, such as comments or drafts, with no collection around it. Each resource page says which form its list uses.

#Page sizes

Where a list takes a size parameter, a value above the maximum returns the maximum. The size in effect is echoed as page_info.limit or per_page.

Cursor lists

ListPage sizeParameters
GET /contacts50next_cursor
GET /organizations50next_cursor
GET /threads50next_cursor
GET /files50next_cursor
GET /notifications50; limit up to 100next_cursor
GET /tasks25; limit 1–100next_cursor prev_cursor
GET /calendar_events100; limit 1–250next_cursor prev_cursor

Page-number lists

ListPage sizeParameters
GET /deals50; per_page 1–100page per_page
GET /proposals50; per_page 1–100page per_page
GET /conversations50; per_page 1–100page per_page

#Other lists

A few endpoints take their own paging parameters, which their pages describe: Search takes page and limit, the timeline takes before, which you set to the previous page’s oldest_timestamp, and a conversation’s messages take before and limit.