> ## Documentation Index
> Fetch the complete documentation index at: https://docs.daysync.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat

> Read a tour's chat history — channels and group chats. Read-only; direct messages are never exposed.

The Integration API exposes Daysync chat **for reading only**, and only for **channels and group chats**.

<Warning>
  **1:1 direct messages are never available through this API.** They are filtered out of every list and search, and requesting one by ID returns `404`. There is no way to reach a DM through the Integration API or the MCP server.

  There is also no `chat.write` scope. You cannot post, edit, delete, pin, or react to messages.
</Warning>

Everything below is additionally bounded by the authenticated user's own access: their conversation membership, their history cutoff if they joined a channel late, and per-viewer redaction of mentions pointing at items they cannot see. The API never widens what that user could see in the app.

All endpoints require the standard [authentication](/authentication) headers and the `chat.read` scope.

***

## Is chat enabled?

```text theme={null}
GET /v1/tours/{tourId}/chat/enabled
```

Chat is switched on per tour. Call this first — the other endpoints return nothing useful on a tour with chat disabled.

**Response `data`:** the tour's chat configuration.

***

## List conversations

```text theme={null}
GET /v1/tours/{tourId}/chat/conversations
```

Every channel and group chat on the tour that the user belongs to.

**Response `data`**

```json theme={null}
{
  "totalUnread": 5,
  "favourites": [],
  "channels": [{
    "id": 17845,
    "type": "channel",
    "name": "production",
    "is_public": true,
    "unread_count": 3,
    "last_message": { "id": 90210, "content": "Doors at 7", "sender_user_id": "cdd1…", "created_at": "2026-08-07T04:00:00Z" }
  }],
  "dmsAndGroups": [{ "id": 17999, "type": "group_chat", "name": "Tour managers", "member_count": 4, "unread_count": 2 }]
}
```

<Note>
  `dmsAndGroups` keeps its name for backwards compatibility but contains **group chats only** through this API — DMs are removed. `type` values are lowercase: `channel`, `group_chat`.
</Note>

<Note>
  **`totalUnread` counts only the conversations this API returns.** It is the sum of `unread_count` across `favourites`, `channels` and `dmsAndGroups`, so it always reconciles with the payload you received — but it will be **lower than the unread badge the same user sees in the Daysync app**, because the app counts direct messages and this API never exposes them. Muted conversations count as `0` in both.

  Don't treat a difference from the in-app number as missing data.
</Note>

This endpoint is not paged; it returns the tour's full list.

***

## Get a conversation

```text theme={null}
GET /v1/chat/conversations/{conversationId}
```

**Response `data`:** `{ id, type, name, description, is_public, is_archived, created_by_user_id, member_count, created_at }`

## List its members

```text theme={null}
GET /v1/chat/conversations/{conversationId}/members
```

**Response `data`:** array of members with their user record and chat role.

***

## Read messages

```text theme={null}
GET /v1/chat/conversations/{conversationId}/messages
```

Returns messages **newest first**.

**Query parameters**

| Name              | Type   | Description                                                  |
| ----------------- | ------ | ------------------------------------------------------------ |
| `limit`           | number | Messages per page. Capped at **100**.                        |
| `cursor`          | number | A **message ID**. Returns messages older than it.            |
| `aroundMessageId` | number | Centre the page on a specific message instead of the newest. |
| `before`          | number | With `aroundMessageId` — how many older messages. Max 100.   |
| `after`           | number | With `aroundMessageId` — how many newer messages. Max 100.   |

<Warning>
  Paging here is **cursor-based on message ID**, not `limit`/`offset` like the rest of the API. Pass the `nextCursor` from the previous response back as `cursor` to walk backwards through history.
</Warning>

**Response `data`**

```json theme={null}
{
  "messages": [{
    "id": 90210,
    "content": "Doors at 7",
    "type": "USER",
    "created_at": "2026-08-07T04:00:00Z",
    "sender_user_id": "cdd1…",
    "sender": { "id": "cdd1…", "firstname": "Jane", "lastname": "Doe" },
    "is_edited": false,
    "is_deleted": false,
    "reply_to": null,
    "attachments": [],
    "reactions": [{ "emoji": "👍", "user_id": "cdd1…" }],
    "mentions": [],
    "is_pinned": false,
    "thread_reply_count": 2
  }],
  "nextCursor": 90180,
  "prev_cursor": 90180,
  "next_cursor": null
}
```

A few things to expect:

* **Thread replies are not in this feed.** Use the thread endpoint below.
* A message deleted by its author is **omitted**; one removed by an admin comes back as a tombstone with `content: null`.
* Attachments blocked by moderation are stripped from the response.
* Voice notes carry `is_voice_note`, `duration_seconds`, and `waveform_data`.

***

## Read a thread

```text theme={null}
GET /v1/chat/messages/{messageId}/replies
```

Replies to a threaded message, **oldest first**.

| Name     | Type   | Description                                       |
| -------- | ------ | ------------------------------------------------- |
| `limit`  | number | Max 100.                                          |
| `cursor` | number | A message ID — returns replies **newer** than it. |

<Note>
  The cursor runs in the opposite direction to `messages`: threads page forwards, the main feed pages backwards.
</Note>

***

## Pinned messages

```text theme={null}
GET /v1/chat/conversations/{conversationId}/pinned
```

Often the most useful single call on a channel — pins are where load-in details, addresses, and running orders end up.

**Response `data`:** array of `{ pin_id, pinned_by_user_id, pinned_at, message }`.

***

## Reactions

```text theme={null}
GET /v1/chat/messages/{messageId}/reactions
```

**Response `data`:** `[{ "emoji": "👍", "count": 3, "reactors": [{ "userId": "cdd1…", "name": "Jane Doe", "isYou": false }] }]`

***

## Search messages

```text theme={null}
GET /v1/tours/{tourId}/chat/search?query=load%20in
```

Searches every channel and group chat the user is in.

| Name             | Type   | Description                                   |
| ---------------- | ------ | --------------------------------------------- |
| `query`          | string | Required.                                     |
| `conversationId` | number | Restrict to one conversation.                 |
| `limit`          | number | Default 20.                                   |
| `cursor`         | number | A message ID — returns matches older than it. |

**Response `data`:** `{ messages: [...], nextCursor }`. Each hit carries the `conversation` it came from. Hits in DMs are removed.

***

## Search files

```text theme={null}
GET /v1/chat/conversations/{conversationId}/files?query=rider
```

Files and images shared in a conversation, matched by name.

***

## Not available

Deliberately not exposed: read receipts, presence, mention candidates, report reasons, and any write operation. If your integration needs one of these, [get in touch](/apply-for-access).

***

See also: [Tours](/endpoints/tours), [Scopes & Permissions](/scopes).
