## Load a chat

`GET /v1/chats/:dialogId/load`

Opens a chat in one request — the v2 messenger method `im.v2.Chat.load`: the chat card, the first page of messages, pinned messages, participants and files. The first page is built around the last read message, or around the unread mark when the chat is marked as unread. The `me` alias passed as `dialogId` addresses the current user's personal dialog.

## Parameters

| Parameter | Type | Required | Default | Description |
|----------|-----|:-----:|-----------|---------|
| `dialogId` (path) | string | yes | — | Dialog ID: a numeric user ID for private messages, `chatXXX` for group chats, `me` — the current user's personal dialog. It comes from the `dialogId` field of a [recent dialogs](/docs/chats/discovery/recent) row; a user ID comes from the [user list](/docs/entities/users/list) |
| `messageLimit` (query) | number | no | 50 | How many messages to take on each side of the pivot message: the page holds up to `messageLimit` messages before it, the message itself and up to `messageLimit` after. From 1 to 200: a value outside the range is clamped, echoed as `meta.requestedMessageLimit` and `meta.appliedMessageLimit` |
| `pinLimit` (query) | number | no | 50 | How many pinned messages to return. From 1 to 200, echoed as `meta.requestedPinLimit` and `meta.appliedPinLimit` |
| `ignoreMark` (query) | boolean | no | `false` | `true` — build the first page from the last read message, ignoring the "unread" mark |
| `shallow` (query) | boolean | no | `false` | `true` — the lightweight load, see below. With `true` no other parameter is accepted. A value other than `true` and `false` is rejected |

Other or repeated parameters are rejected with `400 INVALID_PARAMS`.

**The lightweight load.** `shallow=true` opens the chat with the v2 messenger method `im.v2.Chat.shallowLoad`: `data` carries the chat card, its members and the chat context — `recentConfig`, `parentChat`, `copilot`, `messagesAutoDeleteConfigs`, `callInfo` — but no page of messages, no pinned messages, no files and no `hasPrevPage` / `hasNextPage` flags. This is the call for a chat header or a settings screen. The lightweight load may make you a member too; for an ordinary employee personal key this is a permitted named read of an existing chat. `shallow=false` is the full load; without `shallow` the response and the refusals are unchanged.

**Read-only key.** In `READONLY` mode, this request reads an existing chat: pass its `chatN`, or a numeric peer ID confirmed in the same employee's recent dialogs. For `me`, the check requires an existing personal dialog. The check scans at most 4000 raw rows of recent dialogs; if the binding is not confirmed, the request returns `403 WRITE_BLOCKED_READONLY_KEY` without calling a method that could create a chat. The check's limits and the permitted read effects are described in [access rights](/docs/access-rights).

This exception for named reads applies only to an ordinary employee personal key, whether it uses a webhook or previously configured OAuth tokens. An application key with a user Bearer session, a management key, or a key whose owner type is unconfirmed receives `403 WRITE_BLOCKED_READONLY_KEY` in `READONLY` or `PORTAL_READONLY` mode before the existing-chat binding check and before the named messenger method is called. Ordinary reads without these effects remain available to application keys; read/write mode is unchanged.

## Examples

### curl — personal key

```bash
curl "https://vibecode.bitrix24.com/v1/chats/chat42/load?messageLimit=30" \
  -H "X-Api-Key: YOUR_API_KEY"
```

### curl — OAuth application

```bash
curl "https://vibecode.bitrix24.com/v1/chats/chat42/load?messageLimit=30" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

### JavaScript — personal key

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/chats/chat42/load?messageLimit=30', {
  headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})

const { data } = await res.json()
console.log('Chat:', data.chat.name)
console.log('Messages:', data.messages.length, 'has older:', data.hasPrevPage)
```

### JavaScript — OAuth application

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/chats/chat42/load?messageLimit=30', {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

const { data } = await res.json()
console.log('Chat:', data.chat.name)
console.log('Messages:', data.messages.length, 'has older:', data.hasPrevPage)
```

### curl — the lightweight load

```bash
curl "https://vibecode.bitrix24.com/v1/chats/chat42/load?shallow=true" \
  -H "X-Api-Key: YOUR_API_KEY"
