Перейти до основного вмісту
Розробникам Вебхуки

Надсилайте повідомлення через вебхук

Вебхук це URL, який публікує повідомлення у вашій спільноті. Надішліть на нього JSON із будь-чого, що вміє робити HTTP-запити, як-от CI, моніторинг, cron-завдання чи скрипт, і повідомлення з’явиться в каналі.

Що можна зробити

  • Публікуйте текст або карткуПростий текст або картка із заголовком, кольором, markdown, полями й зображеннями.
  • Додавайте файлиДо п’яти файлів на повідомлення: логи, звіти, знімки екрана.
  • Додавайте кнопкиПосилання або кнопки, що змінюють картку чи звертаються до вашого сервісу.
  • Змінюйте згодомВідповідь містить callback URL, щоб оновити або видалити повідомлення.

У застосунку

$ curl -X POST "$MSSGS_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-H "X-Mssgs-Signature: sha256=$SIG" \
-d '{"message_container": {"title": "Збірка #1847 успішна", ...}}'
{"success": true, "message_id": "aZZ1a2b-..."}

Один запит із CI, одна картка в #deploys. Ім’я вгорі це назва, яку ви дали вебхуку.

Швидкий старт

  1. Створіть вебхук

    У настільному застосунку відкрийте у своїй спільноті Manage Server → Webhooks (керування сервером, вебхуки), створіть вебхук, виберіть канали, у яких він може публікувати, і скопіюйте URL для потрібного каналу. Він має такий вигляд:

    url
    https://mss.gs/api/v1/webhook/{webhook_guid}/{token}/{channel_guid}
  2. Надішліть повідомлення

    Підпишіть JSON секретом вебхука й надішліть його методом POST. Вебхук, створений у настільному застосунку, завжди має секрет: скопіюйте його з поля Webhook Secret (секрет вебхука) в налаштуваннях вебхука.

    bash
    BODY='{"content": "Build #1847 passed on main"}'
    SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$MSSGS_WEBHOOK_SECRET" | sed 's/^.* //')
    
    curl -X POST "$MSSGS_WEBHOOK_URL" \
      -H "Content-Type: application/json" \
      -H "X-Mssgs-Signature: sha256=$SIG" \
      -d "$BODY"
  3. Прочитайте відповідь

    Відповідь містить id повідомлення і callback_url, щоб змінити повідомлення згодом.

    json
    {
      "success": true,
      "message_id": "aZZ1a2b-...",
      "callback_url": "https://mss.gs/api/v1/trigger-callback/8f14e45f-...",
      "stream_url": "https://mss.gs/api/v1/instant/6b1e...c0?token=a1b2c3d4-..."
    }
Будь-хто, хто має URL і секрет, може публікувати в цьому каналі. Не тримайте їх у публічних репозиторіях і клієнтському коді.

Що можна надіслати

Повідомлення буває в короткій формі (текст із заголовком і кольором) або повною карткою, і будь-яке з них може містити кнопки та файли. Ім’я вгорі картки завжди є власною назвою вебхука. У налаштуваннях вебхука ви також вирішуєте, чи може він публікувати зображення та згадувати людей.

Коротка форма

Цього достатньо для більшості сповіщень.

json
{
  "content": "Server backup completed at 03:00 UTC",
  "color": "green",
  "title": "Backup Bot"
}
ПолеТипЩо робить
contentstringТекст повідомлення. Обов’язкове, якщо ви не надсилаєте картку чи файли.
colorstringblue (за замовчуванням), green, orange, red, yellow або purple.
titlestringЗаголовок над текстом. За замовчуванням це назва вебхука.

Повна картка

Надішліть message_container, щоб отримати картку із заголовком-посиланням, підзаголовком, markdown, полями й зображеннями. Через вебхук картка приймає type, color, title, title_url, sub_title, description, fields, avatar_url, image_url, image_base64, images і поля індикатора завантаження. Плашка статусу, бейдж, статистика diff і згорнуті міркування доступні лише у відповідях на команди. Усі поля описано на сторінці картки повідомлень.

json
{
  "message_container": {
    "type": "embed_message",
    "color": "green",
    "title": "Build #1847 passed",
    "title_url": "https://ci.example.com/builds/1847",
    "description": "All 212 tests green on **main**.",
    "fields": [
      { "field": "Duration", "value": "2m 34s" },
      { "field": "Commit", "value": "1a2b3c4" }
    ]
  }
}
deploys
System
Повідомлення від CI

Збірка #1847 успішна

Усі 212 тестів на main зелені.
Duration
2m 34s
Commit
1a2b3c4

Кнопки

