How to Create a Comment in a Task and Attach a File
Who can execute the methods: a user with access to the task and its chat
- tasks.task.get — any user with access to the task
- im.v2.File.upload — a user with access to the task chat
- im.v2.File.download — a user with access to the task chat
Choose a tool for developing with an AI agent:
- use Alaio Vibecode to build an app for Bitrix24 from a task description without knowing any programming language. The agent writes the code and deploys the app to a server, with no manual hosting setup
- use the MCP server to develop a REST API integration in your own project. The agent refers to the official REST documentation
Task comments are stored in the task chat. To add a comment with a file, first get the identifier of the task chat, then upload the file to that chat using the im.v2.File.upload method.
The im.v2.File.upload method uploads the file, attaches it to the chat, and sends the message in a single call. You do not need to upload the file to Drive using a separate method.
The scenario consists of two steps.
- Get the task chat
chatIdusing the tasks.task.get method - Send a message with a file using the im.v2.File.upload method
As a result, a comment with an attached file will appear in the task chat. The operation is confirmed by the messageId, chatId, dialogId, and file.id fields in the response of the im.v2.File.upload method.
Before You Start
You need the following to run the example:
- an inbound webhook with the
taskandimscopes - the task
taskId. You can get it using the tasks.task.list method - the file to attach to the comment
- the file name with an extension, for example
file.pdf - the file content in Base64 format without the
data:*/*;base64,prefix
The webhook executes requests with the permissions of the user who created it. Do not publish the webhook secret in client-side code or repositories. Store it in environment variables.
For server-side JS examples with B24Hook, use Node.js 18, 20, 22, or later. For new projects, use 22 or later. B24JsSDK is an ES module: save the code in a .mjs file or add "type": "module" to package.json.
For b24pysdk examples, use Python 3.9 or later.
1. Get the Task Chat chatId
To send a message with a file to the task chat, you need a dialog identifier in the chat{chatId} format. Get chatId using the tasks.task.get method.
Use the following parameters:
taskId— the task identifierselect— the array of fields to return. SpecifyIDandCHAT_ID
How to Use Examples in Documentation
import { B24Hook } from '@bitrix24/b24jssdk'
const $b24 = B24Hook.fromWebhookUrl(process.env.B24_HOOK)
// B24_HOOK = 'https://your-domain.bitrix24.com/rest/USER_ID/TOKEN/'
const taskResponse = await $b24.actions.v2.call.make({
method: 'tasks.task.get',
params: {
taskId: 3711,
select: ['ID', 'CHAT_ID']
},
requestId: 'task-get-chat'
})
if (!taskResponse.isSuccess) {
throw new Error(taskResponse.getErrorMessages().join('; '))
}
const chatId = taskResponse.getData().result.task.chatId
const dialogId = `chat${chatId}`
from b24pysdk import BitrixWebhook, Client
from b24pysdk.errors import BitrixAPIError
token = BitrixWebhook(
domain="your-domain.bitrix24.com",
webhook_token="user_id/webhook_key",
)
client = Client(token)
try:
task = client.tasks.task.get(
bitrix_id=3711,
select=["ID", "CHAT_ID"],
).response.result["task"]
except BitrixAPIError as error:
print(f"Error retrieving the task: {error}")
raise
chat_id = task["chatId"]
dialog_id = f"chat{chat_id}"
require_once 'vendor/autoload.php';
use Bitrix24\SDK\Services\ServiceBuilderFactory;
use Bitrix24\SDK\Core\Exceptions\BaseException;
use Symfony\Component\EventDispatcher\EventDispatcher;
$serviceBuilder = (new ServiceBuilderFactory(new EventDispatcher(), $log))
->initFromWebhook(getenv('B24_HOOK'));
try {
$task = $serviceBuilder->core->call(
'tasks.task.get',
[
'taskId' => 3711,
'select' => ['ID', 'CHAT_ID']
]
)->getResponseData()->getResult()['task'];
} catch (BaseException $e) {
echo 'Error retrieving the task: ' . $e->getMessage();
return;
}
$chatId = $task['chatId'];
$dialogId = 'chat' . $chatId;
As a result, you get the task chat chatId. Convert the value 861 into dialogId: chat861.
{
"result": {
"task": {
"id": "3711",
"chatId": 861
}
}
}
2. Send a Comment with a File
To send a file to the task chat, use the im.v2.File.upload method.
Use the following parameters:
dialogId— the dialog identifier in thechat{chatId}format. For the example from the previous step, this ischat861fields.name— the file name with an extensionfields.content— the file content in Base64 formatfields.message— the comment text
const uploadResponse = await $b24.actions.v2.call.make({
method: 'im.v2.File.upload',
params: {
dialogId,
fields: {
name: 'file.pdf',
content: 'SGVsbG8gV29ybGQh',
message: 'Comment with a file'
}
},
requestId: 'file-upload-to-task-chat'
})
if (!uploadResponse.isSuccess) {
throw new Error(uploadResponse.getErrorMessages().join('; '))
}
const result = uploadResponse.getData().result
console.log(result.messageId, result.file.id)
$b24.destroy()
import base64
from pathlib import Path
file_content = base64.b64encode(Path("file.pdf").read_bytes()).decode()
try {
result = token.call_method(
"im.v2.File.upload",
{
"dialogId": dialog_id,
"fields": {
"name": "file.pdf",
"content": file_content,
"message": "Comment with a file",
},
},
)["result"]
except BitrixAPIError as error:
print(f"Error sending the comment with a file: {error}")
raise
print(result["messageId"], result["file"]["id"])
try {
$response = $serviceBuilder->core->call(
'im.v2.File.upload',
[
'dialogId' => $dialogId,
'fields' => [
'name' => 'file.pdf',
'content' => base64_encode(file_get_contents('/path/to/file.pdf')),
'message' => 'Comment with a file',
],
]
);
} catch (BaseException $e) {
echo 'Error sending the comment with a file: ' . $e->getMessage();
return;
}
$result = $response->getResponseData()->getResult();
echo 'Comment created, MESSAGE_ID: ' . $result['messageId'];
The method returns the message identifier messageId, the chat identifier chatId, the dialog identifier dialogId, and file data in the file object.
{
"result": {
"file": {
"id": 9817,
"chatId": 861,
"type": "file",
"name": "file.pdf",
"extension": "pdf",
"size": 35341,
"status": "done",
"progress": 100,
"authorId": 1
},
"messageId": 38655,
"chatId": 861,
"dialogId": "chat861"
}
}
Check the Result
Open the task with id 3711 and go to the comments. The task chat must contain a message Comment with a file with the attached file file.pdf.
Through REST, verify that the task is linked to the same chat where the file was sent and that the file is available for download.
const checkResponse = await $b24.actions.v2.call.make({
method: 'tasks.task.get',
params: {
taskId: 3711,
select: ['ID', 'CHAT_ID']
},
requestId: 'task-get-check'
})
if (!checkResponse.isSuccess) {
throw new Error(checkResponse.getErrorMessages().join('; '))
}
const task = checkResponse.getData().result.task
console.log(task.chatId)
const fileResponse = await $b24.actions.v2.call.make({
method: 'im.v2.File.download',
params: {
dialogId: result.dialogId,
fileId: result.file.id
},
requestId: 'file-download-check'
})
if (!fileResponse.isSuccess) {
throw new Error(fileResponse.getErrorMessages().join('; '))
}
console.log(fileResponse.getData().result)
task = client.tasks.task.get(
bitrix_id=3711,
select=["ID", "CHAT_ID"],
).response.result["task"]
print(task["chatId"])
file = token.call_method(
"im.v2.File.download",
{
"dialogId": result["dialogId"],
"fileId": result["file"]["id"],
},
)["result"]
print(file)
$task = $serviceBuilder->core->call(
'tasks.task.get',
[
'taskId' => 3711,
'select' => ['ID', 'CHAT_ID']
]
)->getResponseData()->getResult()['task'];
echo 'CHAT_ID: ' . $task['chatId'];
$file = $serviceBuilder->core->call(
'im.v2.File.download',
[
'dialogId' => $result['dialogId'],
'fileId' => $result['file']['id'],
]
)->getResponseData()->getResult();
print_r($file);
The scenario is successful if the task chatId matches the result.chatId value returned by im.v2.File.upload, and the upload response contains the following fields:
result.messageId— the identifier of the message in the task chatresult.dialogId— the identifier of the task dialogresult.file.id— the identifier of the file in Driveresult.file.status— the file upload status. Thedonevalue means the file was uploaded successfully- the response of im.v2.File.download contains a file download link in the
result.downloadUrlfield
Errors and Diagnostics
If the method returns an error, check the request data.
|
Error |
Cause and solution |
|
|
The file name or file content was not passed. Check |
|
|
|
|
|
The file is larger than 100 MB. Reduce the file size or use a different data transfer approach |
|
|
The chat from |
|
|
The webhook user does not have access to the task or the task chat |
Repeat the scenario from the step that returned the error. If tasks.task.get returned the error, verify taskId and the user's permissions. If im.v2.File.upload returned the error, repeat only the second step.
What to Consider
- im.v2.File.upload replaces the outdated chain
im.disk.folder.get+ upload through Drive +im.disk.file.commit - The file is passed in
fields.contentas a Base64 string without thedata:*/*;base64,prefix dialogIdfor a task chat is built fromchatId: ifchatIdis861, passchat861- Re-running the example creates a new message with a file in the task chat