Figment.so
Mac hostingWebsite hostingGuidesHow to usePricing

Search Message History Without Missing Results

A search that returns 12 results when the inbox holds 400 is not a bug you can retry your way out of. Two independent mechanisms produce that gap, and each one needs a different response.

The first is sync lag: the connected Mac has not yet received every message from iCloud, so queries run against a partial local copy. The second is a local history bound: search scans only the messages available on that Mac. No amount of offset-incrementing surfaces messages that were never synced. Address both before trusting your result count.

Why searches return incomplete results

iMessage reads and searches operate on messages available on the connected Mac (OAuth for iCloud). Apple's Messages in iCloud syncs your message history — including SMS, MMS, RCS, and iMessage — across signed-in devices, but that transfer takes time (Apple Support). While a sync is in progress, a search returns only what has arrived locally.

Even after sync completes, results are limited to what the Mac holds. If messages were never downloaded to this Mac, they will not appear. Both causes produce the same surface symptom: a result set smaller than expected, with no error code to distinguish them.

Check service state before you query

The connection endpoint shows the current state of each service:

GET /v1/connections/{connection_id}
Authorization: Bearer ACCESS_TOKEN

The response includes connection.services.messages.state:

{
  "connection": {
    "id": "con_abc123",
    "mode": "live",
    "services": {
      "messages": {
        "state": "ready",
        "observedAt": 1731388800000
      }
    }
  }
}

Possible states: connecting, needs_approval, syncing, ready, offline, reconnect_required, revoked. Read operations fail on non-ready connections; check this state before issuing any search.

syncing is not an error. A fresh connection passes through it while history downloads. Poll until ready before querying, or surface a "history loading" caveat to your user. needs_approval and reconnect_required require the account holder to act in the account connection screen; your application cannot resolve them.

Search parameters

GET /v1/connections/{connection_id}/messages/search
  ?query=contract%20renewal
  &chatGuid={ENCODED_CHAT_GUID}
  &limit=50
  &offset=0
Authorization: Bearer ACCESS_TOKEN
ParameterDescription
querySearch term applied to message text
chatGuidScope search to one conversation; required for a selected-conversation grant
limitResults per page, 1–100 (default 20)
offsetResults to skip; maximum 10 000

Always build the URL with a URL encoder. chatGuid values come from GET /v1/connections/{connection_id}/chats — do not construct them from phone numbers. chatGuid values contain literal + characters; a raw + in a query string decodes as a space and silently breaks lookups.

Offset is capped at 10 000. If a search would yield more than that many matching results, narrow the query or scope it with chatGuid.

Paginate with hasMore and nextOffset

Each search response carries pagination fields alongside a historyComplete flag:

{
  "data": [...],
  "mode": "live",
  "offset": 0,
  "nextOffset": 50,
  "hasMore": true,
  "historyComplete": true,
  "scope": "messages:read"
}

hasMore: true means additional results exist. nextOffset is the value to pass as offset on the next request. When hasMore is false or nextOffset is null, you have reached the end of the available result set. An empty data array is valid and not an error.

historyComplete: false means the Mac's sync is still in progress. Results are a snapshot of partial history. Surface this to users rather than presenting the result set as exhaustive.

New messages arriving during a paginated search can shift the result set. Do not assume pages form a stable real-time snapshot.

Here is the pagination model in Python pseudocode:

import urllib.parse

def search_messages(connection_id, token, query, chat_guid=None):
    base = "https://figment.so/api/apple-connect/v1"
    params = {"query": query, "limit": 50, "offset": 0}
    if chat_guid:
        params["chatGuid"] = chat_guid

    results = []
    history_complete = False

    while True:
        url = (
            f"{base}/connections/{connection_id}/messages/search"
            f"?{urllib.parse.urlencode(params)}"
        )
        resp = get(url, headers={"Authorization": f"Bearer {token}"})
        # get() is your HTTP client call; raise on non-2xx before this point

        results.extend(resp["data"])
        history_complete = resp.get("historyComplete", False)

        if not resp.get("hasMore") or resp.get("nextOffset") is None:
            break

        next_offset = resp["nextOffset"]
        if next_offset <= params["offset"]:
            break  # non-advancing offset guard
        params["offset"] = next_offset

    return results, history_complete

Pass a chat_guid from the chats endpoint when querying a specific conversation. Check history_complete on return and surface a warning to your user when it is False.

SMS, MMS, and RCS

iMessage and carrier messages share the same search endpoint. SMS, MMS, and RCS require an eligible iPhone that is turned on, online, and signed into the same Apple Account (Apple Support). With Messages in iCloud enabled, carrier message sync is built in and does not require a separate Text Message Forwarding switch.

If the iPhone is offline, existing carrier-message history can remain on the Mac but new messages will not arrive. A ready service state reflects the iMessage connector, not a guarantee that carrier-message history is current.

Get started

Reliable search starts with a connected, synced Apple Account. Figment handles iCloud sign-in, trusted-device approval, and permission grant. Your app receives a scoped access token — never the Apple password.

For the full API reference see iMessage API for Search, Replies, and Agent Actions. For a Python walkthrough of reading and filtering messages, see Read and Search iMessages with Python. For the send path and idempotency model, see Send an iMessage from Node.js Without Duplicates.

Connect Apple Account to try the search and pagination endpoints.


Subscribe for Figma design and website publishing guides.


Figment.so

Contact

Twitter

Website pricing

Compute index

About

Privacy

Terms