From eeed44f2ed3b8d5a469ef6ce24d00f0fed100698 Mon Sep 17 00:00:00 2001 From: Matthew Meszaros Date: Thu, 3 Sep 2026 20:19:16 -0700 Subject: [PATCH] feat: document the contact timeline's cursor parameter and pagination envelope in the contacts API reference, mark before as deprecated with why a bare timestamp can skip events at a page boundary, and say that a bad cursor or limit is a 400 --- docs/content/docs/api/reference/contacts.mdx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/content/docs/api/reference/contacts.mdx b/docs/content/docs/api/reference/contacts.mdx index 65548475..7358aa1f 100644 --- a/docs/content/docs/api/reference/contacts.mdx +++ b/docs/content/docs/api/reference/contacts.mdx @@ -671,12 +671,13 @@ Auth: **Scope** `READ_CONTACTS` ยท **Org permission** `view_contacts` | Parameter | In | Type | Description | | --- | --- | --- | --- | | `id` | path | UUID | Contact ID. | -| `limit` | query | integer | Page size, 1 to 200 (default 50). | -| `before` | query | string (RFC 3339 nano) | The `at` timestamp of the oldest event from the previous page. | +| `limit` | query | integer | Page size, 1 to 200 (default 50). Anything else is a `400`. | +| `cursor` | query | string | Opaque pagination cursor from `pagination.next_cursor`. A malformed cursor is a `400`. | +| `before` | query | string (RFC 3339 nano) | Deprecated. Returns the events strictly older than this timestamp, which can skip events that share an instant with the page boundary; use `cursor`. Ignored when `cursor` is set. | ### Response -Returns a `data` array and a `has_more` flag (not a cursor envelope). Paginate by passing the oldest event's `at` as `before`. +Returns a `data` array and the standard `pagination` envelope. Paginate by passing `pagination.next_cursor` back as `cursor` until `has_more` is `false`. The cursor is the exact position of the last event on the page (its time, source and row), so events that share a timestamp, common when a send, its open and a note land in the same second, are never skipped or repeated across pages. The top-level `has_more` mirrors `pagination.has_more` and is kept for clients written before the envelope. `pagination.total` is always `null`: the feed is merged from several tables and is never counted. ```json { @@ -734,7 +735,8 @@ Returns a `data` array and a `has_more` flag (not a cursor envelope). Paginate b "user_id": "u1..." } ], - "has_more": false + "has_more": false, + "pagination": { "total": null, "next_cursor": null, "has_more": false } } ```