Перейти к содержимому
Все статьи
· Обновлено 21 апреля 2026 г.

Упоминания в Discord Webhook — allowed_mentions, @everyone, роли, пользователи

Контролируйте, кого пингует ваш Discord webhook. Освойте allowed_mentions для безопасного пинга пользователей, ролей и @everyone — на Python, JavaScript и curl.

упоминанияallowed_mentionseveryoneпингролипользователиwebhookdiscord api
Упоминания в Discord Webhook — allowed_mentions, @everyone, роли, пользователи

По умолчанию Discord webhook пингует всех, кого упомянул в content. Звучит разумно — пока ваш мониторинг случайно не пингует @everyone 50 000 пользователей сервера, потому что в тексте алерта была подстрока <@&>. Решение — allowed_mentions, маленький, но критичный кусок payload’а.

В гайде — что делает allowed_mentions, как ведут себя режимы и паттерны безопасного пинга на Python, JavaScript и curl.

Что контролирует allowed_mentions

Когда Discord парсит content на упоминания вида <@123>, <@&456> или @everyone, он может:

  1. Отрисовать как текст (без уведомления, без подсветки)
  2. Реально пингануть пользователя/роль/everyone

allowed_mentions говорит, какие упоминания в сообщении могут пинговать. Всё, что не в списке — становится текстом.

Поведение по умолчанию (ОПАСНО)

Если allowed_mentions не указан:

{ "content": "<@&123456789> деплой упал" }

Discord пингует роль. И если в content где-то есть @everyone, тоже пингует. Самая частая причина «упс, мой CI разбудил весь сервер в 3 ночи».

Безопасный default: не пинговать никого

Самый безопасный паттерн — отключить все пинги, если не разрешены явно:

{
  "content": "Server warning <@&999>",
  "allowed_mentions": { "parse": [] }
}

parse: [] = «не парсить никакие упоминания». Роль рендерится как кликабельное имя, но уведомление не приходит.

Массив parse

parse принимает до трёх значений: "users", "roles", "everyone".

{
  "content": "Hey @everyone, deploy is live",
  "allowed_mentions": { "parse": ["everyone"] }
}

Это пингует @everyone@here). ["users"] пингует все user-упоминания, но не роли, и т. д.

Пинг конкретных пользователей

parse — топорный инструмент. Для точечных пингов — users со списком ID, без users в parse:

{
  "content": "<@111> <@222> review please",
  "allowed_mentions": {
    "parse": [],
    "users": ["111"]
  }
}

Пингуется только 111. 222 показан как кликабельное упоминание, но без уведомления.

Важно: "users" в parse И users: ["111"] одновременно — Discord вернёт 400. Они взаимоисключающие — на один вызов выбирайте один подход.

Пинг конкретных ролей

То же для ролей:

{
  "content": "<@&100> <@&200> on call!",
  "allowed_mentions": {
    "parse": [],
    "roles": ["100"]
  }
}

Уведомление получит только роль 100.

Python — хелпер

import requests

WEBHOOK_URL = "https://discord.com/api/webhooks/ID/TOKEN"

def send(content: str, ping_users=None, ping_roles=None, ping_everyone=False):
    """Отправка с явными правилами упоминаний."""
    parse = []
    payload = {"content": content, "allowed_mentions": {"parse": parse}}

    if ping_everyone:
        parse.append("everyone")
    if ping_users:
        payload["allowed_mentions"]["users"] = [str(u) for u in ping_users]
    if ping_roles:
        payload["allowed_mentions"]["roles"] = [str(r) for r in ping_roles]

    r = requests.post(WEBHOOK_URL, json=payload, timeout=10)
    r.raise_for_status()

# Примеры
send("Daily report posted", )  # Без пингов
send("<@123> code review please", ping_users=[123])  # Один юзер
send("<@&999> incident!", ping_roles=[999])  # Одна роль
send("@everyone maintenance window", ping_everyone=True)  # Аккуратно!

«Не пинговать никого» становится default’ом, и нужно явно opt-in.

JavaScript — тот же паттерн

async function send(content, { users = [], roles = [], everyone = false } = {}) {
  const allowed_mentions = { parse: [] };
  if (everyone) allowed_mentions.parse.push('everyone');
  if (users.length) allowed_mentions.users = users.map(String);
  if (roles.length) allowed_mentions.roles = roles.map(String);

  const res = await fetch(process.env.WEBHOOK_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ content, allowed_mentions }),
  });
  if (!res.ok) throw new Error(`Send failed: ${res.status}`);
}

await send('<@&999> incident!', { roles: ['999'] });

curl

curl -H 'Content-Type: application/json' \
  -d '{
    "content": "<@123> review please",
    "allowed_mentions": { "parse": [], "users": ["123"] }
  }' \
  https://discord.com/api/webhooks/ID/TOKEN

Шпаргалка по синтаксису

ЦельФормат в content
Упомянуть пользователя<@USER_ID>
Упомянуть роль<@&ROLE_ID>
Упомянуть @everyone@everyone
Упомянуть @here@here
Ссылка на канал<#CHANNEL_ID>

User и role ID — числа из 17–19 цифр. ПКМ по пользователю/роли с Developer Mode → «Copy ID».

Флаг replied_user

Если webhook отвечает на сообщение через message_reference, replied_user контролирует, пинговать ли автора оригинала:

{
  "content": "Got it",
  "message_reference": { "message_id": "1234" },
  "allowed_mentions": { "replied_user": false }
}

В большинстве автоматизаций ставьте replied_user: false, если не хотите явно дёргать автора.

Лимиты

  • Максимум 100 user ID в users
  • Максимум 100 role ID в roles
  • ID должны быть строками в JSON (Discord ID — 64-битные, JS-числа теряют точность)
  • parse и users/roles не должны пересекаться (400)

Паттерны защиты от ошибок

Паттерн 1: allowlist ID ролей. Хардкод небольшого набора ролей, которые webhook’у разрешено пинговать.

ALLOWED_ROLES = {"on-call-eng", "ops-lead"}
ROLE_IDS = {"on-call-eng": "111", "ops-lead": "222"}

def page(role_name: str, message: str):
    if role_name not in ALLOWED_ROLES:
        raise ValueError(f"Пинг '{role_name}' запрещён из этого webhook")
    rid = ROLE_IDS[role_name]
    send(f"<@&{rid}> {message}", ping_roles=[rid])

Паттерн 2: фильтр @everyone из пользовательского ввода. Если webhook ретранслирует чужой текст:

import re
def safe(text: str) -> str:
    text = text.replace("@everyone", "@\u200beveryone")
    text = text.replace("@here", "@\u200bhere")
    return re.sub(r"<@&?\d+>", lambda m: m.group(0).replace("<", "<\u200b"), text)

Zero-width space ломает парсер упоминаний, не меняя текст визуально.

Паттерн 3: dry-run. На тестах в проде форсировать allowed_mentions: { parse: [] } независимо от вызова. Спасает от ошибки в 3 ночи.

Частые ошибки

ОшибкаПричина
400 allowed_mentions: cannot have both parse and users/roles"users" в parse И заполнен массив users
Упоминание видно, уведомления нетНорма при parse: [] и ID не в списке
@everyone пингует даже с безопасным конфигомУ роли webhook’а нет права mention_everyone — Discord тут запрещает

Проверьте в конструкторе

Конструктор Discord Webhook визуально отображает allowed_mentions — переключатели «Ping users», «Ping roles», «Ping @everyone» до отправки, чтобы видеть, какие уведомления уйдут. Полезно для уведомлений и автоматизации.

Источники

Попробуйте в нашем инструменте

Открыть конструктор Discord Webhook