```

## Response fields

| Field | Type | Description |
|------|-----|---------|
| `success` | boolean | Always `true` on success |
| `data.chat` | object | The chat card: `id`, `dialogId`, `name`, `type`, `owner`, `role`, `entityType`, `entityId`, `permissions` and other fields |
| `data.messages` | array | The first page of messages |
| `data.messages[].id` | number | Message ID — the `lastId` cursor for the next page and the `messageId` for [messages around a message](/docs/chats/messages/context) |
| `data.messages[].chatId` | number | Chat ID — equals `data.chat.id` |
| `data.messages[].authorId` | number | Author ID — the profile is in `data.users` of the same response or can be fetched [by user ID](/docs/entities/users/get). `0` — a system message |
| `data.messages[].date` | string | Date sent (ISO 8601) |
| `data.messages[].text` | string | Message text |
| `data.messages[].params` | object | Additional message parameters, keys in camelCase |
| `data.pins` | array | Pinned messages |
| `data.users` | array | Participants mentioned on the page |
| `data.files` | array | Files attached to the messages on the page |
| `data.reactions` | array | Reactions to the messages on the page |
| `data.hasPrevPage` | boolean | Whether there are messages older than the first page |
| `data.hasNextPage` | boolean | Whether there are messages newer than the first page |
| `data.recentConfig` | object | Chat context: which sections of the chat list show the chat |
| `data.parentChat` | object\|null | Chat context: a short card of the parent chat, or `null` |
| `data.copilot` | object\|null | Chat context: the CoPilot roles; `null` outside CoPilot chats |
| `data.messagesAutoDeleteConfigs` | array | Chat context: message auto-deletion settings |
| `data.callInfo` | object | Chat context: `chatId` and `token` — the current user's call token. The endpoint passes it through unchanged; do not write it to logs |
| `meta.requestedMessageLimit` | number | The passed `messageLimit` when it falls outside the range from 1 to 200 |
| `meta.appliedMessageLimit` | number | The applied `messageLimit` value |
| `meta.requestedPinLimit` | number | The passed `pinLimit` value, present when it falls outside the range from 1 to 200 |
| `meta.appliedPinLimit` | number | The applied `pinLimit` value |

## Response example

```json
{
  "success": true,
  "data": {
    "chat": {
      "id": 42,
      "dialogId": "chat42",
      "name": "Project",
      "type": "chat",
      "owner": 5,
      "role": "member"
    },
    "messages": [
      {
        "id": 1002,
        "chatId": 42,
        "authorId": 7,
        "date": "2026-09-20T10:01:00+00:00",
        "text": "All done",
        "params": {}
      }
    ],
    "pins": [],
    "users": [],
    "files": [],
    "reactions": [],
    "hasPrevPage": true,
    "hasNextPage": false
  }
}
```

## Error response example

422 — the chat does not exist in the Bitrix24 account:

```json
{
  "success": false,
  "error": {
    "code": "BITRIX_ERROR",
    "message": "Specified chat does not exist.",
    "hint": "dialogId must be a userId (number as string) for DMs or \"chat{N}\" for group chats. Examples: \"1\" for user 1, \"chat123\" for group chat 123. Create a group chat first via POST /v1/bots/:botId/chats if needed.",
    "b24Code": "CHAT_NOT_FOUND"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|---------|
| 400 | `INVALID_PARAMS` | A parameter outside the allowed set (`messageLimit`, `pinLimit`, `ignoreMark`, `shallow`), a repeated parameter, or an invalid value; with `shallow=true` — any other parameter; `shallow` other than `true` and `false`. Checked before any call to Bitrix24 |
| 404 | `ENTITY_NOT_FOUND` | Bitrix24 answered "not found"; the portal code is in `error.b24Code` |
| 422 | `BITRIX_ERROR` | Bitrix24 returned an error; the portal code is in `error.b24Code`. A missing chat lands here too: the portal answers `CHAT_NOT_FOUND` with the text "Specified chat does not exist.", which is not recognized as "not found", so it is not a 404 |
| 502 | `ME_ALIAS_RESOLUTION_FAILED` | Failed to resolve the user when using the `me` alias |
| 403 | `BITRIX_ACCESS_DENIED` | The user has no access to the chat — Bitrix24 refused with the `ACCESS_DENIED` code |
| 403 | `WRITE_BLOCKED_READONLY_KEY` | Read-only mode: the existing chat was not confirmed in the bounded window of recent dialogs, or a creating or ambiguous alias was passed. The method that would create the chat is not sent to the portal |
| 403 | `WRITE_BLOCKED_READONLY_KEY` | The named read in `READONLY` or `PORTAL_READONLY` mode is unavailable to an application key, a management key, or a key whose owner type is unconfirmed |
| 403 | `SCOPE_DENIED` | The API key does not have the `im` scope |
| 401 | `TOKEN_MISSING` | The API key has no Bitrix24 tokens configured |

The full list of general API errors — [Errors](/docs/errors).

## Known specifics

**Opening a chat may make you a member.** When the chat allows auto-join — for example, comment chats, collabs, task chats — the call adds the current user as a member, as opening the chat in the Bitrix24 interface does. This is Bitrix24 behavior, and the endpoint does not hide it. A `READONLY` key is allowed this read operation as a targeted exception; the user's permissions and the `im` scope are still checked. Opening the chat does not itself mark messages as read. [Access rights](/docs/access-rights) describes the other `Chat.load` effects: presence updates, quick file access after a permission check, PullWatch, and a background external-chat event that can trigger lazy project conversion. The same auto-join exception applies to [message history in the v2 mode](/docs/chats/messages/list) and [messages around a message](/docs/chats/messages/context).

**Response keys.** Keys that name fields are converted to camelCase: the `FILE_ID` message parameter arrives as `fileId`. Keys that are data stay as they are: the `data.copilot.roles` dictionary is keyed by the role code, and `copilot_assistant` arrives as `copilot_assistant` — the same value that `role` carries on a chat and a message in `data.copilot`, so you can look up a role directly with `roles[role]`. Fields inside a role are converted to camelCase as usual.

**Continue in the message history.** Load older messages with the [message history in the v2 mode](/docs/chats/messages/list), passing `lastId` equal to the smallest `id` on the page.

**The lightweight load has no messages.** With `shallow=true`, `data` holds only `chat`, `users` and the chat context. Read the page of messages afterwards with the [message history in the v2 mode](/docs/chats/messages/list), and to open the chat at a specific message use [loading around a message](/docs/chats/messages/load-in-context).

## See also

- [Read messages](/docs/chats/messages/list)
- [Messages around a message](/docs/chats/messages/context)
- [Load around a message](/docs/chats/messages/load-in-context)
- [Unread counters](/docs/chats/discovery/counters)
