Пользователи¶
Эндпоинты для управления учётными записями пользователей (список, создание, обновление и удаление пользователей, аватары, ключи API и 2FA), группами пользователей и приглашениями.
Список пользователей¶
GET /users
Выводит учётные записи пользователей, отсортированные по имени пользователя. Вызывающая сторона с api.users.read видит все учётные записи; любой другой вызывающий получает список из одной строки только со своей учётной записью в том же формате с постраничной разбивкой.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
page |
integer | Нет | Номер страницы для постраничной разбивки (по умолчанию: 1) |
per_page |
integer | Нет | Число результатов на странице (по умолчанию: 20, максимум: 1000, оба значения задаются в конфигурации pagination плагина) |
search |
string | Нет | Фильтр по свободному текстовому запросу по имени пользователя, адресу почты и полному имени. |
access |
string | Нет | Фильтр по пользователям, у которых есть действующий доступ к разрешению (например, admin.login, api.super). permission принимается как псевдоним. |
group |
string | Нет | Фильтр по участникам одной группы учётных записей. |
filter |
string | Нет | Идентификатор активной вкладки раздела «Пользователи» (см. GET /users/filters). Вызывает onApiUserListFilter, чтобы плагин мог сузить список до постраничной разбивки. Работает и с хранилищем учётных записей Flex, и с обычным файловым. Не указывайте или используйте all для неотфильтрованного списка. |
Ответ
{
"data": [
{
"username": "editor",
"email": "editor@example.com",
"fullname": "Jane Editor",
"title": "",
"state": "enabled",
"language": "",
"content_editor": "",
"access": { "api": { "access": true, "pages": { "read": true, "write": true } } },
"groups": [],
"avatar_url": null,
"twofa_enabled": false,
"twofa_secret": false,
"created": "2026-09-01T10:00:00+00:00",
"modified": "2026-09-01T10:00:00+00:00"
}
],
"meta": {
"pagination": { "page": 1, "per_page": 20, "total": 1, "total_pages": 1 }
},
"links": {
"self": "/api/v1/users?page=1&per_page=20"
}
}
Коды ответов
| Код | Описание |
|---|---|
200 |
Успех |
401 |
Не авторизован |
Каждая строка пользователя также содержит значения любых пользовательских полей, которые сайт добавил в схему учётной записи, и отображение extra, если плагин предоставляет для неё значения столбцов. twofa_secret — логическое значение, которое лишь сообщает, был ли сгенерирован секрет; сам секрет никогда не возвращается.
Список вкладок пользователей¶
GET /users/filters
Выводит вкладки фильтров, доступные для списка пользователей, вместе с политикой стартового представления. Возвращает встроенную вкладку «All Users» и любые вкладки, добавленные плагинами через событие onApiUserListFilters, с учётом разрешений вызывающей стороны. Выбор вкладки добавляет ?filter=<id> к GET /users, что вызывает onApiUserListFilter, чтобы плагин-владелец мог сузить список до постраничной разбивки.
Ответ
{
"data": {
"tabs": [
{ "id": "all", "plugin": "api", "label": "All Users" },
{ "id": "active", "plugin": "my-plugin", "label": "Active", "icon": "fa-bolt", "priority": 10 }
],
"defaultFilter": "all",
"showAll": true
}
}
Коды ответов
| Код | Описание |
|---|---|
200 |
Успех |
401 |
Не авторизован |
403 |
Запрещено — требуется api.users.read |
data в ответе — объект с тремя ключами:
tabs— упорядоченный ряд вкладок. Каждая вкладка содержитid(передаётся обратно как?filter=<id>;allзарезервирован для встроенной вкладки), slug плагинаpluginи простой текстовыйlabel. Вкладки также могут содержатьicon,priority(большее значение сортирует раньше) иbadge/badgeEndpointдля счётчика в реальном времени.defaultFilter— вкладка, которую клиент должен открыть, если в URL нетfilter. По умолчаниюall; плагин может предложить другую вкладку через$event['defaultFilter'](учитывается только если она соответствует вкладке, видимой вызывающей стороне, иначе используется первая вкладка).showAll— присутствует ли встроенная вкладка «All Users». По умолчаниюtrue; плагин может установить$event['showAll'] = false, чтобы убрать её, когда показ всех учётных записей не является полезным (или безопасным) стартовым представлением. «All Users» убирается только после того, как плагин добавил хотя бы одну разрешённую вкладку, поэтому ряд никогда не остаётся пустым.
Фильтр плагина может только сужать список: он выполняется после search, а фильтры access и group и постраничная разбивка применяются основным эндпоинтом после него, поэтому вкладка никогда не может расширить видимость или изменить структуру ответа. Вкладки работают с обоими хранилищами учётных записей. При учётных записях Flex collection события — это коллекция Flex; при обычных файловых учётных записях — ArrayCollection пользователей с ключами по имени пользователя, и из возвращённого плагином сохраняются только учётные записи, уже присутствующие в списке. О контрактах onApiUserListFilters и onApiUserListFilter см. страницу События API.
Список столбцов пользователей¶
GET /users/columns
Выводит дополнительные столбцы, которые плагины добавили в список пользователей через событие onApiUserListColumns, с учётом разрешений вызывающей стороны. Каждый столбец объявляет, как помечается и форматируется значение, принадлежащее плагину; сами значения передаются в отображении extra каждого пользователя в GET /users и заполняются через onApiUserListColumnData только для текущей страницы.
Ответ
{
"data": {
"columns": [
{
"id": "my-plugin-valid-till",
"plugin": "my-plugin",
"label": "Valid until",
"field": "subscription.valid_till",
"formatter": "datetime",
"sortable": false,
"priority": 50
}
]
}
}
Коды ответов
| Код | Описание |
|---|---|
200 |
Успех |
401 |
Не авторизован |
403 |
Запрещено — требуется api.users.read |
data.columns в ответе — упорядоченный список столбцов, объявленных плагинами. Каждый столбец содержит:
id— уникальный идентификатор столбца.plugin— slug плагина-владельца.label— простой текстовый заголовок столбца.field— ключ, который нужно читать из отображенияextraкаждого пользователя вGET /users.formatter— одно из значенийtext,link,date,datetime,boolean,number,badge. Сервер проверяет его по белому списку и подставляетtextдля всего остального; рендеринг выполняет клиент, поэтому по сети не передаются ни разметка, ни рендерер.sortable— необязательно; предлагает ли столбец клиентскую сортировку текущей страницы.priority— необязательно; большее значение сортирует раньше.
Столбцы принадлежат плагинам, но безопасны по построению: значения в отображении extra каждого пользователя — только скаляры, проверка authorize повторно выполняется на сервере (и удаляется из этого ответа), а событие данных изолировано, поэтому сбойный плагин приводит лишь к отсутствию значений, а не к поломке списка. Значения столбцов вычисляются только для учётных записей текущей страницы — никогда для всех учётных записей.
О контрактах onApiUserListColumns и onApiUserListColumnData см. страницу События API.
Получение пользователя¶
GET /users/{username}
Возвращает сведения о пользователе. Для чтения собственной учётной записи нужно только api.access; для чтения чужой — api.users.read.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
username |
string | Да | Имя пользователя, которое нужно получить |
Ответ
{
"data": {
"username": "editor",
"email": "editor@example.com",
"fullname": "Jane Editor",
"title": "",
"state": "enabled",
"language": "",
"content_editor": "",
"access": { "api": { "access": true, "pages": { "read": true, "write": true } } },
"groups": [],
"avatar_url": null,
"twofa_enabled": false,
"twofa_secret": false,
"created": "2026-09-01T10:00:00+00:00",
"modified": "2026-09-01T10:00:00+00:00",
"twofa_global_enabled": true
}
}
Коды ответов
| Код | Описание |
|---|---|
200 |
Успех |
401 |
Не авторизован |
403 |
Запрещено (чтение чужой учётной записи без api.users.read) |
404 |
Пользователь не найден |
Ответ содержит заголовок ETag; отправьте его обратно как If-Match в Обновлении пользователя, чтобы не перезаписать параллельное изменение. twofa_secret лишь сообщает, был ли сгенерирован секрет, а twofa_global_enabled — установлена ли поддержка 2FA в плагине Login, чтобы клиент знал, предлагать ли настройку 2FA. Пользовательские поля, добавленные сайтом в схему учётной записи, также включаются.
Создание пользователя¶
POST /users
Создаёт новую учётную запись пользователя. Требуется api.users.write.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
username |
string | Да | Уникальное имя пользователя, от 3 до 64 символов. Не может начинаться с точки или содержать .., а также не может содержать / ? * : ; { } или перевод строки. |
password |
string | Да | Пароль пользователя. Должен соответствовать system.pwd_regex сайта, если он задан, и содержать не менее 8 символов, если не задан. |
email |
string | Да | Адрес электронной почты пользователя |
fullname |
string | Нет | Полное отображаемое имя |
title |
string | Нет | Титул, отображаемый вместе с учётной записью |
state |
string | Нет | Состояние учётной записи: enabled (по умолчанию) или disabled |
access |
object | Нет | Объект доступа с разрешениями. Только суперадминистратор может выдать admin.super или api.super. |
groups |
array | Нет | Имена групп. Применяется только если вызывающая сторона — суперадминистратор; в остальных случаях игнорируется. |
Запрос
{"username": "editor", "password": "SecurePass123!", "email": "editor@example.com", "fullname": "Jane Editor"}
Ответ
{"data": {"username": "editor", "email": "editor@example.com", "fullname": "Jane Editor", "title": "", "state": "enabled", "language": "", "content_editor": "", "access": {}, "groups": [], "avatar_url": null, "twofa_enabled": false, "twofa_secret": false, "created": "2026-09-21T10:00:00+00:00", "modified": "2026-09-21T10:00:00+00:00"}}
Коды ответов
| Код | Описание |
|---|---|
201 |
Пользователь создан. Заголовок Location указывает на нового пользователя. |
401 |
Не авторизован |
403 |
Запрещено (нет api.users.write или вызывающая сторона без прав суперпользователя выдаёт супердоступ) |
409 |
Имя пользователя уже существует |
422 |
Ошибка валидации (отсутствует поле, неверное имя пользователя, пароль не соответствует политике или поле не проходит валидацию по схеме учётной записи) |
Любые пользовательские поля, добавленные сайтом в схему учётной записи (user/blueprints/user/account.yaml), также можно передать в теле запроса — они валидируются по этой схеме.
Обновление пользователя¶
PATCH /users/{username}
Обновляет учётную запись пользователя. Меняются только переданные поля. Собственную учётную запись можно обновлять с api.access; для обновления чужой нужен api.users.write.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
username |
string | Да | Имя пользователя, которое нужно обновить (параметр пути) |
email |
string | Нет | Новый адрес электронной почты |
fullname |
string | Нет | Новое полное отображаемое имя |
title |
string | Нет | Новый титул |
language |
string | Нет | Предпочитаемый язык админки |
content_editor |
string | Нет | Предпочитаемый редактор контента |
state |
string | Нет | Новое состояние учётной записи (enabled или disabled). Требуется api.users.write. |
access |
object | Нет | Новый объект доступа с разрешениями. Требуется api.users.write; только суперадминистратор может выдать супердоступ. |
groups |
array | Нет | Новые имена групп. Только для суперадминистраторов. |
password |
string | Нет | Новый пароль. Должен соответствовать system.pwd_regex, если он задан, и содержать не менее 8 символов, если не задан. |
Запрос
Ответ
{"data": {"username": "editor", "email": "editor@example.com", "fullname": "Jane Q. Editor", "title": "", "state": "enabled", "language": "", "content_editor": "", "access": {}, "groups": [], "avatar_url": null, "twofa_enabled": false, "twofa_secret": false, "created": "2026-09-01T10:00:00+00:00", "modified": "2026-09-21T10:00:00+00:00", "twofa_global_enabled": true}}
Коды ответов
| Код | Описание |
|---|---|
200 |
Пользователь обновлён |
401 |
Не авторизован |
403 |
Запрещено (нет api.users.write, отправка state/access/groups без нужного разрешения, либо вызывающая сторона без прав суперпользователя редактирует суперадминистратора) |
404 |
Пользователь не найден |
409 |
Конфликт (несовпадение ETag) |
422 |
Ошибка валидации (пустое тело, пароль не соответствует политике или поле не проходит валидацию по схеме учётной записи) |
Поддерживает оптимистичный контроль конкурентного доступа через заголовок If-Match. Передавайте ETag из последнего GET-запроса, чтобы не перезаписать параллельные изменения.
twofa_enabled и twofa_secret здесь игнорируются, поэтому клиент может без ошибки отправить обратно весь объект пользователя. Двухфакторная аутентификация меняется только через эндпоинты Включение 2FA и Отключение 2FA, которые проверяют код при изменении собственной учётной записи.
Смена пароля или установка state в disabled делает недействительным каждый уже выданный токен API для этой учётной записи. Пользовательские поля, добавленные сайтом в схему учётной записи, также можно передавать.
Удаление пользователя¶
DELETE /users/{username}
Удаляет учётную запись пользователя. Требуется api.users.write.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
username |
string | Да | Имя пользователя, которого нужно удалить |
Коды ответов
| Код | Описание |
|---|---|
204 |
Пользователь удалён |
401 |
Не авторизован |
403 |
Запрещено (нет api.users.write, удаление собственной учётной записи или вызывающая сторона без прав суперпользователя удаляет суперадминистратора) |
404 |
Пользователь не найден |
Загрузка аватара¶
POST /users/{username}/avatar
Загружает пользовательское изображение аватара для пользователя. Отправляется как multipart/form-data. Для собственного аватара дополнительные разрешения не нужны; для чужого нужен api.users.write.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
username |
string | Да | Имя пользователя, для которого загружается аватар |
avatar |
file | Да | Файл изображения (PNG, JPEG или WebP, до 8 МБ). Поле также может называться file. Проверяется содержимое файла, а не заявленный тип. |
Ответ
{"data": {"username": "admin", "email": "admin@example.com", "fullname": "Site Admin", "title": "", "state": "enabled", "language": "", "content_editor": "", "access": {"admin": {"super": true}}, "groups": [], "avatar_url": "/api/v1/thumbnails/3f2a9c1b.jpg", "twofa_enabled": false, "twofa_secret": false, "created": "2026-09-01T10:00:00+00:00", "modified": "2026-09-01T10:00:00+00:00"}}
Коды ответов
| Код | Описание |
|---|---|
201 |
Аватар загружен; тело ответа — обновлённый пользователь |
401 |
Не авторизован |
403 |
Запрещено (нет api.users.write или вызывающая сторона без прав суперпользователя меняет суперадминистратора) |
404 |
Пользователь не найден |
422 |
Ошибка валидации (нет файла, файл слишком большой или не является изображением PNG, JPEG либо WebP) |
Удаление аватара¶
DELETE /users/{username}/avatar
Удаляет пользовательский аватар пользователя. Для собственного аватара дополнительные разрешения не нужны; для чужого нужен api.users.write.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
username |
string | Да | Имя пользователя, для которого удаляется аватар |
Ответ
{"data": {"username": "admin", "email": "admin@example.com", "fullname": "Site Admin", "title": "", "state": "enabled", "language": "", "content_editor": "", "access": {"admin": {"super": true}}, "groups": [], "avatar_url": null, "twofa_enabled": false, "twofa_secret": false, "created": "2026-09-01T10:00:00+00:00", "modified": "2026-09-01T10:00:00+00:00"}}
Коды ответов
| Код | Описание |
|---|---|
200 |
Аватар удалён; тело ответа — обновлённый пользователь |
401 |
Не авторизован |
403 |
Запрещено (нет api.users.write или вызывающая сторона без прав суперпользователя меняет суперадминистратора) |
404 |
Пользователь не найден |
Генерация секрета 2FA¶
POST /users/{username}/2fa
Создаёт или пересоздаёт секрет двухфакторной аутентификации TOTP и возвращает data URI QR-кода. Генерация секрета отключает 2FA, пока код не будет подтверждён через «Включение 2FA». Для собственной учётной записи нужно api.access; для чужой — api.users.write.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
username |
string | Да | Имя пользователя, для которого создаётся 2FA |
Ответ
Коды ответов
| Код | Описание |
|---|---|
200 |
Секрет создан |
401 |
Не авторизован |
403 |
Запрещено. Разрешения проверяются до загрузки учётной записи, поэтому вызывающая сторона без них получает 403 независимо от того, существует ли имя пользователя. |
404 |
Пользователь не найден |
500 |
Плагин Login с поддержкой 2FA не установлен |
Список ключей API¶
GET /users/{username}/api-keys
Выводит все ключи API пользователя. Секреты ключей не возвращаются. Для собственных ключей нужно api.access; для чужих — api.users.read.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
username |
string | Да | Имя пользователя, для которого нужно вывести ключи API |
Ответ
{"data": [{"id": "9f86d081884c7d65", "name": "CI Deploy Key", "prefix": "grav_1a2b3c4...", "scopes": [], "active": true, "created": 1710000000, "last_used": null, "expires": 1717776000}]}
Коды ответов
| Код | Описание |
|---|---|
200 |
Успех |
401 |
Не авторизован |
403 |
Запрещено |
404 |
Пользователь не найден |
created, last_used и expires — временные метки Unix; expires равен null для ключа без срока действия.
Создание ключа API¶
POST /users/{username}/api-keys
Создаёт новый ключ API для пользователя. Необработанный ключ возвращается в ответе только один раз. Для собственных ключей нужно api.access; для чужих — api.users.write.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
username |
string | Да | Имя пользователя, для которого создаётся ключ API |
name |
string | Нет | Описательное имя ключа API (по умолчанию: API Key) |
scopes |
array | Нет | Список областей действия разрешений для ключа. Пустой список означает, что ключ несёт полный доступ учётной записи. |
expiry_days |
integer | Нет | Число дней до истечения срока действия ключа. Не указывайте или задайте null, чтобы ключ не истекал. |
Запрос
Ответ
{"data": {"id": "9f86d081884c7d65", "name": "CI Deploy Key", "prefix": "grav_1a2b3c4...", "scopes": ["api.pages.read"], "active": true, "created": 1710000000, "last_used": null, "expires": 1717776000, "api_key": "grav_1a2b3c4d5e6f..."}}
Коды ответов
| Код | Описание |
|---|---|
201 |
Ключ API создан |
401 |
Не авторизован |
403 |
Запрещено (нет разрешения, вызывающая сторона без прав суперпользователя создаёт ключ для суперадминистратора, либо ключ с областями действия запрашивает область за пределами собственных) |
404 |
Пользователь не найден |
Если запрос аутентифицирован ключом API с областями действия, новый ключ тоже должен быть с областями действия, и каждая запрашиваемая им область должна входить в собственные области вызывающего ключа.
Отзыв ключа API¶
DELETE /users/{username}/api-keys/{keyId}
Отзывает и удаляет ключ API. Для собственных ключей нужно api.access; для чужих — api.users.write.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
username |
string | Да | Имя пользователя, которому принадлежит ключ API |
keyId |
string | Да | Идентификатор отзываемого ключа API |
Коды ответов
| Код | Описание |
|---|---|
204 |
Ключ API отозван |
401 |
Не авторизован |
403 |
Запрещено |
404 |
Пользователь или ключ API не найдены |
Включение 2FA¶
POST /users/{username}/2fa/enable
Проверяет код TOTP по ранее сгенерированному секрету и помечает 2FA как включённую для учётной записи. Включить 2FA в собственной учётной записи может только её владелец (не администраторы), и владельцу нужно api.access. Вызывает onApiUser2faEnabled.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
username |
string | Да | Имя пользователя (параметр пути). |
code |
string | Да | Текущий 6-значный код TOTP из приложения-аутентификатора. |
Запрос
Ответ
Коды ответов
| Код | Описание |
|---|---|
200 |
2FA включена. |
401 |
Не авторизован. |
403 |
Вызывающая сторона не является владельцем учётной записи или не имеет api.access. Владение проверяется до загрузки учётной записи, поэтому это не раскрывает, существует ли имя пользователя. |
404 |
Пользователь не найден. |
422 |
Отсутствует код, неверный код или секрет 2FA ещё не сгенерирован (сначала вызовите POST /users/{username}/2fa). |
500 |
Плагин Login с поддержкой 2FA не установлен. |
Отключение 2FA¶
POST /users/{username}/2fa/disable
Отключает 2FA для учётной записи. Самостоятельное отключение требует api.access и действующего текущего кода TOTP, что не даёт украденной сессии отключить 2FA в одиночку. Администраторы с api.users.write (или суперадминистраторы) могут принудительно отключить 2FA без кода для восстановления при потере устройства; только суперадминистратор может сделать это для учётной записи суперадминистратора. Оба пути очищают twofa_secret. Вызывает onApiUser2faDisabled с флагом forced_by_admin.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
username |
string | Да | Имя пользователя (параметр пути). |
code |
string | Нет | Текущий код TOTP. Требуется для самостоятельного отключения без api.users.write; игнорируется при принудительном отключении администратором. |
Запрос
Ответ
Коды ответов
| Код | Описание |
|---|---|
200 |
2FA отключена. |
401 |
Не авторизован. |
403 |
Вызывающая сторона не является ни владельцем учётной записи, ни обладателем api.users.write, либо администратор без прав суперпользователя нацелен на суперадминистратора. Проверяется до загрузки учётной записи, поэтому это не раскрывает, существует ли имя пользователя. |
404 |
Пользователь не найден. |
422 |
Отсутствует или неверен код (только для самостоятельного отключения). |
500 |
Плагин Login с поддержкой 2FA не установлен. |
Список действий в строке пользователя¶
GET /users/row-actions
Выводит кнопки действий для отдельного пользователя, которые плагины добавили в список пользователей через событие onApiUserListRowActions, с фильтрацией по разрешениям вызывающей стороны. Каждое действие — это описание без рендерера, которое Admin2 отображает в ячейке «Actions» строки пользователя; вызов действия отправляет POST /users/{username}/row-action.
Ответ
{
"data": {
"actions": [
{
"id": "impersonate-user",
"plugin": "impersonate",
"label": "Impersonate",
"icon": "fa-user-secret",
"action": "start",
"confirm": "Impersonate this user?",
"priority": 80
}
]
}
}
Коды ответов
| Код | Описание |
|---|---|
200 |
Успех |
401 |
Не авторизован |
403 |
Запрещено — требуется api.users.read |
data.actions в ответе — упорядоченный список действий в строке, объявленных плагинами. Каждое действие содержит:
id— уникальный идентификатор действия; ключ, отправляемый на эндпоинт выполнения.plugin— slug плагина-владельца.label— простой текстовый текст кнопки (он же её доступное имя и подсказка).icon— необязательный класс иконки Font Awesome.action— необязательный глагол, передаваемый обратно обработчику; для клиента непрозрачен.confirm— необязательный запрос, показываемый в диалоге подтверждения перед выполнением действия.priority— необязательно; большее значение сортирует раньше.
Действия принадлежат плагинам, но безопасны по построению: по сети не передаются ни разметка, ни рендерер, список ограничен по размеру, а проверка authorize повторно выполняется на сервере и удаляется из этого ответа. authorize в объявлении определяет только то, какие кнопки отображаются, — это не граница безопасности; эндпоинт выполнения заново проверяет разрешения независимо.
О контрактах onApiUserListRowActions и onApiUserListRowAction см. страницу События API.
Выполнение действия в строке пользователя¶
POST /users/{username}/row-action
Выполняет объявленное плагином действие строки списка пользователей для одной учётной записи. API заново проверяет authorize объявленного действия для вызывающей стороны, затем вызывает onApiUserListRowAction с именем целевого пользователя; обработчик плагина заново проверяет разрешения для этой цели и возвращает результат. Любой URL перенаправления в результате проверяется на безопасную цель того же источника, прежде чем дойти до клиента.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
username |
Да | Целевая учётная запись, для которой выполняется действие. | |
id |
string | Да | Идентификатор объявленного действия в строке (из GET /users/row-actions). |
Запрос
Ответ
{
"data": {
"status": "success",
"message": "Impersonating alice",
"url": "/admin/impersonate/alice"
}
}
Коды ответов
| Код | Описание |
|---|---|
200 |
Действие выполнено; тело содержит результат обработчика. |
401 |
Не авторизован |
403 |
Запрещено — у вызывающей стороны нет api.users.read, вызывающая сторона без прав суперпользователя нацелена на суперадминистратора, либо обработчик отклонил эту цель |
404 |
Неизвестное имя пользователя или идентификатор действия, на который у вызывающей стороны нет разрешения |
422 |
В теле нет id действия |
Отправьте id объявленного действия в строке. API подтверждает, что вызывающая сторона может перечислять пользователей (api.users.read), загружает целевую учётную запись (только суперадминистратор может действовать в отношении учётной записи суперадминистратора) и заново проверяет собственный authorize действия — неизвестный или неразрешённый идентификатор даёт неотличимый 404, поэтому ничего не утекает. Затем вызывается onApiUserListRowAction с полученным username; обработчик должен проверить $event['plugin'], заново проверить разрешения для цели и установить $event['result'].
Результат приводится к фиксированной форме:
status—successилиerror; определяет, покажет ли Admin2 уведомление об успехе или об ошибке.message— необязательный текст, показываемый во всплывающем уведомлении (с ограничением длины).url— необязательное перенаправление. Проверку проходит только путь относительно корня (не протокольно-относительная форма//host) или абсолютный URL того же источника; схемаjavascript:/data:или URL другого источника отбрасывается. Admin2 открывает прошедший URL в новой вкладке сnoopener.
Обработчик, выбросивший исключение, приводит к 200 со status: error и общим сообщением, а не к поломке списка пользователей; выброшенное ForbiddenException передаётся как 403.
О контракте onApiUserListRowAction см. страницу События API.
Список групп¶
GET /groups
Выводит группы пользователей, отсортированные по имени группы. Требуется api.users.read.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
page |
integer | Нет | Номер страницы для постраничной разбивки (по умолчанию: 1) |
per_page |
integer | Нет | Число результатов на странице (по умолчанию: 20, максимум: 1000) |
search |
string | Нет | Фильтр по свободному текстовому запросу по имени группы, читаемому имени и описанию. |
Ответ
{
"data": [
{
"groupname": "editors",
"readableName": "Editors",
"description": "Can edit site content",
"icon": "users",
"enabled": true,
"access": { "api": { "access": true, "pages": { "read": true, "write": true } } }
}
],
"meta": {
"pagination": { "page": 1, "per_page": 20, "total": 1, "total_pages": 1 }
},
"links": {
"self": "/api/v1/groups?page=1&per_page=20"
}
}
Коды ответов
| Код | Описание |
|---|---|
200 |
Успех |
401 |
Не авторизован |
403 |
Запрещено (нет api.users.read) |
Группы всегда читаются из user/config/groups.yaml и сохраняются в него. Группы, существующие только в наложенном окружении, не выводятся, поэтому любую группу, возвращённую этим эндпоинтом, можно также отредактировать или удалить.
Получение группы¶
GET /groups/{name}
Возвращает одну группу пользователей. Требуется api.users.read.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
name |
string | Да | Имя группы (параметр пути) |
Ответ
{"data": {"groupname": "editors", "readableName": "Editors", "description": "Can edit site content", "icon": "users", "enabled": true, "access": {"api": {"access": true, "pages": {"read": true, "write": true}}}}}
Коды ответов
| Код | Описание |
|---|---|
200 |
Успех |
401 |
Не авторизован |
403 |
Запрещено (нет api.users.read) |
404 |
Группа не найдена |
Ответ содержит заголовок ETag; отправьте его обратно как If-Match в Обновлении группы, чтобы не перезаписать параллельное изменение.
Создание группы¶
POST /groups
Создаёт группу пользователей в user/config/groups.yaml. Требуется суперадминистратор, так как членство в группе может давать любые разрешения. Вызывает onApiGroupCreated.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
groupname |
string | Да | Имя группы: от 1 до 200 букв, цифр, дефисов или подчёркиваний. Это ключ хранения, и позже его нельзя изменить. |
readableName |
string | Нет | Отображаемое имя |
description |
string | Нет | Описание |
icon |
string | Нет | Имя иконки |
enabled |
boolean | Нет | Активна ли группа (по умолчанию: true) |
access |
object | Нет | Объект доступа с разрешениями, выдаваемыми участникам |
Запрос
{"groupname": "editors", "readableName": "Editors", "description": "Can edit site content", "access": {"api": {"access": true, "pages": {"read": true, "write": true}}}}
Ответ
{"data": {"groupname": "editors", "readableName": "Editors", "description": "Can edit site content", "icon": "", "enabled": true, "access": {"api": {"access": true, "pages": {"read": true, "write": true}}}}}
Коды ответов
| Код | Описание |
|---|---|
201 |
Группа создана. Заголовок Location указывает на новую группу. |
401 |
Не авторизован |
403 |
Запрещено (не суперадминистратор) |
409 |
Группа с таким именем уже существует |
422 |
Ошибка валидации (отсутствует или неверен groupname) |
Обновление группы¶
PATCH /groups/{name}
Обновляет группу пользователей. Меняются только переданные поля; access заменяется целиком. Требуется суперадминистратор. Вызывает onApiGroupUpdated.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
name |
string | Да | Имя группы (параметр пути). Группы нельзя переименовать. |
readableName |
string | Нет | Отображаемое имя |
description |
string | Нет | Описание |
icon |
string | Нет | Имя иконки |
enabled |
boolean | Нет | Активна ли группа |
access |
object | Нет | Объект доступа с разрешениями. Заменяет существующий. |
Запрос
Ответ
{"data": {"groupname": "editors", "readableName": "Editors", "description": "Can edit and publish site content", "icon": "users", "enabled": true, "access": {"api": {"access": true, "pages": {"read": true, "write": true}}}}}
Коды ответов
| Код | Описание |
|---|---|
200 |
Группа обновлена |
401 |
Не авторизован |
403 |
Запрещено (не суперадминистратор) |
404 |
Группа не найдена |
409 |
Конфликт (несовпадение ETag) |
422 |
Ошибка валидации (пустое тело) |
Поддерживает оптимистичный контроль конкурентного доступа через заголовок If-Match. Передавайте ETag из последнего GET-запроса, чтобы не перезаписать параллельные изменения.
Удаление группы¶
DELETE /groups/{name}
Удаляет группу пользователей из user/config/groups.yaml. Требуется суперадминистратор. Вызывает onApiGroupDeleted.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
name |
string | Yes | Имя группы (параметр пути) |
Коды ответов
| Код | Описание |
|---|---|
204 |
Группа удалена |
401 |
Не авторизован |
403 |
Запрещено (не суперадминистратор) |
404 |
Группа не найдена |
Учётные записи, у которых удалённая группа указана в groups, сохраняют эту запись; она просто больше ничего не даёт.
Список приглашений¶
GET /invitations
Выводит ожидающие приглашения, сначала новые. Просроченные приглашения предварительно удаляются. Требуется api.users.write, так как каждая запись содержит токен, по которому принимается приглашение.
Ответ
{"data": {"invitations": [{"token": "b7c1e0f4a9d2...", "email": "new.editor@example.com", "fullname": "New Editor", "groups": [], "created": 1758448800, "created_by": "admin", "created_by_name": "Site Admin", "expires": 1759053600, "expired": false}]}}
Коды ответов
| Код | Описание |
|---|---|
200 |
Успех |
401 |
Не авторизован |
403 |
Запрещено (нет api.users.write) |
created и expires — временные метки Unix. Доступ, который даёт приглашение, в список не включается.
Создание приглашения¶
POST /invitations
Создаёт приглашение с заранее заданным доступом и отправляет его по почте, если настроен плагин Email. Получатель сам выбирает имя пользователя и пароль при принятии и получает ровно тот доступ, который задан здесь. Требуется api.users.write.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
email |
string | Да | Адрес, на который отправляется приглашение. Любое ожидающее приглашение для того же адреса заменяется. |
fullname |
string | Нет | Имя, подставляемое в форму принятия |
access |
object | Нет | Объект доступа с разрешениями, которые получает новая учётная запись. admin.super и api.super удаляются, если вызывающая сторона не суперадминистратор. |
groups |
array | Нет | Группы, в которые вступает новая учётная запись. Применяется только если вызывающая сторона — суперадминистратор; в остальных случаях игнорируется. |
expiration |
integer | Нет | Секунды до истечения срока действия приглашения. По умолчанию plugins.api.invitations.expiration (7 дней). Значения меньше 300 заменяются значением по умолчанию, а максимум — 30 дней (2592000). |
message |
string | Нет | Личная заметка, включаемая в письмо |
admin_base_url |
string | Нет | Базовый URL админки для построения ссылки-приглашения, если админка обслуживается не по адресу по умолчанию |
Запрос
{"email": "new.editor@example.com", "fullname": "New Editor", "access": {"api": {"access": true, "pages": {"read": true}}}, "expiration": 604800}
Ответ
{"data": {"token": "b7c1e0f4a9d2...", "email": "new.editor@example.com", "fullname": "New Editor", "groups": [], "created": 1758448800, "created_by": "admin", "created_by_name": "Site Admin", "expires": 1759053600, "expired": false, "link": "https://example.com/admin/invite?token=b7c1e0f4a9d2...", "email_sent": false, "warning": "Email is not configured, so no invitation email was sent. Share the link manually."}}
Коды ответов
| Код | Описание |
|---|---|
201 |
Приглашение создано. Заголовок Location указывает на /auth/invite/{token} — публичный эндпоинт, который проверяет и принимает приглашение. |
401 |
Не авторизован |
403 |
Запрещено (нет api.users.write) |
409 |
Пользователь с таким адресом почты уже существует |
422 |
Ошибка валидации (отсутствует или неверен адрес почты) |
Приглашение создаётся, даже если письмо не удаётся отправить. В этом случае email_sent равен false, а warning объясняет причину, чтобы ссылку можно было передать вручную. Получатель открывает ссылку, а форма принятия использует GET /auth/invite/{token} и POST /auth/invite/{token} для создания учётной записи.
Отзыв приглашения¶
DELETE /invitations/{token}
Отзывает ожидающее приглашение, чтобы его ссылка перестала работать. Требуется api.users.write.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
token |
string | Да | Токен приглашения (параметр пути) |
Коды ответов
| Код | Описание |
|---|---|
204 |
Приглашение отозвано |
401 |
Не авторизован |
403 |
Запрещено (нет api.users.write) |
404 |
Приглашение не найдено |
Повторная отправка приглашения¶
POST /invitations/{token}/resend
Повторно отправляет письмо для ожидающего приглашения. Токен и срок действия остаются прежними. Требуется api.users.write.
Параметры
| Имя | Тип | Обязательный | Описание |
|---|---|---|---|
token |
string | Да | Токен приглашения (параметр пути) |
message |
string | Нет | Личная заметка, включаемая в письмо |
admin_base_url |
string | Нет | Базовый URL админки для построения ссылки-приглашения |
Запрос
Ответ
{"data": {"token": "b7c1e0f4a9d2...", "email": "new.editor@example.com", "fullname": "New Editor", "groups": [], "created": 1758448800, "created_by": "admin", "created_by_name": "Site Admin", "expires": 1759053600, "expired": false, "link": "https://example.com/admin/invite?token=b7c1e0f4a9d2...", "email_sent": true}}
Коды ответов
| Код | Описание |
|---|---|
200 |
Письмо отправлено |
401 |
Не авторизован |
403 |
Запрещено (нет api.users.write) |
404 |
Приглашение не найдено или просрочено |
422 |
Почта не настроена |