Skip to content
Linq

List chats

GET/v1/chats

Lists your brand’s chats, newest first, one page at a time.

Behavior

  • Scoped to your API key’s brand by construction: no parameter names a brand, and another brand’s chats are invisible rather than forbidden.
  • Page with cursor: pass the previous response’s next_cursor back verbatim, and stop when it comes back empty.
Query ParametersExpand Collapse
assigned_operator: optional string

Filter by the operator holding the chat; absent means every row, assigned or not.

cursor: optional string

The previous page’s next_cursor, verbatim; absent starts from the first page. Not a cursor this API issued returns HTTP 400 code 1013.

limit: optional number

Page size; absent (or non-numeric) reads as 25, above 100 reads as 100.

formatint32
owner: optional string

Filter by turn owner (partner, flow, human_pending, human); absent means every owner.

state: optional string

Filter by lifecycle phase (open, closed); absent means both.

ReturnsExpand Collapse
data: array of object { capabilities, chat_id, customer_handle, 10 more }
capabilities: array of string

The device’s most recently announced capability tokens. Empty means unknown, never “supports nothing”.

chat_id: string

Chat id (chat_…); pass it to GET /v1/chats/{chat} for the full view.

customer_handle: string

The customer identifier: an Apple Opaque ID, or canonical tel:+E164, per handle_kind.

handle_kind: "opaque" or "tel"

Which identifier kind customer_handle holds; branch on this, never read the string itself.

One of the following:
"opaque"
"tel"
origin: "customer" or "invitation"

How the chat began. Not derivable from handle_kind: an accepted invitation arrives under a brand-new opaque id.

One of the following:
"customer"
"invitation"
owner: string

Turn owner: partner, flow, human_pending or human. human_pending is the queue.

owner_since: string

When the chat entered its CURRENT owner state: the queue clock, NOT updated_at (which any progress bumps). Stamped only when the owner actually changes; see GET /v1/chats/{chat} for the one self-clearing exception.

formatdate-time
state: string

Lifecycle phase: open or closed.

updated_at: string

Last change of any kind: the list’s sort key, and the first half of the cursor.

formatdate-time
assigned_operator: optional string

The operator holding this chat; absent when nobody does (the common case).

business_id: optional string

The Apple business UUID your brand currently resolves to on this channel: the channel binding of record, present only when one is on file. The same value GET /v1/chats/{chat} serves.

last_inbound_at: optional string

When we last heard from the customer; any inbound, a message or a chat close. ABSENT when they have never written (an invitation nobody has answered yet).

formatdate-time
last_message: optional object { actor, at, has_attachment, 2 more }

The newest message on this chat, so the row has a subject line instead of only a handle and a wait age. ABSENT when the chat has nothing previewable: an invitation nobody has answered, a chat whose only events are ownership changes, or a message that decoded to nothing. Render nothing in that case; never invent a preview.

actor: string

Who spoke: customer on an inbound, partner on an outbound. It is the event log’s actor, not the composer: a send is recorded by the worker that delivered it, so a reply a human agent typed still reads partner here. GET /v1/chats/{chat}/transcript is where a human is named.

at: string

When that message was recorded. Distinct from both of its neighbours on this row: last_inbound_at moves only on inbound, and updated_at moves on any machine progress. Do not treat the three as one clock.

formatdate-time
has_attachment: boolean

Whether the message carried files. Deliberately ORTHOGONAL to kind, because the two answer different questions: kind says what to write on the row and this says whether to badge it. kind: "text" with this true is words PLUS a file: the one multi-part combination Apple admits.

kind: "text" or "attachment" or "interactive" or "reply"

What kind of thing it was: a CLOSED set. text: there were words. attachment: there were none, only files. reply: the customer answered an interactive message instead of typing. interactive: the business sent one. Words win when a message has both.

One of the following:
"text"
"attachment"
"interactive"
"reply"
preview: optional string

The opening words, with attachment placeholders () removed and a single where it was cut. ABSENT rather than empty when no words survived: an attachment-only message has a body of exactly , and a preview built from it verbatim would put an invisible character on the row. Say “sent a file” in your own words instead; this API does not ship desk copy.

next_cursor: string

Pass back as ?cursor= for the next page. EMPTY when this page exhausted the list, that, not an empty data, is how paging ends.

List chats

curl https://messages.api.linqapp.com/v1/chats \
    -H "Authorization: Bearer $LINQ_AMB_API_KEY"
{
  "data": [
    {
      "chat_id": "chat_4f81b2",
      "state": "open",
      "owner": "human_pending",
      "customer_handle": "urn:mbid:AQAAY7c1",
      "handle_kind": "opaque",
      "origin": "customer",
      "capabilities": [
        "TEXT",
        "LIST",
        "TIME",
        "QUICK"
      ],
      "owner_since": "2026-08-06T14:02:11Z",
      "last_inbound_at": "2026-08-06T14:01:58Z",
      "updated_at": "2026-08-06T14:02:11Z",
      "last_message": {
        "actor": "customer",
        "at": "2026-08-06T14:01:58Z",
        "kind": "text",
        "has_attachment": false,
        "preview": "I need a human agent"
      }
    }
  ],
  "next_cursor": "MjAyNi0wOC0wNlQxNDowMTo1OFogY2hhdF80ZjgxYjI"
}
Returns Examples
{
  "data": [
    {
      "chat_id": "chat_4f81b2",
      "state": "open",
      "owner": "human_pending",
      "customer_handle": "urn:mbid:AQAAY7c1",
      "handle_kind": "opaque",
      "origin": "customer",
      "capabilities": [
        "TEXT",
        "LIST",
        "TIME",
        "QUICK"
      ],
      "owner_since": "2026-08-06T14:02:11Z",
      "last_inbound_at": "2026-08-06T14:01:58Z",
      "updated_at": "2026-08-06T14:02:11Z",
      "last_message": {
        "actor": "customer",
        "at": "2026-08-06T14:01:58Z",
        "kind": "text",
        "has_attachment": false,
        "preview": "I need a human agent"
      }
    }
  ],
  "next_cursor": "MjAyNi0wOC0wNlQxNDowMTo1OFogY2hhdF80ZjgxYjI"
}