Перейти к содержимому

Делегирование каналов (Sharing)

Делегирование (sharing) — это способ дать другому человеку доступ к одному вашему каналу, не пуская его в остальной аккаунт. Коллега получит право либо только читать сообщения этого канала, либо читать и отправлять в него новые — но не сможет ни видеть другие ваши каналы, ни менять настройки, ни управлять клиентами и токенами.

Удобно, когда:

  • нужно показать команде только канал Prod-алёрты, не открывая весь проект;
  • CI-боту нужно лишь слать в один канал (право send) и больше ничего;
  • дежурный должен видеть входящие уведомления конкретного сервиса (view);
  • хочется передать доступ временно — делегацию легко отозвать, не трогая токены самого канала.

Технически каждая делегация — это отдельный Share-токен с префиксом S, привязанный к каналу. Владелец канала выпускает токен, опционально указывает email получателя и уровень доступа. Получатель пользуется токеном как обычным notifly-токеном (см. ниже Как получателю пользоваться доступом).

permissionЧто разрешено
viewВидеть сам канал в списке и читать его сообщения (GET /message).
sendТо же, что view, плюс отправлять сообщения (POST /message).

send включает в себя view. Любые мутации самого канала, клиентов, токенов, а также удаление сообщений по Share-токену запрещены (ответ 403).

Отдельно от уровня доступа выдаётся право делиться дальше (canShare): по умолчанию оно выключено, и получатель не может раздавать ваш канал другим — см. Ре-шеринг.

Делегация на конкретный email сначала создаётся в статусе приглашения, которое получатель может принять или отклонить:

statusЧто значит
pendingПриглашение выдано, получатель ещё не отреагировал.
acceptedПолучатель принял — канал появился у него в списке.
declinedПолучатель отклонил приглашение.

Принять можно только pending-приглашение (POST /share/:id/accept); попытка принять/отклонить уже обработанное вернёт 400 share is not pending.

Запрос делает владелец канала (или делегированный пользователь — см. Ре-шеринг) API-токеном или токеном устройства с правом записи.

Окно терминала
curl -X POST "$NOTIFLY_URL/application/42/share" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <client-token>" \
-d '{
"recipientEmail": "colleague@example.com",
"permission": "view",
"note": "Дежурному на эту неделю"
}'

Поля тела (ChannelShareParams):

ПолеТипОбязательноОписание
permissionstringдаview или send. Другое значение → 400.
recipientEmailstringнетEmail получателя. Если пусто — получается «open share» (см. ниже).
canShareboolнетРазрешить получателю делиться каналом дальше (по умолчанию false).
notestringнетПроизвольный комментарий для себя («для CI», «коллеге Х»).

Ответ — созданный объект ChannelShare:

{
"id": 1007,
"token": "S9f3kQw7Zx2Lm5Np8Rt1Vy4",
"appid": 42,
"recipientEmail": "colleague@example.com",
"permission": "view",
"canShare": false,
"status": "pending",
"note": "Дежурному на эту неделю",
"created": "2026-06-23T10:00:00Z",
"lastUsed": null,
"appName": "Prod-алёрты"
}

Поле token (префикс S) — это и есть Share-токен. Передайте его получателю любым каналом, либо рассчитывайте на то, что он сам найдёт приглашение через входящие.

Если у адресата ещё нет аккаунта Notifly, ему уходит письмо-приглашение со ссылкой на регистрацию на этот адрес; после регистрации приглашение появится у него во входящих. Повторный POST на тот же адрес переотправит письмо (в ответе такой выдачи canResendInvite: true).

Повторная выдача тому, у кого доступ к каналу уже есть, не создаёт вторую строку, а меняет существующую: повышает уровень до send, меняет canShare, возвращает отклонённое приглашение в pending, а отозванный доступ восстанавливает — с новым значением токена.

Если оставить recipientEmail пустым, делегация становится open share — ссылкой/токеном, которым может воспользоваться кто угодно, у кого он есть. В этом случае получатель присоединяется через POST /share/join, и для него создаётся персональная копия делегации (со своим Share-токеном), не затрагивая оригинал. Это удобно для приглашений вида «перешлите ссылку команде».

После того как делегация принята (accepted), канал появляется в обычном списке получателя (GET /application). Дальше Share-токен используется как любой notifly-токен:

