Skip to content

Люди и оргструктура

Семейство people.

norm_org_units

Дерево подразделений компании целиком. Состав подразделения — сигнал, по которому подразделение встречи определяется без модели: если большинство участников числится в одном подразделении, выбор сделан. Членство прямое, принадлежность верхним уровням выводится по полю parent_id. Доменное состояние not_ready — оргструктура не подключена: это ждёт человека, повторный вызов ничего не изменит.

Доступ: чтение · Списковый: нет · Версии контракта: 1

Аргументы

Аргументов нет.

Данные ответа (data)

ПолеПри успехеТипЧто это
unitsдасписок OrgUnit
errorнетDomainErrorДоменное состояние
Пример: успешный ответ
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 — то значение, которое передаётся в поля протокола с людьми (participant_ids, organizer_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

Данные ответа (data)

ПолеПри успехеТипЧто это
peopleдасписок Person
totalдаinteger
errorнетDomainErrorДоменное состояние
Пример: успешный ответ
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

Данные ответа (data)

ПолеПри успехеТипЧто это
rolesдасписок Role
totalдаinteger
errorнетDomainErrorДоменное состояние
Пример: успешный ответ
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

Данные ответа (data)

ПолеПри успехеТипЧто это
personдаPersonСотрудник
errorнетDomainErrorДоменное состояние
Пример: успешный ответ
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)

Данные ответа (data)

ПолеПри успехеТипЧто это
createdдаboolean
idдаstring
rejected_fieldsдасписок RejectedField
errorнетDomainErrorДоменное состояние
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
    }
  }
}

Объекты семейства

Объекты, из которых состоят аргументы и ответы инструментов этого семейства.

OrgUnit

Подразделение. Идентификатор, название и родитель. У корневого подразделения родитель — null. Принадлежность верхним уровням выводится по цепочке родителей. Необязательные kind, code и sort_order — вид узла, код в учётной системе компании и порядок среди соседей.

ПолеОбязательноТипЧто это
idдаstring
nameдаstring
parent_idдаstring | null
codeнетstring
kindнетOrgUnitKindВид подразделения
sort_orderнетinteger

OrgUnitKind

Вид подразделения. Уровень узла в дереве: юридическое лицо, дивизион, отдел, команда, группа. Вид описателен: вложенность задаётся только полем parent_id.

Значения: company, division, department, team, group.

Person

Сотрудник. Идентификатор для полей протокола с людьми (participant_ids, organizer_id), имя, другие написания имени, все написания почты в нижнем регистре и прямое членство в подразделениях. handles — опознавательные строки вне почты (логины в мессенджерах): сопоставляйте их так же, как почту. Когда отданы назначения, unit_ids равно множеству их подразделений. Руководителя ищите так: явный manager_id; если его нет — человек с признаком is_head в основном подразделении; если и его нет — по цепочке reports_to_role_id роли основного назначения. extra — поля, которые ведёт сама компания: их состав контракт не описывает.

ПолеОбязательноТип
aliasesдасписок string
emailsдасписок string
idдаstring
nameдаstring
unit_idsдасписок string
assignmentsнетсписок Assignment
extraнетobject
handlesнетсписок string
hired_atнетstring (date)
manager_idнетstring
phoneнетstring
terminated_atнетstring (date)

Assignment

Назначение. Где человек числится и в какой роли. is_primary — основное место работы; is_head — человек руководит этим подразделением. Роль приходит идентификатором, а у компании без справочника должностей — только названием в role_name; назначение вовсе без роли означает «числится в подразделении».

ПолеОбязательноТип
is_headдаboolean
is_primaryдаboolean
unit_idдаstring
ended_atнетstring (date)
idнетstring
role_idнетstring
role_nameнетstring
started_atнетstring (date)

Role

Роль. Чем человек занимается в компании. В обычном кадровом учёте роль — это должность, и у неё есть только идентификатор и название. Компания, которая описывает роли смыслом, добавляет product (что роль производит), customer (главный заказчик результата) и reports_to_role_id (кому роль подчиняется). Цикл в подчинении контракт не запрещает и не проверяет: обходя цепочку, защищайтесь от него сами.

ПолеОбязательноТип
idдаstring
nameдаstring
aliasesнетсписок string
customerнетstring
descriptionнетstring
productнетstring
reports_to_role_idнетstring
unit_idнетstring

RejectedField

Непринятое поле. Поле, которое запись не приняла, и причина. Операция при этом выполнена.

ПолеОбязательноТип
keyдаstring
reasonдаstring