External API: Синхронизация пользователей по стандарту SCIM
UnSpot предоставляет API SCIM 2.0 (System for Cross-domain Identity Management, RFC 7643/7644) для автоматической синхронизации пользователей. Провайдеры идентификации, такие как Microsoft Entra ID или Okta, работают с ним «из коробки», но вы можете вызывать его и напрямую из своих скриптов и HR-систем. Эта страница — справочник API: все endpoint’ы, их параметры и готовые примеры.
Содержание
Список пользователей — GET /Users
Создание пользователя — POST /Users
Получение пользователя — GET /Users/{id}
Полная замена — PUT /Users/{id}
Частичное обновление — PATCH /Users/{id}
Загрузка аватара — POST /Users/{id}/avatar
Создание группы — POST /Groups
Чтение / замена / изменение / удаление группы
Базовый URL и аутентификация
При включении SCIM в разделе Администрирование > Доступ > Интеграции > SCIM UnSpot показывает ваш персональный базовый URL и секретный токен:
Base URL: https://<домен-вашей-компании>/api/scim
Token: <секрет из 64 символов>TextКаждый запрос должен содержать токен в заголовке Authorization:
Authorization: Bearer <token>HTTPДля запросов POST, PUT и PATCH обязателен заголовок Content-Type: application/scim+json — с другим значением API вернёт 415 Unsupported Media Type (Content-Type must be application/scim+json).
- 401 Access denied — заголовок отсутствует, не в формате
Bearer <token>или токен неверный. - 400 Token is expired — срок действия токена истёк; обновите его в настройках SCIM.
Ресурсы
| Ресурс | Endpoint’ы | Назначение |
|---|---|---|
| Users | GET/POST /Users, GET/PUT/PATCH/DELETE /Users/{id}, POST /Users/{id}/avatar | Создание, чтение, обновление, деактивация и удаление учётных записей |
| Groups | GET/POST /Groups, GET/PUT/PATCH/DELETE /Groups/{id} | Управление группами UnSpot и их составом |
| OrgUnits | PUT /OrgUnits | Замена всего дерева оргструктуры |
| Schemas | GET /Schemas | Машиночитаемое описание всех поддерживаемых атрибутов |
Пагинация
Списочные endpoint’ы (/Users, /Groups) принимают count (размер страницы, по умолчанию 20, максимум 1000) и startIndex (индекс первого результата, отсчёт с 1). Ответы используют стандартный конверт SCIM ListResponse с totalResults, startIndex и itemsPerPage.
Users
Список пользователей — GET /Users
Возвращает всех пользователей рабочего пространства, включая деактивированных. Используйте для аудита синхронизации или поиска id пользователя в UnSpot.
| Параметр запроса | Тип | Описание |
|---|---|---|
count | integer | Размер страницы. По умолчанию 20, максимум 1000. |
startIndex | integer | Индекс первого результата (с 1). |
filter | string | Поддерживается только форма userName eq "email@example.com". Любой другой фильтр вернёт 400 Filter syntax error. |
curl -H "Authorization: Bearer $TOKEN" \
"https://acme.unspot.ru/api/scim/Users?count=50&startIndex=1"
curl -G -H "Authorization: Bearer $TOKEN" \
--data-urlencode 'filter=userName eq "jane.doe@example.com"' \
https://acme.unspot.ru/api/scim/UsersBashОтвет 200:
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 128,
"startIndex": 1,
"itemsPerPage": 50,
"Resources": [ { ...объекты пользователей, см. ниже... } ]
}JSONСоздание пользователя — POST /Users
Создаёт учётную запись. userName — это email пользователя, должен быть уникальным. Если email принадлежит архивированному пользователю, учётная запись восстанавливается, а не создаётся заново. Если в настройках SCIM включено приветственное письмо, новый пользователь получит приглашение.
| Атрибут тела | Обязателен | Описание |
|---|---|---|
schemas | да | Должен содержать urn:ietf:params:scim:schemas:core:2.0:User (плюс URN расширения Unspot, если передаются его атрибуты). |
userName | да | Email, используется для входа. |
name.givenName / name.familyName | да | Имя и фамилия. |
externalId | нет | Идентификатор из вашей системы, до 36 символов, уникальный. |
title | нет | Должность. |
active | нет | По умолчанию true. false создаёт деактивированную запись. |
phoneNumbers | нет | Массив; используется только первый элемент с type: "work". |
urn:...:enterprise:2.0:User | нет | department и manager.value (id руководителя в UnSpot или его email). |
urn:...:Unspot:2.0:User | нет | role, orgUnit (важнее department), employeeId, numberPass, attendance (0–100). |
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/scim+json" \
https://acme.unspot.ru/api/scim/Users \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "jane.doe@example.com",
"name": { "givenName": "Jane", "familyName": "Doe" },
"title": "Product Manager",
"externalId": "00u1abcd2EFGH3ij4x5",
"active": true
}'BashОтвет 201 — созданный пользователь:
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "5f1c9d2e-...-a1b2",
"userName": "jane.doe@example.com",
"name": { "givenName": "Jane", "familyName": "Doe", "formatted": "Jane Doe" },
"active": true,
"title": "Product Manager",
"externalId": "00u1abcd2EFGH3ij4x5",
"phoneNumbers": [ { "type": "work", "value": "+7 900 000-00-00" } ],
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
"department": "Product",
"manager": { "value": "8a2b...-uuid", "displayName": "Ivan Petrov" }
},
"urn:ietf:params:scim:schemas:extension:Unspot:2.0:User": {
"role": "user", "orgUnit": "Company/Product", "employeeId": "E-1042", "attendance": 60
},
"meta": { "resourceType": "User", "created": "2026-01-15T09:30:00.000Z", "lastModified": "2026-06-02T11:00:00.000Z" }
}JSON- 409 This userName is already used — активная учётная запись с таким email уже существует.
- 409 This externalId is already used — externalId занят.
Получение пользователя — GET /Users/{id}
Возвращает одного пользователя по id UnSpot (UUID). Ответ 200 — такой же объект пользователя, как выше.
Полная замена — PUT /Users/{id}
Полное обновление: передаётся полное представление пользователя (то же тело, что при создании). Пропущенные атрибуты очищаются. Для частичных изменений используйте PATCH. Ответ 200.
Частичное обновление — PATCH /Users/{id}
Частичное обновление в стандартном формате SCIM PatchOp. Именно так провайдеры идентификации меняют отдельные поля и деактивируют пользователей.
curl -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/scim+json" \
https://acme.unspot.ru/api/scim/Users/5f1c9d2e-...-a1b2 \
-d '{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{ "op": "replace", "path": "title", "value": "Head of Product" },
{ "op": "replace", "path": "active", "value": false }
]
}'BashПоддерживаемые значения path и операции:
| path | replace | add | remove |
|---|---|---|---|
name.givenName, name.familyName, userName | ✓ | ✓ | |
active | ✓ | ||
externalId, title, phoneNumbers[type eq "work"].value | ✓ | ✓ | ✓ |
urn:...:enterprise:2.0:User:department / :manager | ✓ | ✓ | ✓ |
urn:...:Unspot:2.0:User:orgUnit / :attendance | ✓ | ✓ | ✓ |
urn:...:Unspot:2.0:User:role / :numberPass / :employeeId | ✓ |
active: falseдеактивирует пользователя (бронирования и доступ блокируются);true— активирует снова. Для администраторов деактивация игнорируется.managerпринимает id пользователя UnSpot (UUID) или email.- Неподдерживаемый
pathили операция возвращают 400 с пояснением.
Ответ 200 — обновлённый пользователь.
Удаление — DELETE /Users/{id}
Удаляет учётную запись из рабочего пространства. Ответ 204 No Content. Для временной блокировки используйте PATCH с active: false.
Загрузка аватара — POST /Users/{id}/avatar
Устанавливает фото профиля. multipart/form-data с полем file: JPEG или PNG, до 100 КБ. Ответ 200.
curl -X POST -H "Authorization: Bearer $TOKEN" \
-F "file=@avatar.png" \
https://acme.unspot.ru/api/scim/Users/5f1c9d2e-...-a1b2/avatarBashGroups
Список групп — GET /Groups
Возвращает группы рабочего пространства. Пагинация как у /Users. Ответ 200, ListResponse из объектов групп:
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"id": "9c3d...-uuid",
"displayName": "Product team",
"externalId": "okta-grp-42",
"meta": { "resourceType": "Group", "created": "...", "lastModified": "..." }
}JSONСоздание группы — POST /Groups
Создаёт группу, опционально с участниками (members[].value = id пользователей). displayName должен быть уникальным (до 255 символов). Неизвестный id участника — 404; дубликат displayName/externalId — 409. Ответ 201.
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/scim+json" \
https://acme.unspot.ru/api/scim/Groups \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "Product team",
"members": [ { "value": "5f1c9d2e-...-a1b2" } ]
}'BashЧтение / замена / изменение / удаление группы
GET /Groups/{id}— одна группа, ответ200.PUT /Groups/{id}— полная замена (displayNameобязателен,members— массив id), ответ204.PATCH /Groups/{id}— PatchOp; поддерживаемые path:displayName(replace),externalId(replace, add),members(add, replace, remove). Ответ204.DELETE /Groups/{id}— ответ204.
Оргструктура
Замена оргструктуры — PUT /OrgUnits
Заменяет всё дерево подразделений одним вызовом. Каждый элемент — узел с полным путём path (уровни через /, до 4000 символов), опциональным руководителем (email) и описанием (до 255).
curl -X PUT -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/scim+json" \
https://acme.unspot.ru/api/scim/OrgUnits \
-d '{
"items": [
{ "path": "Acme", "manager": "ceo@example.com" },
{ "path": "Acme/Product", "manager": "cpo@example.com", "description": "Продуктовая вертикаль" },
{ "path": "Acme/Product/Design" }
]
}'BashОтвет 200. Пользователи привязываются к подразделениям через атрибут расширения orgUnit (или department).
Schemas
GET /Schemas
Возвращает машиночитаемые определения всех поддерживаемых ресурсов и атрибутов, включая расширение UnSpot (urn:ietf:params:scim:schemas:extension:Unspot:2.0:User: role, numberPass, orgUnit, employeeId, attendance, read-only workMode). Полезно для коннекторов IdP с автоматическим обнаружением атрибутов.
Ошибки
Ошибки возвращаются в JSON с пояснением в message. Основные коды:
| Код | Значение | Типичные причины |
|---|---|---|
| 400 | Некорректный запрос | Неверный URN схемы, неподдерживаемый фильтр или PATCH-path, истёкший токен, ошибки валидации |
| 401 | Доступ запрещён | Отсутствующий или неверный Bearer-токен |
| 404 | Не найдено | Неизвестный id пользователя/группы, неизвестный участник в members |
| 409 | Конфликт | Дубликат userName, externalId или displayName |