PUT /saas/v2/user/ext/{extId}/update (обновление карточки
по внешнему идентификатору) — если сотрудника нет (NotFound), POST /saas/v2/user/create
(создаёт пользователя и нанимает его — массив extra.staff.employments). Пользователь,
подразделение и должность адресуются по extId напрямую — внутренние id нашей системы не нужны
вообще. extra — контейнер сопутствующих сущностей: сейчас staff.employments, позже —
значения кастомных полей и т.п.
Что реально уходит в API на Иванова: маппинг 1-в-1
Входной item из выгрузки:{ "user": { ... } } — пользователь создан и нанят в «ПОДР-001»
на должность «Менеджер» одним вызовом.
Существующий сотрудник — обновление карточки по extId, внутренний id не нужен
(если пользователя нет — вернётся NotFound, тогда идём в create):
extra.staff — намеренно: повторная передача назначения безвредна (идемпотентный no-op),
но если сотрудника в 1С перевели в другое подразделение, extra создаст ему второе
назначение (совместительство), а не перевод. Кадровые изменения — через /staff/employment/*.
extra в update тоже поддерживается — тот же формат, что и в create. Разберём, что произойдёт
с каждым элементом employments:
extra.employments умеет только «убедиться, что назначение есть»
(нет — нанять, есть — пропустить). Оно НЕ умеет закрывать/менять существующие назначения:
- сотрудника перевели →
POST /staff/employment/ext/{extId}/transfer; - повысили (сменилась должность) →
POST /staff/employment/ext/{extId}/promote; - уволили →
POST /staff/employment/ext/{extId}/terminate.
employments —
с ним НИЧЕГО не произойдёт, оно останется активным. Массив — это не «полный список для
синхронизации»: отсутствие назначения в нём ≠ увольнение с него. Убрать назначение можно
только явным вызовом terminate. Поэтому слать можно хоть одно назначение, хоть все —
перечисленные донаймутся/пропустятся, неперечисленные не тронутся.
Если при переводе прислать в extra новую пару — получите сотрудника с ДВУМЯ активными
назначениями (старым и новым), а не перевод.
Совместительство — несколько назначений в одном массиве (до 10):
_):
Что делать, когда в 1С что-то изменилось
Цикл выше — идемпотентный: его можно гонять хоть каждый час, повторные прогоны безопасны. Карточные изменения он подхватывает сам, а вот кадровые — нет, для них есть отдельные вызовы. Все они адресуются поextId назначения (тот самый extId, который вы передали в элементе
employments при найме — поэтому его важно задавать).
Примеры кадровых вызовов (extId назначения из примера выше —
i.ivanov.01011990:ПОДР-001):
i.ivanov.01011990:ПОДР-001 продолжает
указывать на действующее назначение сотрудника. Если в extId зашит код подразделения (как в
примере), он перестанет совпадать с фактическим департаментом — это не ошибка, просто ключ.
Хотите точности — используйте в качестве extId идентификатор записи о назначении из 1С.
Предусловия
- Подразделения (
ПОДР-001и т.д.) должны быть созданы заранее:POST /saas/v2/staff/department/create { "name": "Отдел продаж", "extId": "ПОДР-001", "parentExtId": "ПОДР-000" }. ЕслиdepartmentExtIdне найден — create вернётStaffDepartmentNotFoundи пользователь создан не будет. - Кадровые изменения существующего сотрудника идут через employment-endpoint’ы по extId назначения:
перевод —
POST /staff/employment/ext/{extId}/transfer { "toDepartmentExtId": "ПОДР-002" }, смена должности —.../promote { "toPositionExtId": "<GUID>" }, увольнение —.../terminate. Новое назначение (в т.ч. совместительство) —POST /staff/employment/hire, либоextra.staff.employmentsвuser/update/user/upsert— донанимает идемпотентно (повтор той же активной пары департамент + должность — no-op); переводы и увольнения черезextraне выражаются. - Увольнение с последнего активного назначения автоматически закрывает аккаунт:
user.statusстановитсяTerminated, все сессии завершаются, вход блокируется. Повторный наём (hire) автоматически возвращаетActive. Уволить владельца школы или самого себя нельзя (StaffCannotTerminateSchoolOwner/StaffCannotTerminateSelf). - Статус
Blocked(блокировка админом) ставится черезuser/update { "status": "Blocked" }: вход закрыт, сессии завершаются, новые назначения курсов запрещены; данные сохраняются и видны в отчётах.{ "status": "Active" }снимает блокировку, доступы восстанавливаются. Владельца школы заблокировать нельзя. - Отсутствия управляют статусом
OnLeave: когда у сотрудника начинается действующее absence (отпуск/больничный и т.д.),user.statusавтоматически становитсяOnLeave, по завершении/удалении — возвращается вActive.OnLeave— информационный статус: вход в систему остаётся доступен. leader_external_idsмапится не на сотрудника, а на руководителя подразделения — отдельный вызовPOST /saas/v2/staff/department-manager/set { "departmentExtId": "ПОДР-001", "employmentExtId": "<extId назначения>", "isPrimary": true }.statusиз выгрузки мапится наuser.status: «Работает» →"Active". «Уволен» напрямую статусом не передаётся — увольнение оформляется черезemployment/terminate, иTerminatedвыставится автоматически.OnLeaveтоже вручную не ставится — им управляют absences.role/tag_list/city/email_for_notifications— соответствия в API нет, поля игнорируются.- Сотрудники без email: передавайте
domain(латиница/цифры/_/точки — точка не по краям и не подряд; сервер приведёт к lowercase, уникален в рамках школы — занят →DomainIsBusy) и обязательноpassword— без email и телефона domain+password становится единственным способом входа. - Должности — по GUID (
positionExtId), не по имени: имя изменяемо и не уникально на стороне 1С («добавят мягкий знак — интеграция сломается»). GUID необязателен: без него работает fallback по имени. Ограничение: имя должности уникально в рамках школы — две должности с одинаковым именем, но разными GUID (разные организации в 1С) создать нельзя (StaffPositionNameIsNotUniq) — сведите GUID’ы к одному или не передавайте GUID у второй организации.
Обновлено: 2026-07-09 07:40 UTC