# 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`

## Operations

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

## Key fields

Fields of one link between a deal and a contact. They are returned in every item of `data`, and `contactId`, `isPrimary`, and `sort` are also passed in link and replace requests.

| Field | Description |
|------|----------|
| `contactId` | Contact ID. List: [`GET /v1/contacts`](/docs/entities/contacts/list) |
| `isPrimary` | Primary contact of the deal. `true` on exactly one link |
| `sort` | Position of the contact in the list. The link list is returned sorted by this field |
| `roleId` | Role of the contact in the deal. The link methods do not save it: `roleId` in a request is ignored |

The deal fields `contactId` and `contactIds` are described in [Deal fields](/docs/entities/deals/fields).

## What to know before you start

1. **A deal with contacts always has a primary one.** The first linked contact becomes primary, even if `isPrimary: false` is passed. `isPrimary: true` in a link or replace request moves the flag to that contact. If no item in a replace request has `true`, the first item of the array becomes primary; if several items have `true`, the first of them does. If you unlink the primary contact, the first remaining contact in `sort` order becomes primary.
2. **Contact existence is not checked.** Link and replace accept an ID that matches no contact, return `200`, and save the link. Check the ID with [`GET /v1/contacts/:id`](/docs/entities/contacts/get) before linking.
3. **Repeated calls behave differently.** Linking the same contact again returns `409 RELATION_ALREADY_EXISTS`, unlinking one contact again returns `404 ENTITY_NOT_FOUND`, and unlinking all contacts again still returns `204`.
4. **Write methods respond differently.** Link and replace return the whole link list 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 deal: [`GET /v1/deals/:id/contacts`](./contacts-list.md).
3. Link a contact and make it primary if needed: [`POST /v1/deals/:id/contacts`](./contacts-create.md) with `isPrimary: true`.
4. Replace the whole set of contacts, for example when syncing with an external system: [`PUT /v1/deals/:id/contacts`](./contacts-set.md) with all the required contacts in `items`.
5. Read the deal together with the full contact records: [`GET /v1/deals/:id?include=contact`](/docs/entities/deals/get); the contacts are in `data._included.contacts`.

## Limits

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

## See also

- [Deals](/docs/entities/deals)
- [Get deal](/docs/entities/deals/get)
- [Deal fields](/docs/entities/deals/fields)
- [Contacts](/docs/entities/contacts)
- [Limits and optimization](/docs/optimization)
