---
title: Notificações
description: Resumos por e-mail e webhooks para conversas que precisam de atenção, incluindo a verificação de assinatura.
---

O Hearl pode avisar sua equipe assim que uma conversa precisar de atenção. Configure na página **Notificações**. Só proprietários e administradores podem alterar essas configurações.

## Quando as notificações são enviadas [#when]

O Hearl verifica a cada 15 minutos. Uma conversa é incluída quando:

- o status da plataforma dela é **Sem resposta ainda** ou **Usuário respondeu de novo**
- o andamento dela ainda é **Não iniciado**
- a IA avaliou que é sobre o seu produto, sem respostas incertas
- a prioridade dela é igual ou superior ao mínimo que você definiu: tudo, Média ou superior, ou apenas Alta

Cada conversa é notificada uma vez por status. Se ela foi notificada como **Sem resposta ainda** e o usuário responde de novo mais tarde, ela é notificada outra vez como **Usuário respondeu de novo**.

## E-mail [#email]

Ative **Enviar e-mail** e adicione os destinatários. Deixe a lista vazia para enviar e-mail a todos os membros do workspace. Qualquer endereço serve, como uma caixa de suporte compartilhada, até 20 destinatários.

Cada verificação envia um resumo que lista até 10 conversas, com um link para o restante na caixa de entrada. Escolha inglês ou chinês em **Idioma**.

## Webhook [#webhook]

Informe um **Endpoint**. Ele precisa ser uma URL `https` pública. O Hearl reconhece bots de chat comuns pelo endereço e envia o formato de mensagem que eles esperam:

| Endereço | Enviado como |
| --- | --- |
| `hooks.slack.com` | Mensagem do Slack |
| `feishu.cn`, `larksuite.com` | Mensagem de texto do Feishu |
| `qyapi.weixin.qq.com` | Mensagem Markdown do WeCom |
| `oapi.dingtalk.com` | Mensagem Markdown do DingTalk |
| `discord.com`, `discordapp.com` | Mensagem do Discord |
| Qualquer outra URL | JSON genérico (abaixo) |

A página mostra qual tipo foi detectado. **Enviar um teste** envia um exemplo, e a página mostra o resultado do último envio. Uma requisição que demora mais de 8 segundos conta como timeout.

### JSON genérico [#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"
}
```

| Campo | Descrição |
| --- | --- |
| `event` | `conversations.needs_attention`, ou `test` para **Enviar um teste**. |
| `workspace` | O `id` e o `name` do workspace. |
| `text` | Um resumo pronto para publicar. O Slack lê apenas este campo. |
| `conversations` | Todas as conversas deste envio. |
| `sent_at` | Quando o envio foi feito, em ISO 8601. |

`platform` é `x`, `reddit` ou `hn`. `status`, `priority` e `category` são códigos estáveis em chinês, para que o seu código possa compará-los qualquer que seja o idioma do seu workspace:

| Campo | Código | Significado |
| --- | --- | --- |
| `status` | `待回复` | Sem resposta ainda |
| `status` | `用户有新回复` | Usuário respondeu de novo |
| `priority` | `高` / `中` / `低` | Alta / Média / Baixa |
| `category` | `故障` | Bug |
| `category` | `求助` | Dúvida |
| `category` | `功能建议` | Sugestão de recurso |
| `category` | `价格` | Preço |
| `category` | `负面反馈` | Crítica |
| `category` | `正面反馈` | Elogio |
| `category` | `购买咨询` | Compra |
| `category` | `其他` | Outro |

### Verifique a assinatura [#signature]

Quando você salva um endpoint de webhook, o Hearl cria um **Segredo de assinatura** para ele. Você pode mostrá-lo ou trocá-lo na página Notificações. A requisição traz este cabeçalho:

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

`<hex>` é o HMAC-SHA256 do corpo bruto da requisição, com a chave sendo o seu segredo de assinatura, em hexadecimal minúsculo. Calcule sobre os bytes exatos que você recebeu, antes de interpretar o JSON, e compare em tempo constante.

```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
```

Retorne qualquer status `2xx` para confirmar o recebimento.