Окно терминала
# Чтение сообщений канала (view и send)
curl "$NOTIFLY_URL/message" -H "X-Notifly-Key: S9f3kQw7Zx2Lm5Np8Rt1Vy4"
# Отправка в канал (только send)
curl -X POST "$NOTIFLY_URL/message" \
-H "X-Notifly-Key: S9f3kQw7Zx2Lm5Np8Rt1Vy4" \
-H "Content-Type: application/json" \
-d '{"title": "Деплой", "message": "Готово"}'

Share-токен даёт доступ строго к одному каналу. Попытка вызвать мутирующие эндпоинты (создать/изменить канал, удалить сообщение, управлять токенами) вернёт 403 channel tokens cannot perform this action.

Получатель видит ещё не принятые (pending) приглашения на свой email через GET /share/incoming. Не показываются приглашения на каналы, которыми получатель владеет сам, и приглашения с теми же правами, что у уже принятой делегации; приглашение с другими правами показывается — это предложение сменить уровень доступа.

Окно терминала
curl "$NOTIFLY_URL/share/incoming" -H "X-Notifly-Key: <client-token>"
Окно терминала
# Принять — канал появится в списке получателя
curl -X POST "$NOTIFLY_URL/share/1007/accept" -H "X-Notifly-Key: <client-token>"
# Отклонить
curl -X POST "$NOTIFLY_URL/share/1007/decline" -H "X-Notifly-Key: <client-token>"

Принять/отклонить может только пользователь, чей email совпадает с recipientEmail делегации; иначе — 404. Обработать можно только pending-приглашение.

Если получателю передали Share-токен напрямую (например, open share или просто строку S...), он присоединяется одним вызовом:

Окно терминала
curl -X POST "$NOTIFLY_URL/share/join" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <client-token>" \
-d '{"token": "S9f3kQw7Zx2Lm5Np8Rt1Vy4"}'

Поведение зависит от типа делегации:

  • Именная (с recipientEmail): токен присоединяет, только если email пользователя совпадает с адресом делегации (иначе 403 this share is not for your email). Статус автоматически переводится в accepted.
  • Open share (без email): создаётся персональная копия делегации для присоединившегося со статусом accepted. Если у него уже есть делегация на этот канал, она при необходимости повышается до send (и получает canShare, если его даёт ссылка) и переводится в accepted. Если же его доступ к каналу владелец отозвал, вернуться по ссылке нельзя: 403 access to this channel was revoked by the owner.

Неверный, отозванный или истёкший токен → 404 invalid share token. Владелец канала присоединиться к собственному каналу не может → 409 you already own this channel.

Управление выданными делегациями (владельцу)

Заголовок раздела «Управление выданными делегациями (владельцу)»

Список делегаций конкретного канала. Владелец канала видит все выдачи, включая сделанные получателями при ре-шеринге (у чужих выдач заполнено createdByEmail); получатель с правом canShare видит только свои:

Окно терминала
curl "$NOTIFLY_URL/application/42/share" -H "X-Notifly-Key: <client-token>"

Изменить уровень доступа, право делиться дальше, email или комментарий — PUT /share/:id (только владелец канала). Если меняется уровень принятой делегации, получатель получает уведомление («Вам повысили доступ» / «Доступ к каналу изменён»):

Окно терминала
curl -X PUT "$NOTIFLY_URL/share/1007" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <client-token>" \
-d '{"permission": "send", "canShare": false, "recipientEmail": "colleague@example.com"}'

Отозвать делегацию — DELETE /share/:id. Это может сделать тот, кто её создал, либо владелец канала. Отзыв двухступенчатый:

  • первый DELETE по действующей делегации — отзыв: токен немедленно перестаёт работать, канал исчезает из списка получателя, а строка остаётся в списке (с revokedAt) и работает как блок — вернуться по всё ещё живой открытой ссылке получатель не сможет. Вместе с доступом отзываются и его «ничейные» выдачи этого канала: открытые ссылки и непринятые приглашения;
  • повторный DELETE по уже отозванной строке удаляет её навсегда — вместе с блоком. Чтобы закрыть вход по открытой ссылке насовсем, удаляйте саму ссылку.

Вернуть отозванный доступ можно повторной выдачей тому же адресату — токен будет новым.

Окно терминала
curl -X DELETE "$NOTIFLY_URL/share/1007" -H "X-Notifly-Key: <client-token>"

Чтобы не вводить email вручную, форма шеринга может подсказать адреса, с кем вы уже делились, — GET /share/recipients возвращает список distinct-email от самых свежих к старым:

Окно терминала
curl "$NOTIFLY_URL/share/recipients" -H "X-Notifly-Key: <client-token>"

Отказ от доступа и ротация своего токена (получателю)

