# Company contacts

Links contacts to a company, reads their list, replaces the whole set, and unlinks contacts one at a time or all at once. A link stores the contact's position in the list. Unlinked contacts stay in the CRM.

The `isPrimary` flag on a link means this company is the contact's primary company: its ID is returned in the contact's `companyId` field. Linking and replacing make the company primary for every contact passed. The IDs of all linked contacts are returned in the company's `contactIds` field.

Bitrix24 API: `crm.company.contact.items.get`, `crm.company.contact.add`, `crm.company.contact.items.set`, `crm.company.contact.delete`, `crm.company.contact.items.delete`
Scope: `crm`

## Operations

- [List company contacts](./contacts-list.md) — `GET /v1/companies/:id/contacts`
- [Replace company contacts](./contacts-set.md) — `PUT /v1/companies/:id/contacts`
- [Link a contact to a company](./contacts-create.md) — `POST /v1/companies/:id/contacts`
- [Unlink a contact from a company](./contacts-delete-delete.md) — `DELETE /v1/companies/:id/contacts/:relatedId`
- [Unlink all contacts from a company](./contacts-delete.md) — `DELETE /v1/companies/:id/contacts`

## Key fields

Fields of a single company–contact link. They are returned in every item of the list, link, and replace responses; `contactId` and `sort` are also passed in link and replace requests.

| Field | Description |
|------|----------|
| `contactId` | Contact ID. List: [`GET /v1/contacts`](/docs/entities/contacts/list) |
| `isPrimary` | The company is primary for this contact. Linking and replacing set `true`; the value from the request is ignored |
| `sort` | The contact's position in the list. The list of links is returned sorted by this field |
| `roleId` | The contact's role in the company. The link methods do not save it: `roleId` from the request is ignored |

## What to know before you start

1. **The primary flag belongs to the contact, not to the company.** `isPrimary: true` means this company is the contact's primary company, and its ID is returned in the contact's `companyId` field. Linking and replacing make the company primary for every contact passed; `isPrimary` from the request is ignored. The link to the contact's previous primary company gets `isPrimary: false`, so `true` can be set on several contacts of a company or on none of them.
2. **Unlinking changes the contact's primary company.** If you unlink a contact from its primary company, the contact's `companyId` field contains the ID of another of its companies, or `0` if it has no other companies. The `isPrimary` flag on the contact's remaining links does not change.
3. **Contact existence is not checked.** Linking and replacing accept an ID that does not belong to any contact, return `200`, and save the link. Check the ID with [`GET /v1/contacts/:id`](/docs/entities/contacts/get) before linking.
4. **The list does not check the company.** For an ID that does not belong to any company, an empty contact list is returned with `200`, just as for a company without contacts. Check the company with [`GET /v1/companies/:id`](/docs/entities/companies/get): it returns `404` for such an ID.
5. **Repeated calls behave differently.** Linking the same contact again returns `409 RELATION_ALREADY_EXISTS`, unlinking a single contact again returns `404 ENTITY_NOT_FOUND`, and unlinking all contacts again still returns `204`.
6. **Write methods respond differently.** Linking and replacing return the full list of links after the change; both unlink methods return `204 No Content` with an empty body.

## Typical scenario

1. Find a contact: [`GET /v1/contacts`](/docs/entities/contacts/list) with a filter on contact fields.
2. See which contacts are already linked to the company: [`GET /v1/companies/:id/contacts`](./contacts-list.md).
3. Link the contact and set its position in the list: [`POST /v1/companies/:id/contacts`](./contacts-create.md) with `sort`. The company becomes the contact's primary company.
4. Define the whole set of contacts at once, for example when syncing with an external system: [`PUT /v1/companies/:id/contacts`](./contacts-set.md) with all required contacts in `items`.
5. Read the company together with the full contact records: [`GET /v1/companies/:id?include=contact`](/docs/entities/companies/get); the contacts are returned in `data._included.contacts`. The `include` value is `contact`, singular.

## Limits

| Limit | Value |
|-------|----------|
| List pagination | None: [`GET /v1/companies/:id/contacts`](./contacts-list.md) returns all of the company's links in one call |
| List read rate | Route limit: 300 requests per minute per Bitrix24 account; all API keys of the account share one limit. The current route limit is returned in the `x-ratelimit-limit` header |
| Write rate | General API limits — [Limits and optimization](/docs/optimization) |
| Contacts per link call | One. To link several contacts at once, use [`PUT /v1/companies/:id/contacts`](./contacts-set.md) and pass the full required set in its `items`: contacts missing from `items` are unlinked |

## See also

- [Companies](/docs/entities/companies)
- [Get company](/docs/entities/companies/get)
- [Contacts](/docs/entities/contacts)
- [Contact companies](/docs/entities/contacts/companies)
- [Related data (include)](/docs/includes)
- [Limits and optimization](/docs/optimization)
