Список ролей
Все роли рабочего пространства, встроенные первыми, с числом людей и ключей на каждой.
Выполняет настоящий запрос в вашем рабочем пространстве, с вашим собственным ключом.
GET /roles
Все роли рабочего пространства, встроенные первыми, с числом людей и ключей на каждой.
Две оси, и это не один и тот же вопрос
export OE=https://api.openemail.ukexport AUTH="Authorization: Bearer $OPENEMAIL_API_KEY"РОЛЬ говорит, что человеку МОЖНО ДЕЛАТЬ в этом рабочем пространстве: читать почту, отправлять её, редактировать шаблоны, добавить домен. ВЫДАННЫЙ ДОСТУП говорит, к каким АДРЕСАМ он может это применять, и живёт по соседству на /members/{userId}/addresses как member (читает адрес и отправляет от его имени) или viewer (только читает). Обе стороны должны согласиться, прежде чем письмо уйдёт: роль с emails:send и без выданных адресов может отправлять ниоткуда, и все адреса рабочего пространства под доступом viewer тоже позволяют отправлять ниоткуда.
Каждое рабочее пространство создаётся с одними и теми же шестью ролями. Owner, Admin, Member и Viewer образуют лестницу. Каждая содержит всё, что содержит следующая, поэтому понижение сужает доступ человека, а не меняет его на другой набор. Developer и Billing не ступени этой лестницы: Developer строит интеграции (ключи, вебхуки, шаблоны, отправку) и не читает почту рабочего пространства вовсе, а Billing видит тариф и счета и больше ничего. Обе строго внутри Admin. Они создаются при первом чтении, а не при создании рабочего пространства, поэтому пространство, созданное до появления этой возможности, обзаводится ими в момент первого запроса. builtin называет, из какого шаблона получилась строка, и это всё, что он называет: шесть ролей — это отправная точка, которую рабочее пространство должно подогнать под себя, и любую из них, кроме Owner, можно переименовать, перенастроить по разрешениям и удалить. Ветвитесь по editable и deletable, а не по имени: переименованная кем-то роль по-прежнему отвечает на эти два поля верно, а её имя уже ни о чём не говорит.
Owner — единственное исключение, и исключение во всех направлениях: editable: false, deletable: false и отказ в качестве цели в PATCH /members/{userId}. Он описывает аккаунт, к которому привязано рабочее пространство, и содержит каждое разрешение, включая добавленные в более поздних релизах, — поэтому его список вычисляется, а не хранится. Сделать владельцем кого-то другого — это передача рабочего пространства; эндпоинта, который её выполняет, здесь нет.
Остальные пять принимают всё: новый список разрешений, новое описание, новое имя, DELETE. Это созданные по умолчанию заготовки, а не неизменяемые фикстуры: рабочее пространство, которое никогда не строит интеграции, должно иметь возможность избавиться от Developer, а то, где «Member» означает нечто более узкое, должно иметь возможность сказать это своими словами. Отказывает только владелец, и отказывает во всём под одним кодом: role_immutable, 409 с param: "roleId", независимо от того, было ли в PATCH имя или список разрешений. Переименование само по себе больше нигде не отклоняется, поэтому неизменяемости с param: "name" обрабатывать не нужно; единственный 409, который ещё может вызвать имя, — это role_name_taken, когда на него уже откликается другая роль в рабочем пространстве.
Сверх этих шести рабочее пространство может завести до 24 собственных ролей. Потолок считает только их, поэтому удаление созданной при заполнении роли не освобождает места под ним. Разрешения при записи РАСКРЫВАЮТСЯ, а не берутся буквально (templates:write сам по себе сохраняется как templates:read и templates:write), поэтому читайте список из ответа, а не считайте, что он совпадает с отправленным.
Роль — это ещё и потолок для ключа API. Ключ, выпущенный под ролью, может делать key.scopes ∩ role.permissions и не более, и это вычисляется на границе при каждом запросе, поэтому изменение роли меняет возможности её ключей уже при самом следующем вызове, а у ключа без роли потолка нет вовсе. Всё это подробно описано на странице «Скоупы».
Пример
Требует roles:read. Без курсора. Обёртка несёт hasMore и nextCursor, чтобы клиент мог передать её в тот же код списка, что и для любой другой коллекции, и второй страницы не бывает никогда.
curl "$OE/roles" -H "$AUTH"{ "object": "list", "data": [ { "object": "role", "id": "role_1c94e05d3862c1f0a44b7f3a", "name": "Owner", "description": "The person the workspace belongs to. Holds everything, including additions.", "permissions": ["emails:send", "emails:read", "…", "workspace:manage"], "builtin": "owner", "editable": false, "deletable": false, "members": 0, "apiKeys": 2, "createdAt": "2026-08-01T09:00:00.000Z", "updatedAt": "2026-08-01T09:00:00.000Z" }, { "object": "role", "id": "role_c40a95f21cc65d31c2a89e07", "name": "Viewer", "description": "Reads the mail on the addresses they hold, and changes nothing.", "permissions": [ "emails:read", "drafts:read", "threads:read", "labels:read", "contacts:read", "calendar:read", "templates:read", "rules:read", "connections:read", "settings:read" ], "builtin": "viewer", "editable": true, "deletable": true, "members": 3, "apiKeys": 1, "createdAt": "2026-08-01T09:00:00.000Z", "updatedAt": "2026-08-01T09:00:00.000Z" } ], "hasMore": false, "nextCursor": null}Сортировка по рангу встроенной роли, затем по имени (owner, admin, member, viewer, developer, billing, затем остальные по алфавиту), а не по убыванию даты создания, как в остальном API. Матрицу разрешений читают как лестницу, а сортировка по createdAt каждую неделю ставит самую широкую роль в другую строку.
Именно чтение этого списка СОЗДАЁТ шесть ролей в рабочем пространстве, где их никогда не было. Заполнение конфликтует по уникальному индексу и во второй раз ничего не делает, поэтому вызов идемпотентен и пишет только первый из них, — и это же гарантирует, что POST /members всегда может указать существующий roleId.
Заполнение происходит ОДИН раз. Рабочее пространство запоминает, что оно заполнено, поэтому это чтение дополняет пространство старше самой возможности и больше никогда не пишет, — благодаря чему удаление созданной при заполнении роли окончательно. Более ранняя сборка заново вставляла любую отсутствующую шаблонную строку при каждом чтении, так что удалённый Billing возвращался под новым id при следующей загрузке страницы; сейчас этого нет.
members и apiKeys — это то, что пришлось бы перенести, прежде чем роль можно будет удалить, и именно это позволяет клиенту предупредить до предложения удаления, а не после 409. В строке владельца обычно стоит members: 0: владелец не участник собственного рабочего пространства, он аккаунт, к которому оно привязано.
Жёсткий потолок в 24 пользовательские роли существует именно для того, чтобы это мог быть один ответ. Рабочее пространство с сорока ролями не сможет ответить на вопрос «кто может отправлять от billing@» простым взглядом, а ведь это единственный вопрос, ради ответа на который эта возможность и существует.