Заголовок раздела «Отказ от доступа и ротация своего токена (получателю)»

Получатель управляет только своей стороной доступа — двумя вызовами. Оба принимают канал в теле запроса (appid), а не в пути:

Окно терминала
# Отказаться от доступа к каналу (канал исчезает из списка, токен умирает)
curl -X POST "$NOTIFLY_URL/share/leave" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <client-token>" \
-d '{"appid": 42}'
# Сменить значение своего Share-токена (например, при компрометации)
curl -X POST "$NOTIFLY_URL/share/rotate" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <client-token>" \
-d '{"appid": 42}'
  • share/leave удаляет все ваши доступы к этому каналу (их может быть несколько, если делились разные люди). Чтобы вернуться, нужно новое приглашение — или всё ещё действующая открытая ссылка.
  • share/rotate меняет значение токена на месте, сохраняя права и привязку; старое значение перестаёт работать сразу. Ротируются все ваши принятые (accepted) и действующие делегации на этот канал; отозванную ротировать нельзя.

Если доступа к каналу нет, оба вызова отвечают 404.

Делегации по email — про людей. Для скриптов, CI и интеграций у канала есть машинные ключи: несколько ключей на канал, у каждого свои права, метка, срок действия и собственный lastUsed.

Окно терминала
# Выдать ключ только на отправку
curl -X POST "$NOTIFLY_URL/application/42/token" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <client-token>" \
-d '{"name": "CI deploy key", "canRead": false, "canWrite": true,
"note": "gitlab runner", "expiresAt": 0}'
ПолеЗначение
nameчеловекочитаемая метка ключа
canReadчтение истории канала и подписка по WebSocket
canWriteотправка в канал (POST /message, /ask)
noteпроизвольный комментарий
expiresAtсрок действия, unix-миллисекунды; 0 — бессрочно

Ключ обязан разрешать хотя бы одно из canRead/canWrite, иначе — 400. Управление ключами доступно только владельцу канала: получателю делегации оно не положено даже с правом записи.

Отзыв двухступенчатый. Первый DELETE /token/:id — мягкий: ключ перестаёт аутентифицировать, но строка остаётся, и видно, когда он использовался в последний раз и когда отозван. Повторный DELETE удаляет запись навсегда.

Ротация (POST /token/:id/rotate) меняет только значение: id, права и привязка к каналу сохраняются, поэтому ничего, что ссылается на ключ, не рвётся.

Отзыв действует со следующего запроса. Исключение — уже открытое WebSocket-соединение: оно авторизовано до апгрейда и живёт со старым ключом до переподключения.

Делиться каналом дальше может только получатель, которому владелец выдал право canShare; без него POST /application/:id/share ответит 403 you are not allowed to share this channel further. Даже с этим правом нельзя выдать больше, чем есть у вас самого. Если у вас только view, попытка выдать send вернёт:

403 cannot grant 'send' permission — you only have 'view' access

Передать дальше право canShare тоже можно только тому, у кого оно есть.

Владелец канала всегда считается имеющим максимальный доступ (send и canShare). В списке GET /application/:id/share ре-шарер видит только свои выдачи, а владелец — все, с указанием, кто их сделал (createdByEmail), и может отозвать любую.

Метод и путьАвторизацияНазначение
GET /application/:id/shareclient-tokenсписок делегаций канала (только свои)
POST /application/:id/shareclient-token (write)создать делегацию (выдать Share-токен)
PUT /share/:idclient-token (write)изменить permission / email / note (владелец канала)
DELETE /share/:idclient-token (write)отозвать делегацию
GET /share/incomingclient-tokenвходящие приглашения на email пользователя
GET /share/recipientsclient-tokenemail-адреса, с кем вы уже делились (для подсказок)
POST /share/:id/acceptclient-tokenпринять pending-приглашение
POST /share/:id/declineclient-tokenотклонить pending-приглашение
POST /share/joinclient-tokenприсоединиться к каналу по Share-токену
POST /share/leaveclient-token (write)отказаться от доступа к каналу, тело {"appid": N}
POST /share/rotateclient-token (write)сменить значение своего Share-токена, тело {"appid": N}
GET /application/:id/tokenclient-tokenмашинные ключи канала (только владелец)
POST /application/:id/tokenclient-token (write)выдать машинный ключ
PUT /token/:idclient-token (write)изменить права, метку и срок ключа
DELETE /token/:idclient-token (write)отозвать ключ (повторно — удалить навсегда)
POST /token/:id/rotateclient-token (write)сменить значение ключа, сохранив права