Додайте масив actions, щоб розмістити кнопки під повідомленням. Як вони працюють, описано на сторінці кнопки.

Файли

Публікуйте разом із повідомленням справжні файли: лог, звіт, знімок екрана. Вони показуються як будь-яке інше вкладення: рядком для завантаження або вбудовано, якщо це зображення, відео чи аудіо. Повідомлення лише з файлами теж підходить: просто не передавайте content і картку.

json
{
  "message_container": {
    "color": "orange",
    "title": "Log dump: ios",
    "description": "DMs stopped arriving after switching networks"
  },
  "attachments": [
    {
      "name": "mssgs-logs-20260803-141205.log",
      "content_base64": "MjAyNi0wOC0wMyAxNDoxMjowNSBbV1NdIGNvbm5lY3RlZAo=",
      "mime_type": "text/plain"
    }
  ]
}
ПолеТипЩо робить
namestringІм’я, під яким файл завантажується. Обов’язкове. Шлях скорочується до останньої частини.
content_base64stringБайти файлу в base64, сирим рядком або як data:-URI. mssgs зберігає файл і лишає в повідомленні тільки посилання.
mime_typestringТип вмісту content_base64. За замовчуванням text/plain.
urlstringФайл, уже розміщений на mssgs: шлях /static/... або URL https://mss.gs/....
Для кожного файлу надсилайте рівно одне з полів: content_base64 або url. Обидва одразу або жодного є помилкою.
ЛімітЗначення
Файлів на повідомлення5
Розмір файлу після декодування8 МБ
Ім’я файлу200 символів
Увесь запитБлизько 10 МБ. Base64 збільшує файл на третину, тож один файл понад приблизно 7 МБ не вміститься.

Чому url приймає лише адреси mssgs

URL вебхука часто опиняється вставленим в інші дашборди. Якщо він витече, це не повинно дати змоги комусь змусити застосунок кожного учасника завантажити файл із вибраного цією людиною сервера. Якщо ваш файл лежить деінде, надішліть його як content_base64, і mssgs розмістить його в себе.

Невдале завантаження не скасовує повідомлення

Файли перевіряються одразу, а завантажуються пізніше. Якщо завантаження не вдасться, цей файл буде пропущено, а решта повідомлення все одно опублікується, без помилки: краще втратити файл, ніж звіт. Якщо файл важливий, перевірте, що він дійшов.

Файл із командного рядка

bash
BODY='{"attachments":[{"name":"report.csv","content_base64":"'"$(base64 < report.csv | tr -d '\n')"'","mime_type":"text/csv"}]}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$MSSGS_WEBHOOK_SECRET" | sed 's/^.* //')

printf '%s' "$BODY" | curl -sS -X POST "$MSSGS_WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -H "X-Mssgs-Signature: sha256=$SIG" \
  --data-binary @-

Підпис запитів

Вебхук із секретом приймає лише запити, які доводять, що знають його, а вебхук, створений у настільному застосунку, завжди має секрет (Webhook Secret у його налаштуваннях). Підпишіть сире тіло запиту за допомогою HMAC-SHA256 із цим секретом і надішліть hex-дайджест у нижньому регістрі в заголовку X-Mssgs-Signature у форматі sha256=<hex>.

javascript
import crypto from 'node:crypto';

const body = JSON.stringify({ content: 'Deploy finished' });
const signature = crypto.createHmac('sha256', process.env.MSSGS_WEBHOOK_SECRET)
  .update(body)
  .digest('hex');

await fetch(process.env.MSSGS_WEBHOOK_URL, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Mssgs-Signature': `sha256=${signature}`
  },
  body
});
Запит без дійсного підпису отримує 401 і {"error": "INVALID_SIGNATURE"}. Запити без підпису приймає лише вебхук без секрету, наприклад створений через MCP без webhook_secret.

Власний заголовок GitHub X-Hub-Signature-256 теж приймається, тож вебхук GitHub із тим самим секретом працює без змін. Підпис не містить позначки часу, тому не заважає повторно надіслати перехоплений запит: головним секретом залишається URL.

Відповіді та помилки

Опубліковане повідомлення повертається зі своїм id і callback_url, через який його можна оновити або видалити протягом 30 хвилин.

json
{
  "success": true,
  "message_id": "aZZ1a2b-...",
  "callback_url": "https://mss.gs/api/v1/trigger-callback/8f14e45f-...",
  "stream_url": "https://mss.gs/api/v1/instant/6b1e...c0?token=a1b2c3d4-..."
}
Читайте не лише статус, а й тіло. Відхилений payload повідомляє причину кодом error у тілі. Вважайте будь-яке тіло з ключем error невдачею, незалежно від коду статусу.
http
HTTP/1.1 200 OK
Content-Type: application/json

