Notifications
Feedbot analyzes each conversation: summary, category, priority, lead score and whether a human is needed. Notification rules decide what gets sent where.
Channels
Section titled “Channels”Channels belong to the workspace. Add them in Settings → Notifications, then choose which bots send to which channel.
| Channel | Setup |
|---|---|
| Telegram | Click Open in Telegram (private chat) or Add to a group. The connect link is valid for 24 hours; create a new one if it expires. |
| One address per channel. Add several channels for several addresses. | |
| Slack | Paste an Incoming Webhook URL (https://hooks.slack.com/...). |
| Discord | Paste a channel webhook URL (https://discord.com/api/webhooks/...). |
| Webhook | Any HTTPS URL. Use it for Zapier, Make, n8n or your own backend. Pro and Business. |
The Telegram channel is also where your team answers visitors live. See Human handoff & email replies.
Each bot has its own rule for each channel:
| Setting | What it does |
|---|---|
| Minimum priority | From “Everything (1+)” to “Only urgent (5)”. |
| Categories | support, sales, payments, complaint, feedback, bug, partnership, other. All means every category except spam and useless chats. |
| Only when a human is needed | Skip conversations the bot handled on its own. |
| Always notify about new leads | Hot leads (lead score 70+) are sent even if they don’t match the filters above. On by default. |
| Silent when not urgent | Telegram messages arrive without sound unless a human is needed. |
| Tickets: new and resolved | Ticket messages and ticket.created / ticket.resolved webhook events for this bot. In a digest: the number of new and resolved tickets. On by default. |
| Delivery | Instant, Daily digest or Weekly digest. |
Spam is never sent. Each conversation is sent at most once, even if it is analyzed again later.
A digest is one message with up to 25 conversations ([category, priority] summary) that match the rule’s priority, category and “human needed” filters. With Tickets: new and resolved on, it starts with a line like Tickets: 3 new, 2 resolved for the period. A period with no matching conversations and no tickets sends nothing.
What a notification contains
Section titled “What a notification contains”Telegram, Slack, Discord and email messages show the bot name, category, priority (1–5), whether a human is needed, the lead score (when it is 50 or higher), tags, the summary, the visitor’s name, email and phone, and an Open conversation link.
Tickets
Section titled “Tickets”Every channel with an Instant rule for a bot that has Tickets: new and resolved on (the default) also gets a short message when a ticket of that bot is created or resolved: “🧾 New ticket · Refund · Acme” or “✅ Ticket resolved · Refund · Acme”, the ticket title and an Open link. This covers tickets created by the bot, the AI analysis, your team or the API, and tickets closed in the dashboard or through the API. Each channel gets it once, even with several rules.
Turn the toggle off in the rule (Settings → Notifications, the gear next to a bot and channel) to keep a channel for conversations only. Ticket filters don’t use the rule’s priority, category or “human needed” settings: the toggle is the only switch. Digest rules don’t get ticket messages one by one; they get the ticket counts in the digest instead.
Webhook
Section titled “Webhook”Feedbot sends a POST with a JSON body and these headers:
| Header | Value |
|---|---|
Content-Type |
application/json |
User-Agent |
FeedbotAI-Notifier/2 |
X-Feedbot-Event |
conversation.analyzed, digest, ticket.created or ticket.resolved |
X-Feedbot-Delivery |
The event id (evt_…), the same on every retry. |
X-Feedbot-Signature |
t=<unix seconds>,v1=<hex signature> |
The webhook secret (whsec_...) is shown only once, when you create the channel. Your endpoint must answer with a 2xx status within 15 seconds.
Retries
Section titled “Retries”If your endpoint fails (an error, a non-2xx status or a timeout), the delivery is retried up to 8 attempts in total over about two days: after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, 12 hours and 24 hours. Every attempt has the same id and a fresh signature, so deduplicate by id (or X-Feedbot-Delivery). Retries stop when the channel is deleted.
Envelope
Section titled “Envelope”Every event has the same envelope (version 2):
{ "id": "evt_8a3b…", "version": 2, "type": "conversation.analyzed", "createdAt": "2026-09-29T10:16:05Z", "data": { }}| Field | Description |
|---|---|
id |
Unique event id. |
version |
2. Bodies without version come from the old format. |
type |
The event type, same as X-Feedbot-Event. |
createdAt |
When the event happened, RFC 3339 UTC. |
data |
The event payload, described below. |
For compatibility, conversation.analyzed and digest also repeat their fields at the top level, as they were sent before the envelope. These top-level copies are deprecated: read data in new code. New event types have no top-level copies.
conversation.analyzed
Section titled “conversation.analyzed”{ "id": "evt_8a3b…", "version": 2, "type": "conversation.analyzed", "createdAt": "2026-09-29T10:16:05Z", "data": { "botId": "5521cdf1-…", "botName": "Acme", "conversationId": "9f0c…", "summary": "Team of 5, wants Pro yearly, asked about SSO", "category": "sales", "tags": ["pricing"], "priority": 4, "humanNeeded": true, "leadScore": 80, "sentiment": 0.3, "url": "https://app.feedbotai.com/c/9f0c…" }, "botId": "5521cdf1-…", "…": "the same fields as data (deprecated)"}contact fields are omitted when unknown. tags is always an array ([] when there are none).
digest
Section titled “digest”{ "id": "evt_1f20…", "version": 2, "type": "digest", "createdAt": "2026-09-29T10:00:00Z", "data": { "title": "Daily digest: Acme (12 conversations)", "text": "• [sales, p4] Team of 5, wants Pro yearly…", "url": "https://app.feedbotai.com/b/5521cdf1-…/conversations" }, "title": "Daily digest: Acme (12 conversations)", "text": "• [sales, p4] Team of 5, wants Pro yearly…", "url": "https://app.feedbotai.com/b/5521cdf1-…/conversations"}The weekly insights report is also delivered to channels as a digest event.
ticket.created and ticket.resolved
Section titled “ticket.created and ticket.resolved”Sent to webhook channels with an instant rule for the ticket’s bot that has Tickets: new and resolved on.
{ "id": "evt_c94e…", "version": 2, "type": "ticket.resolved", "createdAt": "2026-09-30T08:41:12Z", "data": { "id": "7d1e…", "botId": "5521cdf1-…", "botName": "Acme", "conversationId": "9f0c…", "conversationUrl": "https://app.feedbotai.com/c/9f0c…", "url": "https://app.feedbotai.com/t/7d1e…", "type": "refund", "typeName": "Refund", "title": "Refund · order #1234", "description": "Charged twice for the yearly plan.", "status": "done", "priority": 4, "source": "bot", "resolution": "We refunded the second charge." }}source is ai, bot, manual or api. priority is 1 to 5 (5 = urgent). resolution is the reply sent to the customer when the ticket was closed, or an empty string.
New leads for your CRM have their own webhook with a lead.created event in the same envelope. See Leads & CRM export.
Verify the signature
Section titled “Verify the signature”The signature is the hex HMAC-SHA256 of "<t>.<raw body>" with your webhook secret. Check it against the raw request body, before parsing JSON, and reject old timestamps to block replays.
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyFeedbotSignature(rawBody: string, header: string, secret: string, toleranceSec = 300) { const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2) as [string, string])); const t = Number(parts.t); if (!t || !parts.v1 || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false; const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex"); return expected.length === parts.v1.length && timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));}