For AI agents: markdown of this page — /docs-content-en/chats/messages/pins.md documentation index — /llms.txt
Pinned messages
GET /v1/chats/:dialogId/pins · POST /v1/chats/messages/:messageId/pin · DELETE /v1/chats/messages/:messageId/pin · GET /v1/chats/:dialogId/pins/count
Four endpoints work with the pinned messages of a chat: the list of pins, pinning, unpinning and the number of pins. They run the v2 messenger methods im.v2.Chat.Pin.tail, im.v2.Chat.Message.pin, im.v2.Chat.Message.unpin and im.v2.Chat.Pin.count. Pinning and unpinning resolve the chat from the message, so they need no dialogId.
List pins
GET /v1/chats/:dialogId/pins
Returns the pins of a chat, latest first by default. The pinned messages themselves come alongside, in data.additionalMessages. The me alias as dialogId addresses the current user's personal dialog — see more in the Chats overview.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
dialogId (path) |
string | yes | — | Dialog ID: numeric user ID for personal messages, chatXXX for group chats. The special me alias — the current user's personal dialog |
lastId (query) |
number | no | — | Cursor: the id of the last pin of the previous page — a pin ID, not a message ID. The boundary itself is not included |
order (query) |
string | no | desc |
desc — latest pins first, asc — earliest first |
limit (query) |
number | no | 50 | Pins per page, from 1 to 200: a value outside the range is clamped and echoed in meta.requestedLimit and meta.appliedLimit |
Any other parameter or a repeated parameter is rejected with 400 INVALID_PARAMS.
Examples
curl — personal key
curl -X GET "https://vibecode.bitrix24.com/v1/chats/chat42/pins" \
-H "X-Api-Key: YOUR_API_KEY"
curl — OAuth application
curl -X GET "https://vibecode.bitrix24.com/v1/chats/chat42/pins" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN"
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/chats/chat42/pins', {
method: 'GET',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
},
})
const { data } = await res.json()
const byId = new Map((data.additionalMessages ?? []).map((m) => [m.id, m]))
console.log('Pinned:', data.pins.map((p) => byId.get(p.messageId)?.text))
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/chats/chat42/pins', {
method: 'GET',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
})
const { data } = await res.json()
const byId = new Map((data.additionalMessages ?? []).map((m) => [m.id, m]))
console.log('Pinned:', data.pins.map((p) => byId.get(p.messageId)?.text))
Response fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true on success |
data.pins |
array | Pins on the page |
data.pins[].id |
number | Pin ID. The list is paged by it |
data.pins[].messageId |
number | ID of the pinned message |
data.pins[].chatId |
number | Chat ID |
data.pins[].authorId |
number | ID of the user who pinned the message |
data.pins[].dateCreate |
string | When the message was pinned (ISO 8601) |
data.additionalMessages |
array | The pinned messages: id, chatId, authorId, date, text, params and other v2 message fields |
data.users |
array | Users referenced by the pins and the pinned messages |
data.files |
array | Files of the pinned messages |
data.reactions |
array | Reactions to the pinned messages |
data.tariffRestrictions |
object | Plan restrictions on the history: isHistoryLimitExceeded |
meta.requestedLimit |
number | The limit passed, when it was outside the range from 1 to 200 |
meta.appliedLimit |
number | The limit value applied |
The response also includes stickers, forwardSource and copilot — collections of the v2 message history common to all responses that carry messages.
Response example
{
"success": true,
"data": {
"pins": [
{
"id": 17,
"messageId": 1001,
"chatId": 42,
"authorId": 5,
"dateCreate": "2026-09-20T10:06:00+00:00"
}
],
"additionalMessages": [
{
"id": 1001,
"chatId": 42,
"authorId": 5,
"date": "2026-09-20T10:00:00+00:00",
"text": "Please review the mockup",
"params": { "isPinned": "Y" }
}
],
"users": [],
"files": [],
"reactions": [],
"stickers": [],
"forwardSource": null,
"copilot": null,
"tariffRestrictions": { "isHistoryLimitExceeded": false }
}
}
Pin a message
POST /v1/chats/messages/:messageId/pin
Pins a message in its chat. No body and no query parameters are accepted.
Examples
curl — personal key
curl -X POST "https://vibecode.bitrix24.com/v1/chats/messages/1001/pin" \
-H "X-Api-Key: YOUR_API_KEY"
curl — OAuth application
curl -X POST "https://vibecode.bitrix24.com/v1/chats/messages/1001/pin" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN"
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/chats/messages/1001/pin', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
},
})
const { data } = await res.json()
console.log('Result:', data)
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/chats/messages/1001/pin', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
})
const { data } = await res.json()
console.log('Result:', data)
Response on success: { "success": true, "data": [] }.
Unpin a message
DELETE /v1/chats/messages/:messageId/pin
Removes the pin from a message. No body and no query parameters are accepted.
Examples
curl — personal key
curl -X DELETE "https://vibecode.bitrix24.com/v1/chats/messages/1001/pin" \
-H "X-Api-Key: YOUR_API_KEY"
curl — OAuth application
curl -X DELETE "https://vibecode.bitrix24.com/v1/chats/messages/1001/pin" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN"
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/chats/messages/1001/pin', {
method: 'DELETE',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
},
})
const { data } = await res.json()
console.log('Result:', data)
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/chats/messages/1001/pin', {
method: 'DELETE',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
})
const { data } = await res.json()
console.log('Result:', data)
Response on success: { "success": true, "data": [] }.
Number of pins
GET /v1/chats/:dialogId/pins/count
Returns how many messages are pinned in the chat. dialogId works the same as for the pins list, including the me alias. Query parameters are rejected with 400 INVALID_PARAMS.
Examples
curl — personal key
curl "https://vibecode.bitrix24.com/v1/chats/chat42/pins/count" \
-H "X-Api-Key: YOUR_API_KEY"
curl — OAuth application
curl "https://vibecode.bitrix24.com/v1/chats/chat42/pins/count" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN"
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/chats/chat42/pins/count', {
headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})
const { data } = await res.json()
console.log('Pinned:', data.counter)
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/chats/chat42/pins/count', {
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
})
const { data } = await res.json()
console.log('Pinned:', data.counter)
Response fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true on success |
data.counter |
number | Number of pinned messages |
Response example
{
"success": true,
"data": { "counter": 2 }
}
Error response example
422 — the message is already pinned:
{
"success": false,
"error": {
"code": "BITRIX_ERROR",
"message": "MESSAGE_IS_ALREADY_PIN",
"b24Code": "MESSAGE_IS_ALREADY_PIN"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_PARAMS |
messageId is not a positive integer; for the list — a parameter other than lastId, order, limit, a repeated parameter or an invalid value; for pinning and unpinning — any body field or query parameter; for the number of pins — any query parameter. Checked before any call to Bitrix24 |
| 404 | ENTITY_NOT_FOUND |
Bitrix24 reported "not found"; the portal code is in error.b24Code |
| 422 | BITRIX_ERROR |
Bitrix24 returned an error; the code is in error.b24Code: MESSAGE_IS_ALREADY_PIN — the message is already pinned, MESSAGE_NOT_FOUND — there is no such message, CHAT_NOT_FOUND — there is no such chat |
| 403 | SCOPE_DENIED |
The API key does not have the im scope |
| 403 | WRITE_BLOCKED_READONLY_KEY |
A read-only key cannot add or remove pins; the list and count are allowed reads — see access rights |
| 401 | TOKEN_MISSING |
The API key has no Bitrix24 tokens configured |
| 502 | ME_ALIAS_RESOLUTION_FAILED |
The me alias could not be resolved: Bitrix24 returned no ID of the current user |
Full list of common API errors — Errors.
Known specifics
The pins list and count may make you a member. When the chat allows auto-join, either read may add the current user as a member, as loading a chat does. A READONLY key may use both audited reads; neither marks messages read.
There is no next-page flag. Bitrix24 returns no hasNextPage for pins. To get the next page, pass lastId equal to the id of the last pin on the page; a page shorter than limit is the last one.
The response for an empty list is shorter. For a chat without pins, only pins, users and tariffRestrictions are returned. The other collections appear with the first pin, so read them with a fallback value.
Pinning shows in the chat. Bitrix24 posts a system message about the pin to the chat, quoting the pinned text. Pinning again is refused with MESSAGE_IS_ALREADY_PIN; unpinning again succeeds.
The number of pins covers only the visible history. If you can see the chat history only from a certain point on — for example, you were added later without access to older messages — pins before that point are not counted.