Untuk ejen AI: markdown halaman ini — /docs-content-en/entities/documents/crm-upload.md indeks dokumentasi — /llms.txt
Artikel dokumentasi kini tersedia dalam bahasa Inggeris.
Upload a CRM document
POST /v1/crm-documents/upload
Attaches a ready-made document file, produced outside Bitrix24 without a template, to a CRM record. The file is sent as a base64 string, and the fields go inside the fields object.
Request fields (body)
| Field | Type | Required | Description |
|---|---|---|---|
fields.entityTypeId |
number | yes | CRM record type, a positive integer: 2 — deal, 3 — contact, 4 — company. Other types are in the "CRM record types" list on the GET /v1/crm-documents page |
fields.entityId |
number | yes | Record ID, a positive integer. The source depends on the type: deals — GET /v1/deals, contacts — GET /v1/contacts, companies — GET /v1/companies |
fields.title |
string | yes | Document title |
fields.number |
string | yes | Document number. A number instead of a string is rejected |
fields.region |
string | yes | Document region, for example uk or de |
fields.fileContent |
string | yes | DOCX file content as a base64 string, at most 2 MiB after decoding |
fields.pdfContent |
string | no | PDF version of the document as a base64 string, at most 2 MiB after decoding |
fields.imageContent |
string | no | Document image as a base64 string, at most 2 MiB after decoding |
The whole request body is at most 3 MiB. The id, fileId, pdfId, imageId, moduleId, providerClassName and value fields are set by Bitrix24: a request with any of them is rejected with 400 READONLY_FIELD.
Examples
In the examples, contract.docx is your document file. The request body is assembled into a document.json file and then sent.
curl — personal key
printf '{"fields":{"entityTypeId":2,"entityId":8781,"title":"Supply agreement","number":"VD-1","region":"uk","fileContent":"%s"}}' \
"$(base64 < contract.docx | tr -d '\n')" > document.json
curl -X POST "https://vibecode.bitrix24.com/v1/crm-documents/upload" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @document.json
curl — OAuth application
printf '{"fields":{"entityTypeId":2,"entityId":8781,"title":"Supply agreement","number":"VD-1","region":"uk","fileContent":"%s"}}' \
"$(base64 < contract.docx | tr -d '\n')" > document.json
curl -X POST "https://vibecode.bitrix24.com/v1/crm-documents/upload" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @document.json
JavaScript — personal key
import { readFile } from 'node:fs/promises'
const fileContent = (await readFile('contract.docx')).toString('base64')
const res = await fetch('https://vibecode.bitrix24.com/v1/crm-documents/upload', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
fields: {
entityTypeId: 2,
entityId: 8781,
title: 'Supply agreement',
number: 'VD-1',
region: 'uk',
fileContent,
},
}),
})
const { success, data } = await res.json()
console.log('Document:', data.id)
JavaScript — OAuth application
import { readFile } from 'node:fs/promises'
const fileContent = (await readFile('contract.docx')).toString('base64')
const res = await fetch('https://vibecode.bitrix24.com/v1/crm-documents/upload', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
fields: {
entityTypeId: 2,
entityId: 8781,
title: 'Supply agreement',
number: 'VD-1',
region: 'uk',
fileContent,
},
}),
})
const { success, data } = await res.json()
Response fields
Returns HTTP status 201 Created and the created document. The full description of document fields is on the Get a CRM document page.
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true on success |
data.id |
string | Document ID |
data.title |
string | Title from fields.title |
data.number |
string | Number from fields.number |
data.entityTypeId |
string | CRM record type |
data.entityId |
string | CRM record ID |
data.templateId |
string | Internal template used for uploaded documents. It does not appear in template lists |
data.createdBy |
string | ID of the user who uploaded the document. List: GET /v1/users |
data.downloadUrlMachine |
string | URL of /v1/crm-documents/:id/download. Requires X-Api-Key with the crm scope |
data.pdfUrlMachine |
string | URL of /v1/crm-documents/:id/pdf. Present in the response right away if fields.pdfContent was sent |
Response example
The main fields are shown. Full list: Get a CRM document.
{
"success": true,
"data": {
"downloadUrl": "https://example.bitrix24.com/bitrix/services/main/ajax.php?action=crm.documentgenerator.document.download&SITE_ID=s1&id=1985",
"publicUrl": null,
"title": "Supply agreement",
"number": "VD-1",
"id": "1985",
"createTime": "2026-10-08T17:59:45+00:00",
"createdBy": "1317",
"stampsEnabled": false,
"isTransformationError": false,
"templateId": "275",
"entityId": "8781",
"entityTypeId": "2",
"downloadUrlMachine": "https://vibecode.bitrix24.com/v1/crm-documents/1985/download"
}
}
Error response example
400 — fileContent is not a base64 string:
{
"success": false,
"error": {
"code": "INVALID_PARAMS",
"message": "fileContent must be base64"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | MISSING_REQUIRED_FIELDS |
The fields object is missing. Message: fields is required |
| 400 | MISSING_REQUIRED_FIELDS |
A required field is missing or empty. The message names the fields: Empty required fields: number |
| 400 | READONLY_FIELD |
fields contains a field set by Bitrix24, for example id |
| 400 | INVALID_PARAMS |
entityTypeId or entityId is not a positive integer |
| 400 | INVALID_PARAMS |
title, number or region is not a string |
| 400 | INVALID_PARAMS |
fileContent, pdfContent or imageContent is not a base64 string. The message names the field |
| 400 | INVALID_PARAMS |
The CRM record type in entityTypeId is not supported for documents, for example 999. Message: Wrong "entityTypeId" field value |
| 413 | PAYLOAD_TOO_LARGE |
A file exceeds 2 MiB after decoding. The message names the field: fileContent must not exceed 2 MiB |
| 413 | PAYLOAD_TOO_LARGE |
The request body exceeds 3 MiB. Message: Request body too large |
| 429 | LARGE_BODY_BACKEND_BUSY |
The body exceeds 1 MiB and the platform is already processing the maximum volume of large bodies. Retry the request after Retry-After seconds |
| 502 | BITRIX_INVALID_RESPONSE |
Bitrix24 responded without a document |
| 403 | WRITE_BLOCKED_READONLY_KEY |
The key is read-only |
| 403 | SCOPE_DENIED |
The key lacks the crm scope |
| 401 | MISSING_API_KEY |
The X-Api-Key header is missing |
| 401 | TOKEN_MISSING |
No tokens are mapped to the key — an OAuth application key was called without a user session |
Full list of common API errors — Errors.
Known specifics
The file format is not checked. The only check is that fileContent is a valid base64 string. The file is stored as sent, even if it is not a DOCX, and the DOCX download returns the same bytes.
The record's existence is not checked. A document is created even for an entityId that does not exist among records of this type: the response is 201, including for a contact — unlike creating from a template. A document attached to a non-existent contact cannot be read or deleted afterwards: all methods return 403 BITRIX_ACCESS_DENIED. Check the record beforehand, for example with GET /v1/contacts/:id.
Without pdfContent, the PDF is generated later. If no PDF version is sent, the PDF is generated from the DOCX after the upload, and until then the PDF download returns 409 DOCUMENT_NOT_READY.