How to Add a Template and Create a Document Based on It

Scope: crm

Who 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:

  1. crm.documentgenerator.numerator.add — create a document number generator,

  2. crm.documentgenerator.template.add — upload the document template,

  3. 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 specify template.docx.

  • iDealID — the deal identifier. We will create a document for the deal with the identifier 1.

  • sDocName — the name of the document being created. We will specify Product 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 specify Rest 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 variable sDocName.

  • numeratorId — the identifier of the number generator. We will pass it from the object resNum, which we obtained in the first step.

  • region — the region of the template. This affects localization, such as currency and date. We will specify de — Germany.

  • users — an array of access permissions. This defines which user groups can see and use the template. We will specify UA — all authorized users.

  • entityTypeIdthe identifier of the CRM object type. We will specify 2 — deal. A complete list of object types can be obtained using the method crm.enum.ownertype.

  • file — the content of the file filePath, 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.

  1. templateId — the identifier of the template. We will pass it from the object resTemplate, which we obtained in the second step.

  2. entityTypeIdthe identifier of the CRM object type. We will specify 2 — deal. A complete list of object types can be obtained using the method crm.enum.ownertype.

  3. entityId — the identifier of the deal. We will specify the variable iDealID.

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']);
        }