{ "error": "ATTACHMENT_TOO_LARGE" }
javascript
const res = await fetch(webhookUrl, { method: 'POST', headers, body });
const reply = await res.json().catch(() => null);

// A rejected payload still comes back as 200: read the body.
if (!res.ok || (reply && reply.error)) {
  throw new Error(`webhook rejected: ${reply?.error ?? res.status}`);
}

Якщо повідомлення має кнопки, відповідь містить ще й stream_url: потік наживо з відповідями, реакціями й натисканнями кнопок на цьому повідомленні, відкритий 10 хвилин або годину, якщо надіслати "sse_event_extended_timeout": true. Див. оновлення наживо.

Коди статусу

СтатусКоли
401Вебхук має секрет, а підпис відсутній або неправильний.
403Цей вебхук не може публікувати в цьому каналі.
404За цим URL немає вебхука.
413Запит завеликий.
429Забагато запитів. Пригальмуйте й спробуйте знову.
502Не вдалося доставити повідомлення. Спробуйте знову.

Коди помилок

КодЗначення
MISSING_CONTENTНемає що публікувати: ні тексту, ні картки, ні файлів.
INVALID_MESSAGE_CONTAINERmessage_container не є об’єктом.
INVALID_MESSAGE_CONTAINER_TYPEТип картки не embed_message і не system_message.
MISSING_MESSAGE_CONTAINER_DESCRIPTIONКартці потрібен опис, якщо це не індикатор завантаження.
MISSING_MESSAGE_CONTAINER_LOADER_TEXTКартці з індикатором завантаження потрібен loader_text.
INVALID_WEBHOOK_BINDINGЦей вебхук не може публікувати в цьому каналі.
INVALID_SIGNATUREЗаголовок підпису відсутній або неправильний.
REQUEST_BODY_TOO_LARGEЗапит перевищує ліміт розміру.
PUBLISH_FAILEDНе вдалося доставити повідомлення.
INVALID_ACTIONS_FORMAT, INVALID_ACTION_MISSING_FIELDS, DUPLICATE_ACTION_ID, INVALID_TRIGGERS_FORMAT, INVALID_TRIGGER_MISSING_ACTION, INVALID_TRIGGER_ACTION_NOT_ALLOWEDЩось не так із кнопкою. Див. кнопки.

Помилки файлів

КодЗначення
INVALID_ATTACHMENTS_FORMATattachments не є списком, або елемент не є об’єктом.
TOO_MANY_ATTACHMENTSПонад п’ять файлів.
MISSING_ATTACHMENT_NAMEФайл не має імені.
INVALID_ATTACHMENT_NAMEІм’я зводиться до непридатного значення, наприклад ...
MISSING_ATTACHMENT_SOURCEНемає ні url, ні content_base64.
AMBIGUOUS_ATTACHMENT_SOURCEПередано і url, і content_base64.
INVALID_ATTACHMENT_BASE64Не вдається декодувати base64.
ATTACHMENT_TOO_LARGEФайл після декодування більший за 8 МБ.
INVALID_ATTACHMENT_URLurl не є адресою mssgs.

Ліміти

ЛімітЗначення
Розмір запитуБлизько 10 МБ
Файлів на повідомлення5, до 8 МБ кожен
Опис карткиДо 50 000 байтів. Якщо понад 1 000 байтів, учасники бачать початок і кнопку Показати більше.
Оновлення повідомлення згодом30 хвилин, через callback_url
Потік наживо для повідомлення з кнопками10 хвилин або година на запит

Частоту запитів обмежено. Отримавши 429, зачекайте, перш ніж надсилати знову, а сповіщення, що надходять пачками, об’єднуйте в одне повідомлення.

GitHub, UniFi і App Store Connect

Спрямуйте один із цих сервісів на URL вебхука, і mssgs розпізнає його та опублікує належну картку, без жодного payload з вашого боку. Див. інтеграції. Вони отримують відповідь {"success": true} без callback URL.

ДжерелоЯк розпізнаєтьсяЩо публікує
GitHubЗаголовок x-github-eventPush, pull requests і рев’ю, issues і коментарі, гілки й теги, релізи. Серію змін одного issue чи pull request буде зібрано в одну картку.
UniFi ProtectUser agent protect-alarm-managerДзвінки у двері, рух, а також люди, транспорт чи посилки, помічені вашими камерами.
App Store ConnectТіло сповіщення або заголовок x-apple-signatureСповіщення App Store Connect.

Що далі