---
title: Уведомления
description: Email-сводки и вебхуки для обсуждений, требующих внимания, включая проверку подписи.
---

Hearl может сообщить вашей команде, как только обсуждению потребуется внимание. Настройка находится на странице **Уведомления**. Менять эти настройки могут только владельцы и администраторы.

## Когда отправляются уведомления [#when]

Hearl проверяет каждые 15 минут. Обсуждение включается в уведомление, если:

- его статус платформы **Без ответа** или **Пользователь написал снова**
- его ход работы всё ещё **Не начато**
- ИИ Hearl признал, что оно относится к вашему продукту, и неуверенных ответов нет
- его приоритет не ниже заданного вами минимума: все, Средний и выше или только Высокий

Каждое обсуждение уведомляется один раз для каждого статуса. Если оно было отправлено как **Без ответа**, а потом пользователь написал снова, оно будет отправлено ещё раз как **Пользователь написал снова**.

## Email [#email]

Включите **Отправлять письма** и добавьте получателей. Оставьте список пустым, чтобы письма получали все участники рабочего пространства. Подойдёт любой адрес, например общий ящик поддержки, до 20 получателей.

Каждая проверка отправляет одну сводку, в которой перечислено до 10 обсуждений, со ссылкой на остальные во входящих. Выберите английский или китайский в поле **Язык**.

## Webhook [#webhook]

Укажите **Endpoint**. Это должен быть публичный URL с `https`. Hearl распознаёт популярных чат-ботов по адресу и отправляет сообщение в нужном им формате:

| Адрес | Формат отправки |
| --- | --- |
| `hooks.slack.com` | Сообщение Slack |
| `feishu.cn`, `larksuite.com` | Текстовое сообщение Feishu |
| `qyapi.weixin.qq.com` | Сообщение WeCom в Markdown |
| `oapi.dingtalk.com` | Сообщение DingTalk в Markdown |
| `discord.com`, `discordapp.com` | Сообщение Discord |
| Любой другой URL | Обычный JSON (ниже) |

Страница показывает, какой тип определён. Кнопка **Отправить тест** отправляет пример, а страница показывает результат последней отправки. Запрос, который длится дольше 8 секунд, считается тайм-аутом.

### Обычный JSON [#json]

```json
{
  "event": "conversations.needs_attention",
  "workspace": { "id": "org_123", "name": "Acme" },
  "text": "*2 conversations need attention* · Acme\n• [reddit] Sync stopped working after 2.3 — No reply yet <https://…>",
  "conversations": [
    {
      "id": "c_8f2a",
      "platform": "reddit",
      "product": "Acme",
      "title": "Sync stopped working after 2.3",
      "author": "some_user",
      "url": "https://www.reddit.com/r/…",
      "status": "待回复",
      "priority": "高",
      "category": "故障",
      "inbox_url": "https://hearl.org/app?c=c_8f2a"
    }
  ],
  "sent_at": "2026-11-08T09:15:00.000Z"
}
```

| Поле | Описание |
| --- | --- |
| `event` | `conversations.needs_attention` или `test` для **Отправить тест**. |
| `workspace` | `id` и `name` рабочего пространства. |
| `text` | Готовая к публикации сводка. Slack читает только это поле. |
| `conversations` | Все обсуждения в этой отправке. |
| `sent_at` | Когда отправка была выполнена, в формате ISO 8601. |

`platform` принимает значения `x`, `reddit` или `hn`. `status`, `priority` и `category` содержат постоянные коды на китайском, поэтому ваш код может сопоставлять их независимо от языка рабочего пространства:

| Поле | Код | Значение |
| --- | --- | --- |
| `status` | `待回复` | Без ответа |
| `status` | `用户有新回复` | Пользователь написал снова |
| `priority` | `高` / `中` / `低` | Высокий / Средний / Низкий |
| `category` | `故障` | Ошибка |
| `category` | `求助` | Вопрос |
| `category` | `功能建议` | Запрос функции |
| `category` | `价格` | Цены |
| `category` | `负面反馈` | Критика |
| `category` | `正面反馈` | Похвала |
| `category` | `购买咨询` | Покупка |
| `category` | `其他` | Другое |

### Проверьте подпись [#signature]

Когда вы сохраняете endpoint вебхука, Hearl создаёт для него **Секрет подписи**. Его можно показать или обновить на странице Уведомления. Запрос содержит заголовок:

```txt
X-Hearloop-Signature: sha256=<hex>
```

`<hex>` это HMAC-SHA256 от необработанного тела запроса с ключом в виде вашего секрета подписи, в нижнем регистре в hex. Вычисляйте его по точным байтам, которые вы получили, до разбора JSON, и сравнивайте за постоянное время.

```js Node.js
import { createHmac, timingSafeEqual } from "node:crypto";
import express from "express";

const app = express();
const secret = process.env.HEARL_WEBHOOK_SECRET;

app.post("/hearl", express.raw({ type: "application/json" }), (req, res) => {
  const expected = "sha256=" + createHmac("sha256", secret).update(req.body).digest("hex");
  const received = req.get("x-hearloop-signature") ?? "";
  const ok =
    received.length === expected.length &&
    timingSafeEqual(Buffer.from(received), Buffer.from(expected));
  if (!ok) return res.status(401).end();

  const payload = JSON.parse(req.body.toString("utf8"));
  console.log(payload.event, payload.conversations.length);
  res.status(200).end();
});

app.listen(3000);
```

```python Python
import hashlib
import hmac
import json
import os

from flask import Flask, abort, request

app = Flask(__name__)
SECRET = os.environ["HEARL_WEBHOOK_SECRET"].encode()


@app.post("/hearl")
def hearl():
    body = request.get_data()
    expected = "sha256=" + hmac.new(SECRET, body, hashlib.sha256).hexdigest()
    received = request.headers.get("X-Hearloop-Signature", "")
    if not hmac.compare_digest(received, expected):
        abort(401)

    payload = json.loads(body)
    print(payload["event"], len(payload["conversations"]))
    return "", 200
```

Верните любой статус `2xx`, чтобы подтвердить получение.
