BuzzGleanBuzzGlean

Webhooks

Receive matches as JSON on your own endpoint, and verify they came from BuzzGlean.

A webhook channel sends every alert batch to your HTTPS endpoint as a JSON POST. Use it to push matches into a CRM, a help desk, a spreadsheet automation (Zapier, Make, n8n) or your own service.

Create one in the app under Notifications → New channel → Webhook, or with the REST API.

Request

  • URL: a public HTTPS endpoint. Localhost, private IP ranges and cloud metadata addresses are rejected; use a tunnel such as ngrok to test locally.
  • Method: POST
  • Content type: application/json
  • Timeout: your endpoint must respond within 5 seconds with a 2xx status. Do slow work asynchronously after responding.
  • Signature: X-App-Signature header, when the channel has a signing secret (see below).

Payload

POST https://example.com/buzz-alerts
{
  "type": "buzz.alert_batch",
  "sent_at": "2026-10-29T09:14:03.120Z",
  "channel_id": "5f0c1c8e-7c1a-4d0f-9a43-2f1d6c3e9b10",
  "settings": {},
  "batchId": "b_8c2f",
  "alertRuleId": "r_41aa",
  "ruleName": "CRM shoppers",
  "ruleContent": "People looking for a simple, affordable CRM, or unhappy with their current one.",
  "ruleKeywords": ["CRM", "switching"],
  "posts": [
    {
      "id": "post_01",
      "post_id": "733291000000001",
      "group_id": "smallbusiness",
      "source": "reddit",
      "source_type": "subreddit",
      "source_id": "smallbusiness",
      "page_name": "r/smallbusiness",
      "author_name": "Minh Nguyen",
      "title": null,
      "rating": null,
      "content": "We're a 3-person team and our current CRM just doubled its price. Any CRM that's simple and doesn't cost a fortune?",
      "url": "https://reddit.com/r/smallbusiness/comments/example1",
      "created_at": "2026-10-29T09:02:11.000Z",
      "ai_score": 0.94,
      "ai_reason": "Asking for a CRM recommendation",
      "tags": ["recommendation_request", "buy_intent"],
      "sentiment": "neutral",
      "matched_keywords": ["CRM"],
      "detail_url": "https://buzzglean.com/app/posts/post_01"
    },
    {
      "id": "post_02",
      "post_id": "trustpilot.com:6720f1c2a9b3e4d5f6a7b8c9",
      "group_id": "w_3f9a1c2b7d4e8f60",
      "source": "trustpilot",
      "source_type": "page",
      "source_id": "w_3f9a1c2b7d4e8f60",
      "page_name": "Example CRM reviews",
      "author_name": "Laura K.",
      "title": "Support never got back to me",
      "rating": 2,
      "content": "Import failed twice and I've been waiting four days for an answer from support. Thinking about switching.",
      "url": "https://www.trustpilot.com/reviews/6720f1c2a9b3e4d5f6a7b8c9",
      "created_at": "2026-10-29T08:47:30.000Z",
      "ai_score": 0.88,
      "ai_reason": "Unhappy customer considering switching",
      "tags": ["complaint", "alternative_seeking"],
      "sentiment": "negative",
      "matched_keywords": ["switching"],
      "detail_url": "https://buzzglean.com/app/posts/post_02"
    }
  ]
}
FieldDescription
typeAlways buzz.alert_batch for alerts.
sent_atWhen this request was sent (ISO 8601).
channel_idThe webhook channel that sent it.
settingsThe channel's non-secret settings (usually empty).
batchIdUnique id of this batch. Use it to de-duplicate retries.
alertRuleIdThe rule that produced the matches.
ruleNameThe rule's name.
ruleContentThe rule's description (what AI looks for).
ruleKeywordsThe rule's keywords ([] when it has none).
posts[]The matched posts.
posts[].sourceThe platform: facebook, reddit, a site id (trustpilot, g2, capterra, apple_app_store, google_play) or web for any other site.
posts[].source_typegroup (Facebook group), subreddit, or page (review site, app store or web page).
posts[].source_idId of the source: the Facebook group id, the subreddit name, or a page id like w_3f9a… for other pages.
posts[].group_idSame as source_id; kept for compatibility.
posts[].page_nameThe source's name as shown in the app.
posts[].titleThe review or post title, when the site has one.
posts[].ratingThe star rating for reviews (for example 1-5), otherwise null.
posts[].urlLink to the original post.
posts[].ai_scoreRelevance from 0 to 1.
posts[].ai_reasonWhy AI matched the post.
posts[].tagsTag keys assigned by AI (see taxonomy).
posts[].sentimentpositive, neutral or negative; null when the rule has sentiment analysis turned off.
posts[].matched_keywordsThe rule's keywords found in the post. Older matches without this information get the rule's keywords.
posts[].detail_urlThe match in the BuzzGlean app.

Fields that aren't known for a post are null or omitted. Facebook posts may also include fb_group_id and fb_post_id. For review sites and app stores, post_id is prefixed with the site's domain.

Verify signatures

When a webhook channel has a signing secret, each request carries:

X-App-Signature: sha256=<hex HMAC-SHA256 of the raw request body>

Compute the HMAC over the raw body bytes (before parsing JSON) with your secret and compare in constant time.

Set the secret in the channel form (Signing secret → Generate, then copy it before saving), or with webhook_secret in the REST API. The secret is write-only: BuzzGlean never shows it again, so store it in your endpoint's configuration. Channels without a secret send unsigned requests.

import { createHmac, timingSafeEqual } from "node:crypto"

export function isValidSignature(rawBody: string, header: string | null, secret: string) {
  if (!header) return false
  const expected = `sha256=${createHmac("sha256", secret).update(rawBody).digest("hex")}`
  const a = Buffer.from(expected)
  const b = Buffer.from(header)
  return a.length === b.length && timingSafeEqual(a, b)
}

Test your endpoint

From the channel's actions menu, choose Send test alert, or call POST /channels/{id}/test with the API. BuzzGlean sends a sample batch to your endpoint; a 2xx response marks the channel as verified.

Best practices

  • Respond fast: return 200 immediately, then process the batch in the background.
  • De-duplicate: a batch may be delivered more than once; use batchId and posts[].id to ignore repeats.
  • Use HTTPS and verify the signature before trusting the body.

Tags and sentiment

TypeLabelAPI value
SentimentPositivepositive
SentimentNeutralneutral
SentimentNegativenegative
TagBuy intentbuy_intent
TagAsking for recommendationsrecommendation_request
TagLooking for alternativesalternative_seeking
TagComplaintcomplaint
TagPraisepraise
TagQuestionquestion
TagFeedbackfeedback
TagOtherother

On this page