REST API модуля «Корпоративный университет» (ithive.ipr)
Справочник REST-методов модуля ithive.ipr для интеграций, входящих вебхуков и AI-агентов.
Базовый URL
https://{портал}/rest/{user_id}/{webhook_code}/{method}.json
Пример:
https://portal.company.ru/rest/1/xxxxxxxx/ipr.ipr.list.json
Все методы имеют префикс ipr. (например, ipr.ipr.list, ipr.competency.get). Исключение — два служебных метода без вложенной сущности: ipr.currentUser и ipr.schema.
Scope и аутентификация
- Scope:
ipr - Аутентификация: входящий вебхук Bitrix24 или OAuth/сессия авторизованного пользователя с доступом к scope
ipr - Все методы
ipr.*требуют авторизованного пользователя REST. Без авторизации — ошибкаUNAUTHORIZED. Часть методов дополнительно проверяет права на конкретную операцию и/или сущность (иначеPERMISSION_DENIED).
Авторизация ≠ право на операцию: доступ к модулю / наличие вебхука сами по себе не дают, например, право редактировать чужой ИПР или писать в справочники.
Для вызовов через сессию с cookie (без OAuth/app-токена) дополнительно требуется CSRF-токен (sessid) — это поведение стандартного REST-движка Bitrix (Bitrix\Main\Engine\ActionFilter\Csrf), а не самого модуля.
Роли и права доступа
Модуль не хранит отдельную REST-модель прав — используются существующие роли и группы модуля ithive.ipr (IPR\Rest\Support\AccessService).
Роли пользователя
Роль (role) |
Условие |
|---|---|
admin |
Администратор портала |
hr |
Участник группы HR-отдела |
manager |
Не admin/HR, но имеет хотя бы одного подчинённого |
employee |
Все остальные (по умолчанию) |
Роль вычисляется по первому совпадению сверху вниз (AccessService::resolveRole). Узнать роль и доступные текущему пользователю флаги можно через GET ipr.currentUser.
Проверки доступа в коде
| Проверка | Кто проходит | Используется в |
|---|---|---|
isPrivileged() |
admin или hr |
Общий флаг «расширенного» доступа — обход большинства ограничений видимости и владения |
canManageEmployee(actor, employeeId) |
Руководитель сотрудника (по оргструктуре) либо привилегированный | Создание/апрув/реджект/реопен ИПР, запуск теста за сотрудника, mass-launch шаблонов |
canManageCourse(courseId) |
Привилегированный или ACL курса (IPR\API\Course\Course::canManageCourse) |
CRUD курсов, уроков, тестов, вопросов |
canManageCatalog() |
Привилегированный или группа «может управлять ИПР» (IPR\Action::checkUserIPRGroupOrAdmin) |
Запись компетенций, должностей, шаблонов программ, запуск/масс-запуск шаблонов |
canAssignCourse() |
Привилегированный или группа «может назначать курсы» | Не используется REST-методами напрямую (зарезервировано) |
canAccessAnalytics() |
Привилегированный или отдельный доступ к аналитике | ipr.analytics.course.list |
Сводка по группам методов
| Группа методов | Кто может (как в коде) |
|---|---|
Служебные (currentUser, schema) |
Любой авторизованный пользователь REST |
ipr.ipr.list |
Авторизованный; выборка режется списком доступных ИПР (IPR\API\Ipr::getAllAvailableIprIds), кроме привилегированных |
ipr.ipr.get |
Авторизованный; доступ проверяется на уровне элемента инфоблока (иначе NOT_FOUND) |
ipr.ipr.add |
Актор создаёт себе (userId == actor) либо canManageEmployee(actor, userId) — руководитель по оргструктуре, группа ИПР/HR, администратор |
ipr.ipr.draft.add |
Как ipr.ipr.add (черновик проходит те же проверки, карточка не создаётся) |
ipr.ipr.draft.get |
Автор черновика либо привилегированный (admin/hr) |
ipr.ipr.update |
Владелец с CAN_EDIT либо привилегированный; свободная смена status — только привилегированным (переходы статуса — через complete/approve/reject/reopen); startFact / finishFact — только администратор портала |
ipr.ipr.delete |
Владелец с CAN_DELETE либо привилегированный; карточка в статусе FINISHED не удаляется никем |
ipr.ipr.complete |
Сотрудник (сам), руководитель сотрудника или привилегированный |
ipr.ipr.approve / reject |
Руководитель сотрудника (не сам сотрудник) или привилегированный; approve продвигает (NEW/SOGL → WORK) или останавливает (SOGL_RES → FINISHED) бизнес-процесс карточки |
ipr.ipr.reopen |
Руководитель или привилегированный; реопен FINISHED — только привилегированным |
ipr.ipr.status.list / ipr.ipr.type.list |
Любой авторизованный |
ipr.action.list / get |
Доступ через родительский ИПР (как ipr.ipr.get) |
ipr.action.add / update / delete |
Родительский ИПР должен быть editable (владелец или привилегированный); delete с force=true — только привилегированным. В update поля dateClosed, resourceId/actId, resourceType/type может менять только привилегированный или руководитель сотрудника — не владелец ИПР |
ipr.action.type.list |
Любой авторизованный |
ipr.event.section.list |
Любой авторизованный |
ipr.event.list / get |
Авторизованный; видимость по правам инфоблока каталога (администратор и HR — всё); предложения (active=false) — только canEdit |
ipr.event.add / update / date.add / date.delete |
canEdit каталога (администратор, HR или право element_edit на инфоблок); создание прошедшей даты проведения и notify=false в date.add — только администратор |
ipr.event.delete |
canDelete каталога (администратор, HR или право section_delete на инфоблок) |
ipr.competency.list / get / section.list |
Видимость по стандартным правам чтения инфоблока Bitrix; привилегированные видят без ограничений |
ipr.competency.add / update / delete |
canManageCatalog() |
ipr.competency.status.list |
Любой авторизованный (статический справочник active/inactive) |
ipr.position.list / get |
Любой авторизованный |
ipr.position.add / update / delete |
canManageCatalog() |
ipr.programtemplate.list / get |
Любой авторизованный |
ipr.programtemplate.add / update / delete |
canManageCatalog() |
ipr.programtemplate.launch / masslaunch |
canManageCatalog() и canManageEmployee(actor, userId) на каждого целевого сотрудника |
ipr.programtemplate.type.list |
Любой авторизованный |
ipr.course.list / get |
По ACL обучения (CHECK_PERMISSIONS); привилегированные — без ограничений |
ipr.course.review.list |
Любой авторизованный |
ipr.course.review.add / delete |
Авторизованный — за себя; userId другого пользователя и date — только администратор портала |
ipr.course.add |
canManageCourse(0) (общее право заводить курсы) или привилегированный |
ipr.course.update / delete |
canManageCourse(courseId) или привилегированный |
ipr.lesson.list / get |
По ACL обучения; привилегированные — без ограничений |
ipr.lesson.add / update / delete / relation.update |
canManageCourse(courseId) или привилегированный |
ipr.lesson.children.check |
Любой авторизованный (только чтение) |
ipr.question.list |
По ACL обучения |
ipr.question.get / add / update / delete |
canManageCourse курса, к которому относится урок вопроса (одного права на урок в модуле обучения недостаточно); привилегированные — без ограничений. Урок должен принадлежать дереву курса |
ipr.test.list / get |
По ACL обучения (get — без дополнительной проверки владения) |
ipr.test.add / update / delete |
canManageCourse(courseId) или привилегированный |
ipr.test.attempt.start |
Только сам студент (userId == actor); руководитель или привилегированный запустить попытку за другого не может |
ipr.test.attempt.answer / finish |
Сам пользователь (userId == actor) либо canManageEmployee(actor, userId); dateStart, dateEnd и notify=false — только администратор портала |
ipr.test.attempt.list |
Привилегированный видит все; иначе — только свои попытки (или попытки управляемых сотрудников при явном filter.userId) |
ipr.test.result.get |
Сам пользователь, canManageEmployee, либо привилегированный |
ipr.employee.get |
Сам сотрудник либо canManageEmployee(actor, userId) |
ipr.employee.update |
Только администратор портала |
ipr.point.list |
Право просмотра карточки (как ipr.ipr.get) |
ipr.point.set |
Руководитель карточки (CUR_MANAGER) — оценка руководителя; владелец в статусе WORK — самооценка; администратор — любая роль (обязателен role); date и notify=false — только администратор |
ipr.history.list / get |
Привилегированный — все записи; иначе — только записи по доступным ИПР |
ipr.analytics.course.list |
canAccessAnalytics() |
Параметры «только администратор»
Даты и режимы, нужные для переноса и демонстрационных данных (startFact, finishFact, dateStart, dateEnd, date, notify=false, а также создание даты проведения в прошлом в ipr.event.date.add и прошедшая дата проведения в eventId у ipr.action.add / update и в competenceRunOptions у ipr.ipr.add), доступны только администратору портала. Если такой параметр прислал не администратор, метод возвращает PERMISSION_DENIED — параметр не игнорируется молча. Формат дат: YYYY-MM-DD или YYYY-MM-DD HH:MM:SS (время сервера), для dateStart / dateEnd / date — не в будущем. Даты проведения мероприятий — ISO 8601 со смещением часового пояса.
В шапках отдельных методов формулировка «Кто может вызывать» даёт краткий итог; детали — в этом разделе.
Формат ответа
Единый конверт модуля (Vibe API, IPR\Rest\ApiResponse) — вложен в стандартную обёртку Bitrix REST (result, time):
| Поле | Описание |
|---|---|
result |
Данные метода или null при ошибке |
total |
Количество записей (для list-методов), иначе null |
next |
Смещение следующей страницы, иначе null |
error |
null или { code, message, details } |
При внутренней ошибке (INTERNAL_ERROR) message всегда равно Internal error, а причина передаётся в details.reason; подробности пишутся только в журнал сервера. Сообщения VALIDATION_ERROR, NOT_FOUND и PERMISSION_DENIED не меняются. Подробнее: Коды ошибок.
Пагинация
Для list-методов (IPR\Rest\Dto\ListParams, IPR\Rest\Pagination):
| Параметр | По умолчанию | Описание |
|---|---|---|
limit |
50 | Размер страницы, максимум 500 |
offset |
0 | Смещение |
fetchAll |
false | Вернуть все записи одним ответом. Максимум 5000 записей; если подходящих больше — ошибка FETCH_ALL_LIMIT_EXCEEDED |
filter |
- | Mongo-style фильтр |
Булево fetchAll принимается как true / 1 / "y" / "yes" (без учёта регистра) — так же, как и другие булевы параметры методов.
Фильтрация (Mongo-style)
filter — объект { поле: значение } или { поле: { $оператор: значение } } (IPR\Rest\Filter\MongoFilter).
Поддерживаемые операторы: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin.
$in/$ninтребуют непустой массив значений — иначеINVALID_FILTER.- Неизвестный оператор (не из списка выше) —
INVALID_FILTER_OPERATOR. - Значение
$in/$nin, переданное не массивом (например, через query-строку), автоматически оборачивается в массив из одного элемента. filterможно передать и JSON-строкой — она будет разобрана автоматически.- Допустимы только поля из раздела «Поля filter» конкретного метода. Неизвестное поле —
INVALID_FILTER(details.field). - Для методов обучения (
course,lesson,test) проверка прав (CHECK_PERMISSIONS) задаётся сервером и не переопределяется черезfilter:Nдля привилегированных,Yдля остальных.
Пример: filter[status][$eq]=WORK, filter[userId][$in][]=8&filter[userId][$in][]=14.
Список доступных полей фильтра указан на странице каждого *.list-метода.
Разделы REST-справочника
| Раздел | Описание |
|---|---|
| Служебные endpoint'ы | ipr.currentUser, ipr.schema |
| ИПР | Карточки ИПР/ПИС: список, создание, жизненный цикл, справочники статусов и типов |
| Действия ИПР | Действия по компетенциям внутри ИПР |
| Каталог мероприятий | Категории, мероприятия и даты проведения (события календаря) |
| Компетенции | Каталог компетенций, разделы, статусы |
| Должности | Каталог должностей |
| Шаблоны программ | Шаблоны ИПР/ПИС, запуск и масс-запуск на сотрудников |
| Сотрудники | Профиль развития сотрудника: должность, компетенции, сроки |
| Оценки компетенций | Самооценка и оценка руководителя по компетенциям ИПР |
| Курсы | Курсы обучения, отзывы и рейтинг |
| Уроки | Уроки курса, дерево уроков |
| Вопросы | Вопросы и варианты ответов для тестов |
| Тесты | Тесты, попытки прохождения, результаты |
| История | История изменений по карточкам ИПР |
| Аналитика | Агрегаты по прохождению курсов |