For AI agents: markdown of this page — /docs-content-en/entities/deals/contacts.md documentation index — /llms.txt
Deal contacts
Links contacts to a deal, reads the list of linked contacts, and unlinks them one at a time or all at once. A link stores the contact's position in the list and the primary-contact flag. Unlinking leaves the contacts themselves in the CRM.
A deal with contacts always has exactly one primary contact. Its ID is returned in the deal's contactId field, and the IDs of all linked contacts are returned in the contactIds field. The contactIds field is read-only: PATCH /v1/deals/:id with it returns 400 READONLY_FIELD, so change the set of contacts with the methods below.
Bitrix24 API: crm.deal.contact.items.get, crm.deal.contact.add, crm.deal.contact.items.set, crm.deal.contact.delete, crm.deal.contact.items.delete
Scope: crm
List deal contacts
GET /v1/deals/:id/contacts
Returns all contacts linked to a deal, so that you know the current set before linking, replacing, or unlinking contacts.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
Parameterid (path) |
Typenumber | Requiredyes | DescriptionDeal ID. List: GET /v1/deals |
There is no pagination: one call returns all of the deal's links.
Examples
curl — personal key
curl "https://vibecode.bitrix24.com/v1/deals/8785/contacts" \
-H "X-Api-Key: YOUR_API_KEY"
curl — OAuth application
curl "https://vibecode.bitrix24.com/v1/deals/8785/contacts" \
-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/deals/8785/contacts', {
headers: {
'X-Api-Key': 'YOUR_API_KEY',
},
})
const { success, data } = await res.json()
const primary = data.find((link) => link.isPrimary)
console.log('Primary contact:', primary?.contactId)
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/deals/8785/contacts', {
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
})
const { success, data } = await res.json()
Response fields
| Field | Type | Description |
|---|---|---|
Fieldsuccess |
Typeboolean | DescriptionAlways true on success |
Fielddata |
Typearray | DescriptionLinks between the deal and its contacts, ordered by sort. An empty array for a deal without contacts |
Fielddata[].contactId |
Typenumber | DescriptionContact ID. Get the contact: GET /v1/contacts/:id |
Fielddata[].isPrimary |
Typeboolean | DescriptionPrimary contact of the deal. For a deal with contacts, exactly one link has true |
Fielddata[].sort |
Typenumber | DescriptionPosition of the contact in the list |
Fielddata[].roleId |
Typenumber | DescriptionRole of the contact in the deal. The link methods do not save it |
Response example
{
"success": true,
"data": [
{ "contactId": 2921, "sort": 10, "isPrimary": false, "roleId": 0 },
{ "contactId": 2923, "sort": 20, "isPrimary": true, "roleId": 0 },
{ "contactId": 2925, "sort": 30, "isPrimary": false, "roleId": 0 }
]
}
Error response example
404 — no deal with this id:
{
"success": false,
"error": {
"code": "ENTITY_NOT_FOUND",
"message": "Not found"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| HTTP400 | CodeINVALID_PARAMS |
Descriptionid is not a positive integer, for example abc |
| HTTP404 | CodeENTITY_NOT_FOUND |
DescriptionNo deal with this id |
| HTTP401 | CodeMISSING_API_KEY |
DescriptionThe X-Api-Key header is missing |
| HTTP401 | CodeTOKEN_MISSING |
DescriptionNo Bitrix24 tokens are attached to the key |
| HTTP403 | CodeSCOPE_DENIED |
DescriptionThe key lacks the crm scope |
| HTTP429 | CodeRATE_LIMITED |
DescriptionRate limit exceeded: 300 requests per minute per portal. All API keys of the portal share one limit. The current limit is returned in the x-ratelimit-limit header. Retry after the delay in the Retry-After header |
| HTTP502 | CodeBITRIX_UNAVAILABLE |
DescriptionBitrix24 is unavailable. Retry the request later |
For the full list of common API errors, see Errors.
Known specifics
- A listed ID may not lead to a contact. Linking does not check the contact ID, so the list can contain an ID that matches no contact. Before working with a contact, request it through
GET /v1/contacts/:id. - Contacts together with the deal.
GET /v1/deals/:id?include=contactreturns the deal and the full records of the linked contacts indata._included.contacts. The primary contact ID is returned in the deal'scontactIdfield, and all linked contact IDs are returned incontactIds.