For AI agents: markdown of this page — /docs-content-en/entities/contacts/companies.md documentation index — /llms.txt
Contact companies
Links companies to a contact, replaces the whole set, reads the list, and unlinks companies one at a time or all at once. A binding stores the company's position in the list and the primary-company flag. Unlinked companies stay in the CRM.
A contact with companies always has one primary company. Its ID arrives in the contact's companyId field, and the IDs of all linked companies arrive in the companyIds field in sort order. The companyIds field is writable: PATCH /v1/contacts/:id with it replaces the whole set of companies, the same way as PUT /v1/contacts/:id/companies. Companies missing from the array are unlinked.
Bitrix24 API: crm.contact.company.items.get, crm.contact.company.add, crm.contact.company.items.set, crm.contact.company.delete, crm.contact.company.items.delete
Scope: crm
List contact companies
GET /v1/contacts/:id/companies
Returns all companies linked to a contact, so you know the current set before linking, replacing, or unlinking.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id (path) |
number | yes | Contact ID. List: GET /v1/contacts |
There is no pagination: the response contains all of the contact's bindings in one call.
Examples
curl — personal key
curl "https://vibecode.bitrix24.com/v1/contacts/2943/companies" \
-H "X-Api-Key: YOUR_API_KEY"
curl — OAuth application
curl "https://vibecode.bitrix24.com/v1/contacts/2943/companies" \
-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/contacts/2943/companies', {
headers: {
'X-Api-Key': 'YOUR_API_KEY',
},
})
const { success, data } = await res.json()
const primary = data.find((link) => link.isPrimary)
console.log('Primary company:', primary?.companyId)
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/contacts/2943/companies', {
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
})
const { success, data } = await res.json()
Response fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true on success |
data |
array | The contact's company bindings in sort order. For a contact without companies — an empty array |
data[].companyId |
number | Company ID. Get the company: GET /v1/companies/:id |
data[].isPrimary |
boolean | The contact's primary company. For a contact with companies, true on exactly one binding |
data[].sort |
number | The company's position in the list |
data[].roleId |
number | Binding role. The binding methods do not save it |
Response example
{
"success": true,
"data": [
{ "companyId": 3099, "sort": 10, "isPrimary": false, "roleId": 0 },
{ "companyId": 3101, "sort": 20, "isPrimary": true, "roleId": 0 },
{ "companyId": 3103, "sort": 30, "isPrimary": false, "roleId": 0 }
]
}
Error response example
400 — id in the path is not a positive integer:
{
"success": false,
"error": {
"code": "INVALID_PARAMS",
"message": "id must be a positive integer"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_PARAMS |
id is not a positive integer, for example abc |
| 401 | MISSING_API_KEY |
The X-Api-Key header is missing |
| 401 | TOKEN_MISSING |
No Bitrix24 tokens are attached to the key |
| 403 | SCOPE_DENIED |
The key lacks the crm scope |
| 429 | RATE_LIMITED |
Rate limit exceeded: 300 requests per minute per portal, all API keys of the portal share one limit. The exact value arrives in the x-ratelimit-limit header (the cap is divided across replicas). Retry after the delay in the Retry-After header |
| 502 | BITRIX_UNAVAILABLE |
Bitrix24 is unavailable. Retry the request later |
Full list of common API errors — Errors.
Known specifics
- An empty list for a nonexistent contact too. For an ID that does not belong to any contact, the method returns
200with an emptydata, as for a contact without companies. To tell these cases apart, request the contact withGET /v1/contacts/:id: for a nonexistent contact it returns404 ENTITY_NOT_FOUND. - An ID in the list might not point to an existing company. Linking does not check the company ID, so the list can contain an ID that does not belong to any company. Before working with a company, request it with
GET /v1/companies/:id. - Companies together with the contact.
GET /v1/contacts/:id?include=companyBindingreturns the contact and the full records of all linked companies indata._included.companyBindings; withinclude=company, only the primary company indata._included.company. The primary company's ID arrives in the contact fieldcompanyId, and the IDs of all linked companies incompanyIds.