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

Редактирование и удаление сообщений Discord Webhook (PATCH и DELETE)

Как редактировать и удалять сообщения, отправленные через Discord webhook. Рабочие PATCH и DELETE на Python, JavaScript и curl — включая получение message ID.

редактированиеудалениеpatchdeletewebhookdiscord apiтуториал
Редактирование и удаление сообщений Discord Webhook (PATCH и DELETE)

Большинство туториалов про webhook’и заканчивается на «отправили сообщение». Но в реальности часто нужно его обновить (live-статус, прогресс билда, эволюция инцидента) или удалить (опечатка, отозванный алерт). Всё это можно делать одним webhook URL — без бота — но форма запроса нестандартная.

В гайде — точные PATCH и DELETE для webhook’а, плюс трюк, который многие пропускают: чтобы получить message ID, при отправке нужно ?wait=true.

Три endpoint’а

Имея webhook URL https://discord.com/api/webhooks/{webhook.id}/{webhook.token}:

ДействиеМетодURL
Отправить сообщениеPOST/webhooks/{id}/{token}
ОтредактироватьPATCH/webhooks/{id}/{token}/messages/{message.id}
УдалитьDELETE/webhooks/{id}/{token}/messages/{message.id}

Для edit и delete нужен message ID. По умолчанию Discord его не возвращает — надо запросить.

Шаг 1: получить message ID

Добавь ?wait=true к URL POST. Тогда Discord вернёт полный объект сообщения (включая id) со статусом 200 вместо 204.

import requests

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

r = requests.post(
    WEBHOOK_URL + "?wait=true",
    json={"content": "Билд стартовал…"},
    timeout=10,
)
r.raise_for_status()
message_id = r.json()["id"]
print(f"Отправлено id={message_id}")

Без ?wait=true приходит 204 No Content с пустым телом — сообщение ушло, но handle’а на него нет.

Шаг 2: редактирование

PATCH той же JSON-формой, что и POST. Поля, которые передаёшь — перезаписываются; поля без передачи остаются как были.

edit_url = f"{WEBHOOK_URL}/messages/{message_id}"
r = requests.patch(
    edit_url,
    json={"content": "Билд завершён за 2м 14с"},
    timeout=10,
)
r.raise_for_status()

Можно править:

  • content
  • embeds (заменяет все embed’ы — пустой массив очищает)
  • components (кнопки, select-меню)
  • attachments (см. ниже)
  • allowed_mentions

Нельзя менять username, avatar_url, tts — они фиксируются в момент отправки.

Live-статус борд: пример

import time
import requests

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

# Стартовое сообщение
r = requests.post(
    WEBHOOK_URL + "?wait=true",
    json={
        "embeds": [{
            "title": "Деплой в процессе",
            "description": "⏳ Шаг 0 / 4 — подготовка",
            "color": 0xfee75c,
        }]
    },
)
mid = r.json()["id"]

steps = ["сборка Docker-образа", "запуск тестов", "пуш в registry", "rolling restart"]
for i, step in enumerate(steps, 1):
    time.sleep(5)  # реальная работа
    requests.patch(
        f"{WEBHOOK_URL}/messages/{mid}",
        json={
            "embeds": [{
                "title": "Деплой в процессе",
                "description": f"⏳ Шаг {i} / {len(steps)}{step}",
                "color": 0xfee75c,
            }]
        },
    )

# Финал
requests.patch(
    f"{WEBHOOK_URL}/messages/{mid}",
    json={
        "embeds": [{
            "title": "Деплой завершён",
            "description": "✅ Все 4 шага выполнены",
            "color": 0x57f287,
        }]
    },
)

Получается одно сообщение в Discord, которое обновляется на месте — без спама в чат.

Шаг 3: удаление

import requests

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

r = requests.delete(f"{WEBHOOK_URL}/messages/{message_id}", timeout=10)
r.raise_for_status()  # 204 No Content при успехе

