For AI agents: markdown of this page — /docs-content-en/chats/messages/bulk.md documentation index — /llms.txt
Bulk message load
POST /v1/chats/messages/bulk
Loads messages from several dialogs in a single request. Use it to sync multiple chats without extra API calls.
Read-only key. In READONLY mode, every dialogId in the batch must point to an existing chat: its chatN, or a numeric peer ID confirmed in the same employee's recent dialogs. The me literal resolves to the current user's ID and is checked the same way. Other dialogId forms are rejected. The check scans at most 4000 raw rows of recent dialogs for the whole request. If any binding is not confirmed, the whole request returns 403 WRITE_BLOCKED_READONLY_KEY and the batch is not sent to Bitrix24. The check keeps a read from implicitly creating a chat. Bitrix24 still checks the user's access to the chat. The check's limits are described in access rights.
Request body fields
| Field | Type | Required | Description |
|---|---|---|---|
dialogs |
array | yes | Array of dialogs to load. From 1 to 50 items |
dialogs[].dialogId |
string | yes | Dialog ID: numeric user ID, chatXXX, or the literal me. In the response, the result is keyed by the value passed in the request — for me, the key is "me" |
dialogs[].lastId |
number | no | Cursor to load older messages |
dialogs[].firstId |
number | no | Cursor to load newer messages |
dialogs[].limit |
number | no | Number of messages for this dialog (no more than 200) |
Examples
curl — personal key
curl -X POST "https://vibecode.bitrix24.com/v1/chats/messages/bulk" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"dialogs": [
{ "dialogId": "chat42", "limit": 20 },
{ "dialogId": "chat99", "lastId": 5000 }
]
}'
curl — OAuth application
curl -X POST "https://vibecode.bitrix24.com/v1/chats/messages/bulk" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"dialogs": [
{ "dialogId": "chat42", "limit": 20 },
{ "dialogId": "chat99", "lastId": 5000 }
]
}'
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/chats/messages/bulk', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
dialogs: [
{ dialogId: 'chat42', limit: 20 },
{ dialogId: 'chat99', lastId: 5000 },
],
}),
})
const { success, data } = await res.json()
console.log('Summary:', data.summary)
for (const [key, result] of Object.entries(data.results)) {
console.log(`Dialog ${key}:`, result.messages.length, 'messages')
}
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/chats/messages/bulk', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
dialogs: [
{ dialogId: 'chat42', limit: 20 },
{ dialogId: 'chat99', lastId: 5000 },
],
}),
})
const { success, data } = await res.json()
Response fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true on success |
data.results |
object | Map of results: key is the dialogId from the request, value is an object with messages |
data.results.<dialogId>.chatId |
number | Numeric chat ID |
data.results.<dialogId>.messages |
array | Array of dialog messages (fields as in Read messages) |
data.results.<dialogId>.users |
array | Dialog participants with profiles |
data.errors |
object | Map of errors: key is the dialogId, value is an object with a code field |
data.summary.total |
number | Total number of requested dialogs |
data.summary.succeeded |
number | Number of successfully loaded dialogs |
data.summary.failed |
number | Number of dialogs that failed |
Response example
{
"success": true,
"data": {
"results": {
"chat42": {
"chatId": 42,
"messages": [
{
"id": 1001,
"chatId": 42,
"authorId": 5,
"date": "2026-06-05T10:00:00+00:00",
"text": "Hello, team!",
"unread": false,
"uuid": null,
"replaces": [],
"params": [],
"disappearingDate": null
}
],
"users": [
{
"id": 5,
"active": true,
"name": "John Brown",
"firstName": "John",
"lastName": "Brown",
"bot": false,
"type": "user"
}
],
"files": []
}
},
"errors": {},
"summary": {
"total": 1,
"succeeded": 1,
"failed": 0
}
}
}
Error response example
400 — the dialogs array is missing or empty:
{
"success": false,
"error": {
"code": "INVALID_REQUEST",
"message": "Body must contain \"dialogs\" array with at least 1 item. Each item: { dialogId, lastId?, firstId?, limit? }"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_REQUEST |
The dialogs field is missing, empty, or an item has no dialogId |
| 400 | BATCH_LIMIT_EXCEEDED |
Limit exceeded: more than 50 dialogs in a single request |
| 422 | BITRIX_ERROR |
Bitrix24 returned an error while processing the whole batch request |
| 502 | ME_ALIAS_RESOLUTION_FAILED |
Failed to resolve the current user for the me literal. The whole batch is rejected |
| 502 | BITRIX_UNAVAILABLE |
Bitrix24 is unavailable or returned a server error |
| 403 | SCOPE_DENIED |
The key is missing the im scope |
| 403 | WRITE_BLOCKED_READONLY_KEY |
Read-only mode: the bounded window of recent dialogs did not confirm an existing chat for one of the dialogId values, or a dialogId in another form was passed. The batch is not sent to Bitrix24 |
| 401 | TOKEN_MISSING |
No X-Api-Key was passed or tokens are not configured |
Full list of common API errors — Errors.
Known specifics
Partial success. An error for one dialog does not stop processing of the rest. Check data.errors and data.summary.failed to detect partial failures.
50-dialog limit. Set by the Bitrix24 batch-request limit. If you need to process more dialogs, split the request into several parts.
Result keys. The keys in data.results and data.errors match the dialogId field from the request. If you pass several entries with the same dialogId, only the last one gets a result.