Тема
Семейство: people
norm_org_units
Дерево подразделений компании целиком. Состав подразделения — сигнал, по которому подразделение встречи определяется без модели: если большинство участников числится в одном подразделении, выбор сделан. Членство прямое, принадлежность верхним уровням выводится по полю parent_id. Доменное состояние not_ready — оргструктура не подключена: это ждёт человека, повторный вызов ничего не изменит.
Доступ: чтение · Списковый: нет · Версии: 1
Вход
| Поле | Обязательно | Тип | Значение |
|---|
Данные ответа
| Поле | При успехе | Тип | Значение |
|---|---|---|---|
error | нет | DomainError | Доменное состояние |
units | да | список OrgUnit |
Пример: успешный ответ
json
{
"source_refs": [
{
"source": "company-data",
"ref": "org:units",
"label": "Подразделения"
}
],
"freshness": {
"as_of": "2026-09-21T03:00:00.000Z",
"ttl_sec": 86400,
"stale": false
},
"data": {
"units": [
{
"id": "u-root",
"name": "Компания",
"parent_id": null,
"kind": "company",
"sort_order": 0
},
{
"id": "u-sales",
"name": "Продажи",
"parent_id": "u-root",
"kind": "division",
"code": "012",
"sort_order": 10
},
{
"id": "u-retail",
"name": "Розница",
"parent_id": "u-sales",
"kind": "department",
"sort_order": 20
}
]
}
}Пример: случай «domain_error»
json
{
"source_refs": [
{
"source": "company-data",
"ref": "org:units"
}
],
"freshness": {
"as_of": "2026-09-21T03:00:00.000Z",
"ttl_sec": 0,
"stale": false
},
"data": {
"error": {
"code": "not_ready",
"message": "Оргструктура не подключена: нет источника подразделений и людей. Это ждёт человека — повторный вызов ничего не изменит.",
"retryable": false
}
}
}norm_people_list
Сотрудники компании страницами. Поле id — то значение, которое возвращается в поля записи типа «человек». Почты приходят в нижнем регистре, и у одного человека их бывает несколько: сопоставляйте по любой из них. Для следующей страницы передайте page.next_cursor как cursor; нет курсора — люди дочитаны. total — сколько людей всего с учётом фильтров. role_id отбирает тех, у кого есть назначение с этой ролью: так отвечают на вопрос «кто занимает роль». unit_id отбирает по прямому членству, без спуска в дочерние подразделения: спускайтесь сами по дереву norm_org_units. active_only не передан — отдаются все, кого хранит сервер; true — скрыты те, у кого дата увольнения уже наступила. Доменное состояние not_ready — оргструктура не подключена.
Доступ: чтение · Списковый: да · Версии: 1
Вход
| Поле | Обязательно | Тип | Значение |
|---|---|---|---|
active_only | нет | boolean | |
cursor | нет | string | |
limit | нет | integer | |
role_id | нет | string | |
unit_id | нет | string |
Данные ответа
| Поле | При успехе | Тип | Значение |
|---|---|---|---|
error | нет | DomainError | Доменное состояние |
people | да | список Person | |
total | да | integer |
Пример: успешный ответ
json
{
"source_refs": [
{
"source": "company-data",
"ref": "org:people",
"label": "Сотрудники"
}
],
"freshness": {
"as_of": "2026-09-21T03:00:00.000Z",
"ttl_sec": 86400,
"stale": false
},
"page": {
"has_more": false
},
"data": {
"total": 2,
"people": [
{
"id": "p-1042",
"name": "Анна Новикова",
"aliases": [
"Новикова А.",
"a.novikova"
],
"emails": [
"a.novikova@example.com",
"79001234567@example.com"
],
"unit_ids": [
"u-sales",
"u-retail"
],
"phone": "+7 900 123-45-67",
"handles": [
"@a_novikova",
"anna.novikova"
],
"manager_id": "p-1077",
"hired_at": "2024-02-01",
"assignments": [
{
"id": "a-1042-sales",
"unit_id": "u-sales",
"role_id": "r-cco",
"role_name": "Коммерческий директор",
"is_primary": true,
"is_head": false,
"started_at": "2024-02-01"
},
{
"id": "a-1042-retail",
"unit_id": "u-retail",
"role_id": "r-head-retail",
"role_name": "Руководитель розницы",
"is_primary": false,
"is_head": true
}
],
"extra": {
"grade": "M2",
"location": "Москва"
}
},
{
"id": "p-1077",
"name": "Михаил Петров",
"aliases": [
"Петров М."
],
"emails": [
"m.petrov@example.com"
],
"unit_ids": [
"u-retail"
]
}
]
}
}Пример: случай «domain_error»
json
{
"source_refs": [
{
"source": "company-data",
"ref": "org:people"
}
],
"freshness": {
"as_of": "2026-09-21T03:00:00.000Z",
"ttl_sec": 0,
"stale": false
},
"page": {
"has_more": false
},
"data": {
"error": {
"code": "not_ready",
"message": "Оргструктура не подключена: нет источника подразделений и людей. Это ждёт человека — повторный вызов ничего не изменит.",
"retryable": false
}
}
}norm_roles_list
Роли компании страницами: то, чем занимаются её люди. У компании с обычным кадровым учётом это справочник должностей, и у роли есть только идентификатор и название; компания, которая описывает роли смыслом, добавляет продукт роли, заказчика и подчинение. Идентификатор роли возвращается в назначениях сотрудника и принимается фильтром norm_people_list. unit_id отбирает роли, привязанные к подразделению. Пустой список — законный ответ компании, которая ролей не ведёт; not_ready означает, что оргструктура не подключена вовсе.
Доступ: чтение · Списковый: да · Версии: 1
Вход
| Поле | Обязательно | Тип | Значение |
|---|---|---|---|
cursor | нет | string | |
limit | нет | integer | |
unit_id | нет | string |
Данные ответа
| Поле | При успехе | Тип | Значение |
|---|---|---|---|
error | нет | DomainError | Доменное состояние |
roles | да | список Role | |
total | да | integer |
Пример: успешный ответ
json
{
"source_refs": [
{
"source": "company-data",
"ref": "org:roles",
"label": "Роли"
}
],
"freshness": {
"as_of": "2026-09-21T03:00:00.000Z",
"ttl_sec": 86400,
"stale": false
},
"page": {
"has_more": false
},
"data": {
"total": 2,
"roles": [
{
"id": "r-head-retail",
"name": "Руководитель розницы",
"aliases": [
"Директор розничной сети"
],
"product": "Выполненный план продаж розничной сети при сохранённой марже",
"customer": "Коммерческий директор",
"reports_to_role_id": "r-cco",
"unit_id": "u-retail",
"description": "Отвечает за выручку и маржу всех торговых точек."
},
{
"id": "r-cco",
"name": "Коммерческий директор"
}
]
}
}Пример: случай «domain_error»
json
{
"source_refs": [
{
"source": "company-data",
"ref": "org:roles"
}
],
"freshness": {
"as_of": "2026-09-21T03:00:00.000Z",
"ttl_sec": 0,
"stale": false
},
"page": {
"has_more": false
},
"data": {
"error": {
"code": "not_ready",
"message": "Оргструктура не подключена: справочник ролей брать неоткуда. Это ждёт человека — повторный вызов ничего не изменит.",
"retryable": false
}
}
}norm_person_get
Карточка одного сотрудника целиком. Передайте id или email — хотя бы один обязателен, без обоих вызов отклоняется как invalid_input. Передали оба — карточку определяет id, почта игнорируется. Почта сравнивается без учёта регистра. Уволенный отдаётся всегда: вы спросили конкретного человека. Доменные состояния: unknown_user — ни идентификатор, ни почта не подошли; record_rejected — на эту почту в компании заведено больше одной карточки, и выбрать за человека нельзя; not_ready — оргструктура не подключена.
Доступ: чтение · Списковый: нет · Версии: 1
Вход
| Поле | Обязательно | Тип | Значение |
|---|---|---|---|
email | нет | string | |
id | нет | string |
Данные ответа
| Поле | При успехе | Тип | Значение |
|---|---|---|---|
error | нет | DomainError | Доменное состояние |
person | да | Person | Сотрудник |
Пример: успешный ответ
json
{
"source_refs": [
{
"source": "company-data",
"ref": "org:people/p-1042",
"label": "Карточка сотрудника"
}
],
"freshness": {
"as_of": "2026-09-21T03:00:00.000Z",
"ttl_sec": 86400,
"stale": false
},
"data": {
"person": {
"id": "p-1042",
"name": "Анна Новикова",
"aliases": [
"Новикова А.",
"a.novikova"
],
"emails": [
"a.novikova@example.com",
"79001234567@example.com"
],
"unit_ids": [
"u-sales",
"u-retail"
],
"phone": "+7 900 123-45-67",
"handles": [
"@a_novikova",
"anna.novikova"
],
"manager_id": "p-1077",
"hired_at": "2024-02-01",
"assignments": [
{
"id": "a-1042-sales",
"unit_id": "u-sales",
"role_id": "r-cco",
"role_name": "Коммерческий директор",
"is_primary": true,
"is_head": false,
"started_at": "2024-02-01"
},
{
"id": "a-1042-retail",
"unit_id": "u-retail",
"role_id": "r-head-retail",
"role_name": "Руководитель розницы",
"is_primary": false,
"is_head": true
}
],
"extra": {
"grade": "M2",
"location": "Москва"
}
}
}
}Пример: случай «domain_error»
json
{
"source_refs": [
{
"source": "company-data",
"ref": "org:people"
}
],
"freshness": {
"as_of": "2026-09-21T03:00:00.000Z",
"ttl_sec": 0,
"stale": false
},
"data": {
"error": {
"code": "unknown_user",
"message": "Ни идентификатор, ни почта не подошли ни к одному сотруднику. Проверьте значение: идентификаторы приходят из norm_people_list.",
"retryable": false
}
}
}norm_person_upsert
Создать или обновить карточку сотрудника. Ключ — id или email, правило то же, что у norm_person_get. По ключу id карточка только обновляется: нет такой — unknown_user. По ключу email карточка обновляется или создаётся; для создания обязательно имя, иначе ответ несёт record_rejected и поле name среди непринятых. Что делают переданные поля: поля нет во входе — оно не трогается; переданный массив заменяет прежний набор целиком; значение null у одиночного поля очищает его; внутри extra то же правило по каждому ключу. Непринятое поле — не отказ: остальное записано, а поле названо в rejected_fields с причиной. Доменные состояния: not_ready — запись профилей у компании не настроена; unknown_user — карточки по ключу id нет; record_rejected — ничего не записано (на почту заведено больше одной карточки, при создании нет имени, хранилище отвергло карточку целиком); unknown_field — компания не ведёт поле ядра, которое вы пытаетесь записать. Реализация вправе разрешить запись только привилегированным ролям и отвечать unauthorized_scope.
Доступ: запись · Списковый: нет · Версии: 1
Вход
| Поле | Обязательно | Тип | Значение |
|---|---|---|---|
aliases | нет | список string | |
assignments | нет | список Assignment | |
email | нет | string | |
emails | нет | список string | |
extra | нет | object | |
handles | нет | список string | |
hired_at | нет | string,null (date) | |
id | нет | string | |
manager_id | нет | string | null | |
name | нет | string | |
phone | нет | string | null | |
terminated_at | нет | string,null (date) |
Данные ответа
| Поле | При успехе | Тип | Значение |
|---|---|---|---|
created | да | boolean | |
error | нет | DomainError | Доменное состояние |
id | да | string | |
rejected_fields | да | список RejectedField | |
url | нет | string (uri) |
Пример: успешный ответ
json
{
"source_refs": [
{
"source": "company-data",
"ref": "org:people/p-1042",
"label": "Карточка сотрудника"
}
],
"freshness": {
"as_of": "2026-09-21T09:31:00.000Z",
"ttl_sec": 0,
"stale": false
},
"data": {
"id": "p-1042",
"created": false,
"url": "https://people.example.com/p-1042",
"rejected_fields": [
{
"key": "extra.birthday",
"reason": "поле не ведётся в карточке сотрудника"
}
]
}
}Пример: случай «created»
json
{
"source_refs": [
{
"source": "company-data",
"ref": "org:people/p-1103",
"label": "Карточка сотрудника"
}
],
"freshness": {
"as_of": "2026-09-21T09:31:00.000Z",
"ttl_sec": 0,
"stale": false
},
"data": {
"id": "p-1103",
"created": true,
"url": "https://people.example.com/p-1103",
"rejected_fields": []
}
}Пример: случай «domain_error»
json
{
"source_refs": [
{
"source": "company-data",
"ref": "org:people"
}
],
"freshness": {
"as_of": "2026-09-21T09:31:00.000Z",
"ttl_sec": 0,
"stale": false
},
"data": {
"error": {
"code": "unknown_user",
"message": "Карточки с таким идентификатором нет. По ключу id карточка только обновляется; чтобы завести новую, передайте email и имя.",
"retryable": false
}
}
}