Удаление одноразовое — отменить нельзя. Webhook удаляет сообщения и старше 14 дней (в отличие от bulk-delete через bot API).

JavaScript / Node.js

const WEBHOOK = process.env.WEBHOOK_URL;

// Отправка + capture id
async function send(payload) {
  const res = await fetch(`${WEBHOOK}?wait=true`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  });
  if (!res.ok) throw new Error(`Send failed: ${res.status}`);
  return (await res.json()).id;
}

// Edit
async function edit(messageId, payload) {
  const res = await fetch(`${WEBHOOK}/messages/${messageId}`, {
    method: 'PATCH',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  });
  if (!res.ok) throw new Error(`Edit failed: ${res.status}`);
}

// Delete
async function del(messageId) {
  const res = await fetch(`${WEBHOOK}/messages/${messageId}`, { method: 'DELETE' });
  if (!res.ok) throw new Error(`Delete failed: ${res.status}`);
}

// Использование
const id = await send({ content: 'Работаем…' });
await new Promise(r => setTimeout(r, 5000));
await edit(id, { content: 'Готово за 5с' });

curl

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

# Отправка с capture ID
MID=$(curl -s -H 'Content-Type: application/json' \
  -d '{"content":"Initial"}' \
  "$WEBHOOK?wait=true" | jq -r '.id')

# Edit
curl -X PATCH \
  -H 'Content-Type: application/json' \
  -d '{"content":"Updated"}' \
  "$WEBHOOK/messages/$MID"

# Delete
curl -X DELETE "$WEBHOOK/messages/$MID"

jq упрощает парсинг ответа. Без него: python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])'.

Редактирование вложений

Не очевидно. Два случая:

Случай 1: убрать все вложения. В PATCH body — attachments: [].

Случай 2: добавить новый файл или заменить. multipart/form-data (как при загрузке), а в payload_json — массив attachments с тем, что оставить:

# Оставить существующее attachment id=123, добавить новый файл
files = {"files[0]": ("new.png", open("new.png", "rb"), "image/png")}
payload_json = '{"attachments":[{"id":"123"},{"id":"0"}]}'
requests.patch(
    f"{WEBHOOK_URL}/messages/{mid}",
    data={"payload_json": payload_json},
    files=files,
)

id нового файла = индекс в files[N] (т. е. files[0]id: "0").

Треды

Если отправляли в тред (?thread_id={tid}), ?thread_id= нужно и на edit/delete:

requests.patch(
    f"{WEBHOOK_URL}/messages/{mid}?thread_id={tid}",
    json={"content": "Обновлённое сообщение треда"},
)

Иначе Discord не находит сообщение и возвращает 404 Unknown Message.

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

СтатусПричина
404 Unknown MessageНеверный message ID, неверный webhook, пропущен ?thread_id=
401 Invalid Webhook TokenWebhook пересоздан или отозван
403 Cannot edit message authored by another userПытаетесь редактировать чужое сообщение
400 Cannot send empty messageПосле edit должно остаться хотя бы одно: content, embeds, attachments, components

Сохранение message ID

Для долгоживущих сервисов (статус-страницы, дашборды) сохраняйте ID в БД или файл:

from pathlib import Path
import json, requests

STATE = Path("/var/lib/myapp/discord_state.json")

def get_or_create_status_message():
    if STATE.exists():
        data = json.loads(STATE.read_text())
        return data["message_id"]
    r = requests.post(WEBHOOK_URL + "?wait=true", json={"content": "Status: starting"})
    mid = r.json()["id"]
    STATE.write_text(json.dumps({"message_id": mid}))
    return mid

Теперь можно PATCH’ить то же сообщение между перезапусками процесса.

Попробуйте в конструкторе

Конструктор Discord Webhook даёт копируемый message ID после каждой отправки и поддерживает edit/delete из UI — удобно для прототипирования update-флоу до автоматизации.

Дополнительно — scheduled messages и Python.

Источники

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

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