
## Contact fields

`GET /v1/contacts/fields`

Returns the full list of available fields, including user fields (`ufCrm*`).

## Examples

### curl — personal key

```bash
curl "https://vibecode.bitrix24.com/v1/contacts/fields" \
  -H "X-Api-Key: YOUR_API_KEY"
```

### curl — OAuth application

```bash
curl "https://vibecode.bitrix24.com/v1/contacts/fields" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

### JavaScript — personal key

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/contacts/fields', {
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
  },
})

const { success, data } = await res.json()
console.log('Fields:', Object.keys(data.fields).length)
```

### JavaScript — OAuth application

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/contacts/fields', {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

const { success, data } = await res.json()
```

## Response fields

The `label` and `description` field captions are returned in English, while the ones the platform takes straight from the Bitrix24 account come in the account language. Request headers do not switch the language.

| Field | Type | Description |
|------|-----|---------|
| `success` | boolean | Always `true` on success |
| `data` | object | The contact field schema and the operations available for contacts. Its keys are in the rows below |
| `data.fields` | object | The contact field schema: field name → an object with `type`, `readonly` and `label`. Some fields also carry `description` and extra attributes such as `nullable`, `multiple`, `maxLength` and `items`. The standard fields are listed below, and the `ufCrm*` user fields of this Bitrix24 account are added to them |
| `data.relations` | object | Relations with companies: `company` is the primary company, `companyBinding` covers all linked companies and the operations on them. See [Contact companies](/docs/entities/contacts/companies) |
| `data.activities` | object | Contact activities: the `list` and `create` operations and the `call`, `meeting`, `email` and `task` activity types. See [Activities of a CRM record](/docs/entities/activities/owner-list) and [Create an activity for a CRM record](/docs/entities/activities/owner-create) |
| `data.aggregatable` | array | Standard fields allowed in the aggregation `groupBy`: `typeId`, `sourceId`, `assignedById` |
| `data.batch` | array | Contact write operations available in [batch calls](/docs/batch): `create`, `update`, `delete` |
| `data.import` | object | Method, path and maximum batch size for [importing records](/docs/import) |
| `data.include` | array | The names the `include` parameter accepts: `company`, `companyBinding` |

### Standard contact fields

| Field | Type | RO | Description |
|------|-----|:--:|---------|
| `id` | number | yes | Contact ID |
| `name` | string | | First name, at most 50 Unicode code points. Longer values are rejected before writing; the name is not truncated. |
| `lastName` | string | | Last name |
| `secondName` | string | | Middle name |
| `phone` | multifield | | Phone. On input (POST/PATCH) accepts `string \| string[] \| object[]`. On output `phone` is a string with the primary value, per-type values are in `phoneWork`/`phoneMobile`, and the full list with types is in the `fm[]` array (format `{ id, typeId, valueType, value }`). **Important:** PATCH **only adds** new records — old `phone` entries are not removed. See [Update contact](/docs/entities/contacts/update). The uppercase form `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` is **not accepted** — it returns `400 INVALID_MULTIFIELD_SHAPE`. Use camelCase: `[{ "value": "...", "typeId": "WORK" }]`. An object with an `id` field is not accepted by any write operation — `400 MULTIFIELD_ID_NOT_SUPPORTED`, and nothing is written. The same applies to a row with `id` inside the raw `fm[]` array. An object keyed by row ids (`{"11": {…}}`) is not accepted either — same code. An object without `value` — empty or with keys such as `n0`, `0` or `011` — and a number or `true`/`false`, on their own or as an array item, are refused with `400 INVALID_MULTIFIELD_SHAPE`. |
| `email` | multifield | | Email. On input accepts `string \| string[] \| object[]`. On output `email` is a string with the primary value, per-type values are in `emailWork`/`emailHome`/`emailMailing`, and the full list is in the `fm[]` array. **Important:** PATCH **only adds** new records — old `email` entries are not removed. The uppercase form `[{ "VALUE": "...", "VALUE_TYPE": "WORK" }]` is **not accepted** — it returns `400 INVALID_MULTIFIELD_SHAPE`. Use camelCase: `[{ "value": "...", "typeId": "WORK" }]`. An object with an `id` field is not accepted by any write operation — `400 MULTIFIELD_ID_NOT_SUPPORTED`, and nothing is written. The same applies to a row with `id` inside the raw `fm[]` array. An object keyed by row ids (`{"11": {…}}`) is not accepted either — same code. An object without `value` — empty or with keys such as `n0`, `0` or `011` — and a number or `true`/`false`, on their own or as an array item, are refused with `400 INVALID_MULTIFIELD_SHAPE`. |
| `phoneWork` | string | yes | Work phone expanded from the `phone` multifield. Read-only: a number is written through `phone`; no write operation saves a submitted value, so the write is rejected: create and update — `400 READONLY_FIELD`, import — `400 IMPORT_ITEM_VALIDATION`, entity batch — `400 BATCH_ITEM_VALIDATION`, global batch — `READONLY_FIELD` under the call. `null` when there is no such number. Filter (exact and `$contains`) and sorting work |
| `phoneMobile` | string | yes | Mobile phone expanded from the `phone` multifield. Read-only, like `phoneWork`. `null` when there is no such number |
| `phoneMailing` | string | yes | Mailing phone expanded from the `phone` multifield. Read-only, like `phoneWork`. `null` when there is no such number |
| `imol` | string | yes | Open Channel (messenger) contact of the person, expanded from the multifield collection. Read-only. `null` when there is none |
| `address` | string | yes | Address of the contact as a single line (legacy column). Bitrix24 returns it but does not store it through the item API used by this method: no write operation saves a submitted value, and the request is rejected (codes as for `phoneWork`); only the legacy `crm.contact.add` of older integrations fills it, and an address is edited in the contact's requisites. `null` when not filled in. Filter (exact and `$contains`) and sorting work |
| `shortName` | string | yes | Short name — last name with initials ("Smith J. R."), computed by Bitrix24. Returned only in list or search results when the field is explicitly named in `select` (without `*`); a single `GET /v1/contacts/{id}`, a list without `select` and the entity batch list (its `select` is a projection) return `null`. Read-only (the same error codes as for `phoneWork`). Filter (exact and `$contains`) and sorting work |
| `hasPhone` | boolean | yes | Whether a phone is set |
| `hasEmail` | boolean | yes | Whether an email is set |
| `hasImol` | boolean | yes | Whether there is an Open Channel contact |
| `companyId` | number | | Company ID. Lookup: `GET /v1/companies` |
| `post` | string | | Position |
| `comments` | string | | Comment |
| `typeId` | string | | Contact type. List: `GET /v1/statuses?filter[entityId]=CONTACT_TYPE` |
| `sourceId` | string | | Source. List: `GET /v1/statuses?filter[entityId]=SOURCE` |
| `sourceDescription` | string | | Source description |
| `assignedById` | number | | Assignee. List: `GET /v1/users` |
| `createdBy` | number | yes | Creator. Lookup: `GET /v1/users` |
| `updatedBy` | number | yes | Modified by. Lookup: `GET /v1/users` |
| `createdTime` | datetime | yes | Creation date |
| `updatedTime` | datetime | yes | Modification date |
| `opened` | boolean | | Available to everyone |
| `export` | boolean | | Export allowed |
| `leadId` | number | | Source lead ID |
| `honorific` | string | | Salutation. List: `GET /v1/statuses?filter[entityId]=HONORIFIC` |

**User fields** (`ufCrm*`) are also returned in responses and accepted on create/update. For an `enumeration` field, this endpoint returns an array of options at `data.fields.<field name>.items`, shaped as `{ "ID": "3989", "VALUE": "warm" }`. To write to a user field, send the `ID`, while `VALUE` is the option label for display. A label sent instead of the identifier is lost without an error. For details, see [Value format by type](/docs/entity-api#value-format-by-type).

## Response example

```json
{
  "success": true,
  "data": {
    "fields": {
      "id": { "type": "number", "readonly": true, "label": "ID", "description": "Contact identifier." },
      "name": { "type": "string", "readonly": false, "maxLength": 50, "label": "First name", "description": "Contact's first name, up to 50 characters. A longer value is refused before writing instead of being silently shortened." },
      "assignedById": { "type": "number", "readonly": false, "label": "Responsible person", "description": "User responsible for the contact." }
    },
    "relations": {
      "company": { "type": "one", "entity": "companies", "includable": true },
      "companyBinding": { "type": "many", "entity": "companies", "operations": ["list", "add", "remove", "set", "clear"] }
    },
    "activities": { "operations": ["list", "create"], "types": ["call", "meeting", "email", "task"] },
    "aggregatable": ["typeId", "sourceId", "assignedById"],
    "batch": ["create", "update", "delete"],
    "import": { "method": "POST", "path": "/v1/contacts/import", "maxItems": 100 },
    "include": ["company", "companyBinding"]
  }
}
```

Three fields from `data.fields` are shown, along with the other `data` keys. The full set of fields is in the tables above.

What to do with the names from `data.include` is covered on the [Get contact](/docs/entities/contacts/get#related-data) page. For more information about the `include` parameter, see [Related data](/docs/includes).

## Error response example

403 — the key lacks the `crm` scope:

```json
{
  "success": false,
  "error": {
    "code": "SCOPE_DENIED",
    "message": "This endpoint requires 'crm' scope",
    "hint": "This request needs the 'crm' scope, which the calling key does not carry. Add 'crm' to this key in the developer cabinet (or through the management API), then repeat the call.",
    "cause": "key_scope_missing",
    "requiredScope": "crm",
    "keyScopes": ["task", "im"],
    "fix": { "action": "edit_key_scopes", "via": "cabinet" },
    "userMessage": "The app's API key lacks the “CRM” permission. You can add it in the key settings in the developer cabinet."
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|---------|
| 403 | `SCOPE_DENIED` | API key lacks the `crm` scope |
| 401 | `TOKEN_MISSING` | API key has no configured tokens |
| 429 | `RATE_LIMITED` | Rate 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 |

For the full list of common API errors, see [Errors](/docs/errors).

## See also

- [Create contact](/docs/entities/contacts/create)
- [User fields](/docs/userfields)
- [Entity API](/docs/entity-api)
- [Limits and optimization](/docs/optimization)
