How to Add a Template and Create a Document Based on It
Scope:
crmWho can execute the method: users with administrative access to the CRM section
If you are developing integrations for Bitrix24 using AI tools (Codex, Claude Code, Cursor), connect to the MCP server so that the assistant can utilize the official REST documentation.
You can automate document handling in CRM using a script. It will perform the complete document generation cycle: create a number generator, upload a template in .docx format, and generate a document for a specific deal.
To create a document, we will sequentially execute the following methods:
-
crm.documentgenerator.numerator.add — create a document number generator,
-
crm.documentgenerator.template.add — upload the document template,
-
crm.documentgenerator.document.add — generate the document.
Preparing Variables
Let's define the main variables that we will use during the document generation process.
-
filePath— the path to the template file. We will specifytemplate.docx. -
iDealID— the deal identifier. We will create a document for the deal with the identifier1. -
sDocName— the name of the document being created. We will specifyProduct Demonstration Implementation.
How to Use Examples in Documentation
let filePath = 'template.docx';
let iDealID = 1;
let sDocName = 'Product Demonstration Implementation';
$filePath = __DIR__ . '/template.docx';
$iDealID = 1;
$sDocName = 'Product Demonstration Implementation';
1. Create a Document Number Generator
We will create a number generator for documents using crm.documentgenerator.numerator.add. We will pass two parameters to the method.
-
name— the name of the number generator. We will specifyRest Numerator. -
template— the template from which the document number will be generated. We will specify{NUMBER}— this variable will be replaced with the sequential number. Other variables can also be used, for example,{DAY}— the current day,{CLIENT_ID}— the client identifier,{RANDOM}— a random number.
BX24.callMethod(
'crm.documentgenerator.numerator.add',
{
'fields': {
'name': 'Rest Numerator',
'template': '{NUMBER}'
}
},
function(resNum) {
if (resNum.error()) {
console.error(resNum.error());
alert('Number generator not added: ' + resNum.error_description());
return;
}
}
);
$resNum = CRest::call(
'crm.documentgenerator.numerator.add',
[
'fields' => [
'name' => 'Rest Numerator',
'template' => '{NUMBER}',
]
]
);
The method crm.documentgenerator.numerator.add will return an object resNum with information about the created number generator.
"numerator": {
"name": "Rest Numerator",
"template": "{NUMBER}",
"id": 43,
"code": null,
"settings": {
"Bitrix_Main_Numerator_Generator_SequentNumberGenerator": {
"start": 1,
"step": 1,
"length": 0,
"padString": "0",
"periodicBy": null,
"timezone": null,
"isDirectNumeration": false
}
}
}
2. Upload the Document Template
If the number generator is created, we will add the document template using the method crm.documentgenerator.template.add.
The content of the template file needs to be converted to Base64.
In crm.documentgenerator.template.add, we need to pass the following data:
-
name— the name of the template. We will specify the variablesDocName. -
numeratorId— the identifier of the number generator. We will pass it from the objectresNum, which we obtained in the first step. -
region— the region of the template. This affects localization, such as currency and date. We will specifyde— Germany. -
users— an array of access permissions. This defines which user groups can see and use the template. We will specifyUA— all authorized users. -
entityTypeId— the identifier of the CRM object type. We will specify2— deal. A complete list of object types can be obtained using the method crm.enum.ownertype. -
file— the content of the filefilePath, which has been converted to Base64.
function fileToBase64(filePath) {
return new Promise((resolve, reject) => {
fetch(filePath)
.then(response => response.blob())
.then(blob => {
let reader = new FileReader();
reader.onloadend = () => resolve(reader.result.split(',')[1]);
reader.onerror = reject;
reader.readAsDataURL(blob);
});
});
}
let fileContent = await fileToBase64(filePath);
BX24.callMethod(
'crm.documentgenerator.template.add',
{
'fields': {
'name': sDocName,
'numeratorId': resNum.data().numerator.id,
'region': 'de',
'users': ['UA'],
'entityTypeId': ['2'],
'file': fileContent
}
},
function(resTemplate) {
if (resTemplate.error()) {
console.error(resTemplate.error());
alert('Template not added: ' + resTemplate.error_description());
return;
}
}
);
$resTemplate = CRest::call(
'crm.documentgenerator.template.add',
[
'fields' => [
'name' => $sDocName,
'numeratorId' => $resNum['result']['numerator']['id'],
'region' => 'de',
'users' => [
'UA' // User All
],
'entityTypeId' => ['2'],
'file' => base64_encode(file_get_contents($filePath))
]
]
);
The method crm.documentgenerator.template.add will return an object resTemplate with information about the template.
template: {
"id": "39",
"name": "Product Demonstration Implementation",
"region": "de",
"active": "Y",
"code": null,
"createTime": "2025-07-09T16:12:13+03:00",
"download": "https://some-domain.bitrix24.com/bitrix/services/main/ajax.php?action=crm.documentgenerator.template.download&SITE_ID=s1&id=39",
"downloadMachine": "https://some-domain.bitrix24.com/rest/crm.documentgenerator.template.download.json?sessid=c4ad892d7583ead4fd38666a0af85cb7&token=crm%7CYWN0aW9uPWNybS5kb2N1bWVudGdlbmVyYXRvci50ZW1wbGF0ZS5kb3dubG9hZCZTSVRFX0lEPXMxJmlkPTM5Jl89azNRNlFuVVRvUGl5VzNLaExTVDJCR3g1WjdyQ0tSSFA%3D%7CImNybS5kb2N1bWVudGdlbmVyYXRvci50ZW1wbGF0ZS5kb3dubG9hZHxjcm18WVdOMGFXOXVQV055YlM1a2IyTjFiV1Z1ZEdkbGJtVnlZWFJ2Y2k1MFpXMXdiR0YwWlM1a2IzZHViRzloWkNaVFNWUkZYMGxFUFhNeEptbGtQVE01Smw4OWF6TlJObEZ1VlZSdlVHbDVWek5MYUV4VFZESkNSM2cxV2pkeVEwdFNTRkE9fGM0YWQ4OTJkNzU4M2VhZDRmZDM4NjY2YTBhZjg1Y2I3Ig%3D%3D.GMgjAbCT099xlo8CJN9n5mP2s7MBbqfU%2BbEM%2FAzpoYE%3D",
"entityTypeId": [ "0": "2" ],
"length": 1,
"numeratorId": "43",
"users": [ "0": "UA" ],
"sort": 500
}
3. Generate the Document
If the template is successfully uploaded, we will create a document for the deal using the method crm.documentgenerator.document.add. We will specify three parameters in the method.
-
templateId— the identifier of the template. We will pass it from the objectresTemplate, which we obtained in the second step. -
entityTypeId— the identifier of the CRM object type. We will specify2— deal. A complete list of object types can be obtained using the method crm.enum.ownertype. -
entityId— the identifier of the deal. We will specify the variableiDealID.
BX24.callMethod(
'crm.documentgenerator.document.add',
{
'templateId': resTemplate.data().template.id,
'entityTypeId': '2',
'entityId': iDealID
},
function(resDoc) {
if (resDoc.error()) {
console.error(resDoc.error());
alert('Document not created: ' + resDoc.error_description());
} else {
alert('Document created');
}
}
);
$resDoc = CRest::call(
'crm.documentgenerator.document.add',
[
'templateId' => $resTemplate['result']['template']['id'],
'entityTypeId' => '2',
'entityId' => $iDealID,
]
);
The document will be generated, and the method crm.documentgenerator.document.add will return its parameters.
"document": {
"products": {
"currencyId": "EUR",
"totalSum": 1500,
"totalRows": 1
},
"downloadUrl": "https://some-domain.bitrix24.com/bitrix/services/main/ajax.php?action=crm.documentgenerator.document.download&SITE_ID=s1&id=29",
"publicUrl": null,
"title": "Product Demonstration Implementation 1",
"number": "1",
"id": 29,
"createTime": "2025-07-09T16:29:27+03:00",
"createdBy": 27,
"updateTime": "2025-07-09T16:29:27+03:00",
"templateId": "39",
"emailDiskFile": 4917,
"entityId": "1",
"entityTypeId": "2",
"downloadUrlMachine": "https://some-domain.bitrix24.com/rest/crm.documentgenerator.document.download.json?sessid=c4ad892d7583ead4fd38666a0af85cb7&token=crm%7CYWN0aW9uPWNybS5kb2N1bWVudGdlbmVyYXRvci5kb2N1bWVudC5kb3dubG9hZCZTSVRFX0lEPXMxJmlkPTI5Jl89YlQ2SU9XeGVnR2s3NnZ5M0hGVlRxTDVaRlJtdFgyNTE%3D%7CImNybS5kb2N1bWVudGdlbmVyYXRvci5kb2N1bWVudC5kb3dubG9hZHxjcm18WVdOMGFXOXVQV055YlM1a2IyTjFiV1Z1ZEdkbGJtVnlZWFJ2Y2k1a2IyTjFiV1Z1ZEM1a2IzZHViRzloWkNaVFNWUkZYMGxFUFhNeEptbGtQVEk1Smw4OVlsUTJTVTlYZUdWblIyczNOblo1TTBoR1ZsUnhURFZhUmxKdGRGZ3lOVEU9fGM0YWQ4OTJkNzU4M2VhZDRmZDM4NjY2YTBhZjg1Y2I3Ig%3D%3D.H575mM4Mf%2Fj4PVH2Ngzb1kmkQhdScsAL75ZJkbYkALk%3D"
}
Code Example
document.addEventListener('DOMContentLoaded', function() {
let filePath = 'template.docx'; // path to the local template file
let iDealID = 1; // deal identifier
let sDocName = 'Product Demonstration Implementation';
function fileToBase64(filePath) {
return new Promise((resolve, reject) => {
fetch(filePath)
.then(response => response.blob())
.then(blob => {
let reader = new FileReader();
reader.onloadend = () => resolve(reader.result.split(',')[1]);
reader.onerror = reject;
reader.readAsDataURL(blob);
});
});
}
async function createDocument() {
try {
let fileContent = await fileToBase64(filePath);
BX24.callMethod(
'crm.documentgenerator.numerator.add',
{
'fields': {
'name': 'Rest Numerator',
'template': '{NUMBER}'
}
},
function(resNum) {
if (resNum.error()) {
console.error(resNum.error());
alert('Number generator not added: ' + resNum.error_description());
return;
}
if (resNum.data().numerator.id) {
BX24.callMethod(
'crm.documentgenerator.template.add',
{
'fields': {
'name': sDocName,
'numeratorId': resNum.data().numerator.id,
'region': 'de',
'users': ['UA'],
'entityTypeId': ['2'],
'file': fileContent
}
},
function(resTemplate) {
if (resTemplate.error()) {
console.error(resTemplate.error());
alert('Template not added: ' + resTemplate.error_description());
return;
}
if (resTemplate.data().template.id) {
BX24.callMethod(
'crm.documentgenerator.document.add',
{
'templateId': resTemplate.data().template.id,
'entityTypeId': '2',
'entityId': iDealID
},
function(resDoc) {
if (resDoc.error()) {
console.error(resDoc.error());
alert('Document not created: ' + resDoc.error_description());
} else {
alert('Document created');
}
}
);
}
}
);
}
}
);
} catch (error) {
console.error(error);
alert('Error: ' + error.message);
}
}
createDocument();
});
$filePath = __DIR__ . '/template.docx'; // path to the local template file
$iDealID = 1; // deal identifier
$sDocName = 'Product Demonstration Implementation';
$resNum = CRest::call(
'crm.documentgenerator.numerator.add',
[
'fields' => [
'name' => 'Rest Numerator',
'template' => '{NUMBER}',
]
]
);
if (!empty($resNum['result']['numerator']['id'])) {
$resTemplate = CRest::call(
'crm.documentgenerator.template.add',
[
'fields' => [
'name' => $sDocName,
'numeratorId' => $resNum['result']['numerator']['id'], // crm.documentgenerator.numerator.add
'region' => 'de', // eu,de,ua,by,ru
'users' => [
'UA' // User All
],
'entityTypeId' => ['2'], // 2 — deal in CRest::call('crm.enum.ownertype');
'file' => base64_encode(file_get_contents($filePath))
]
]
);
if (!empty($resTemplate['result']['template']['id'])) {
$resDoc = CRest::call(
'crm.documentgenerator.document.add',
[
'templateId' => $resTemplate['result']['template']['id'],
'entityTypeId' => '2', // 2 — deal in CRest::call('crm.enum.ownertype');
'entityId' => $iDealID,
]
);
}
}
if (!empty($resDoc['result'])) {
echo json_encode(['message' => 'Document created']);
} elseif (!empty($resDoc['error_description'])) {
echo json_encode(['message' => 'Document not created: ' . $resDoc['error_description']]);
} else {
echo json_encode(['message' => 'Document not created']);
}