Skip to main content

How pagination and search work

Lists in the Sally API are paged, and search has its own endpoint per resource. This page shows the parameters and the envelope every paged answer carries, a copyable loop that fetches all pages, and how the search endpoints take and match their terms.

Every example works as it stands once SALLY_TOKEN and DIRECTORY_ID are set, see the Quickstart. Pick your language once, every example on the API pages follows.

Quick navigation

  1. Pagination
  2. Fetch all pages
  3. Search endpoints
  4. How matching works
  5. Endpoints at a glance

1. Pagination​

Paged list endpoints take two query parameters:

ParameterTypeDefaultDescription
pageinteger1Page number, starting at 1.
pageSizeinteger25Entries per page, at most 100.

This request asks for the second page with ten recordings:

curl "https://api.sally.io/v1.0/directories/$DIRECTORY_ID/recordings?page=2&pageSize=10" \
-H "Authorization: Bearer $SALLY_TOKEN"

The answer is always the same envelope around the entries:

200 OK
{
"page": 2,
"pageSize": 10,
"total": 137,
"hasMore": true,
"items": [
{
"recordingId": "53e2e041-4b34-41c7-a285-634d80b3675d",
"name": "Weekly team meeting",
"durationInSeconds": 1843,
"languageCode": "de-DE",
"createdOn": "2026-09-24T09:30:00Z"
}
]
}
FieldTypeMeaning
pageintegerThe page you got.
pageSizeintegerThe page size that was applied.
totalintegerNumber of matches across all pages.
hasMorebooleantrue if another page follows. Use it as your loop condition.
itemsarrayThe entries of this page. Their fields are in the reference of each endpoint.
Note

A few small lists are not paged and return a plain JSON array. The reference shows which kind each endpoint returns, and Endpoints at a glance lists every paged one.

2. Fetch all pages​

Ask for pages until hasMore is false. Use the largest page size you can handle, so you need fewer calls. When the loop hits the rate limit and gets a 429, it waits a little longer each time and asks for the same page again.

page=1
while : ; do
body=$(curl -s "https://api.sally.io/v1.0/directories/$DIRECTORY_ID/recordings?page=$page&pageSize=100" \
-H "Authorization: Bearer $SALLY_TOKEN")
echo "$body" | jq -c '.items[]'
[ "$(echo "$body" | jq '.hasMore')" = "true" ] || break
page=$((page + 1))
done
Recommendation

Combine paging with field selection: fields=recordingId,name,createdOn keeps every page small. The envelope fields are always returned, so the loop keeps working.

3. Search endpoints​

Every searchable resource has a POST …/search endpoint that takes its parameters in the request body. That is deliberate: a search term in a URL runs into encoding trouble with spaces, umlauts and percent signs, in the body it does not.

A search body always has exactly one free-text field called search, matched across all relevant text fields of the resource at once, plus the structural filters of that resource and page and pageSize. This request searches appointments:

curl -X POST "https://api.sally.io/v1.0/directories/$DIRECTORY_ID/appointments/search" \
-H "Authorization: Bearer $SALLY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"search": "Q4 planning",
"from": "2026-09-01T00:00:00Z",
"page": 1,
"pageSize": 25
}'

The body fields of the appointment search:

FieldTypeDescription
searchstringFree text, matched in subject, description and attendee name or email.
fromstringOnly appointments that start at or after this UTC timestamp.
tostringOnly appointments that start at or before this UTC timestamp.
pageintegerPage number, default 1.
pageSizeintegerEntries per page, default 25, at most 100.

The response has the same envelope as the matching list endpoint, so the loop from Fetch all pages works here too: send the same body again with the next page.

Note

The plain GET list endpoints stay pure list endpoints. The search endpoint is an addition, not a replacement.

4. How matching works​

  • Case-insensitive substring: the term matches anywhere in the value, not only at the start.
  • Literal: %, _ and * are ordinary characters, not wildcards.
  • Trimmed: leading and trailing spaces are removed, and an empty term means no filter.
  • Some endpoints require a minimum length, which the reference names on the endpoint.
searchMatches Q4 planning with SalesWhy
"planning"yesSubstring anywhere in the value.
"SALES"yesCase does not matter.
" q4 "yesSurrounding spaces are removed.
"plan*"no* is a literal character, not a wildcard.
""yesAn empty term means no filter.

5. Endpoints at a glance​

These lists come straight from the specification. Each entry leads to the reference, where you can send the request with your own token.

Paged endpoints

Search endpoints