# Alerts and webhooks

> Get the mentions that need you by email, or send every new mention to your own endpoint

## Email alerts

Each project has two alert channels under **Alerts** on the **Settings** tab: **Email alerts**, off by default, and **Phone push**, on by default once a member has installed the iOS app and allowed notifications. They are independent, so for alerts on the iPhone only, turn email off and leave push on. The daily digest and webhooks don't depend on either.

After each scan, one email goes to every member of the project's organization with the new mentions that need action:

- urgency **High**, or
- type **Misinformation**, or
- type **Buying intent**, or
- a lead with active intent and fit of 80 or more (or your minimum fit, if it's higher). Older assessments without separate intent keep their previous alert rule.

Mentions judged unrelated never trigger an alert. If a scan finds nothing that needs action, no email is sent.

Each mention in the email shows its type, the author, the source, the start of the text and a link to the post; a misinformation mention also shows the claim and the fact it contradicts. The email ends with links to all mentions and to turn alerts off.

> **Note:** Alerts only go to members of the organization. You can't add another address.

## Daily digest

The digest is one email a day per organization, at 07:00 UTC, with everything new in the last 24 hours: every related mention and every lead at or above your minimum fit, grouped by project with the urgent ones first. Turn it on under **Daily digest** on the [Settings](/settings) page. It is off by default, goes to every member, and a day with nothing new sends no email.

Email alerts are separate, so an urgent post never waits for the digest.

## Monthly review

On the 1st of each month every member gets one email per organization, at 07:00 UTC, with what each project found in the last 30 days against the 30 before, and up to three changes worth making: a source that found nothing for a keyword at least 30 days old, a busy source worth searching more often, a lead profile that keeps finding the wrong audience, or product facts waiting for confirmation.

The **Review** tab shows the same numbers at any time, with what each keyword found and, on hosted Overhear, what it would cost per result at its current pace. Changes are never made for you: **Turn off** and **Speed up** apply one source's pace when you click them. Turn the email off under **Monthly review** on `/settings`.

## Competitor moments

When a competitor you track gets a burst of complaints (see [competitor moments](/docs/guides/mentions#competitor-moments)), the opened moment is announced once, by email if the project's email alerts are on, for example "Arcade: 23 complaints in 6h (usual 2). Outage.", with a one-line summary, the top 3 posts and a link to its leads. When it ends, one more email gives its totals: posts and leads. The iOS app gets the same as a push notification if the project's phone push is on. The daily digest lists moments opened or closed that day under **Moments**.

## Webhook

Add a **Webhook URL** on the **Settings** tab to receive a POST request for every new mention. Leave the field empty and save to turn it off.

- The URL must be a public `https` address. A query string, for example a token, is allowed.
- The first time you save a URL, Overhear creates a **signing secret** (`whsec_…`) and shows it under the field. Changing the URL keeps the secret. Turning the webhook off deletes it.
- Mentions judged unrelated are not sent.
- Leads arrive as `lead.created`, only at or above the project's minimum fit, with `fit` (customer suitability, 0–100), `fit_reason`, `intent`, and `evidence`. These fields are `null` for brand mentions; older lead assessments have no separate intent or evidence. Zero-fit results are excluded.
- Deliveries happen after classification, so they include the type and urgency.

### Payload

Each delivery is a JSON body with the event type `mention.created`:

```json
{
  "type": "mention.created",
  "timestamp": "2026-10-17T09:15:42.191921+00:00",
  "data": {
    "id": "6b7390bd-393c-4866-bacc-613021ea866c",
    "project": { "id": "…", "name": "Stepshots" },
    "keyword": "stepshots",
    "source": "x",
    "url": "https://x.com/…",
    "author": "coindotgo",
    "title": null,
    "text": "What tech stack do you use to ship so many tools?",
    "posted_at": "2026-10-12T08:01:00Z",
    "found_at": "2026-10-17T09:00:12Z",
    "engagement": 1,
    "category": "question",
    "category_label": "Question",
    "sentiment": "positive",
    "urgency": "medium",
    "fit": null,
    "fit_reason": null,
    "intent": null,
    "evidence": null
  }
}
```

- `source` is one of `x`, `reddit`, `linkedin`, `youtube`, `web`, `hackernews`.
- `category` is `lead`, `complaint`, `bug`, `question`, `praise`, `misinformation`, `other`, or the id of one of your own categories. `category_label` is the name shown in the app.
- `sentiment` is `positive`, `neutral` or `negative`. `urgency` is `high`, `medium` or `low`.
- `category`, `category_label`, `sentiment` and `urgency` are `null` when the mention couldn't be classified.

### Moment events

Competitor moments send `moment.opened` when one starts and `moment.closed` when it ends, signed and retried like the others:

```json
{
  "type": "moment.opened",
  "timestamp": "2026-11-02T09:15:42.191921+00:00",
  "data": {
    "id": "…",
    "project": { "id": "…", "name": "Stepshots" },
    "competitor": "Arcade",
    "kind": "outage",
    "summary": "Arcade has been down since this morning; demos fail to load",
    "baseline": 2.0,
    "peak": 23,
    "started_at": "2026-11-02T06:02:00Z",
    "ended_at": null,
    "posts": 23,
    "leads": 3,
    "top_posts": [{ "id": "…", "source": "x", "url": "https://x.com/…", "author": "…", "text": "…" }]
  }
}
```

- `kind` is `outage`, `pricing`, `shutdown`, `acquisition`, `release` or `other`.
- `baseline` is the usual complaints per 6 hours, `peak` the most in one 6-hour window.
- `webhook-id` is `msg_` plus the moment id and `_opened`, or `_closed_` and the end time.

### Verifying the signature

Deliveries are signed the [Standard Webhooks](https://www.standardwebhooks.com) way, so you can verify them with any of its libraries. Each request carries three headers:

| Header | Value |
| --- | --- |
| `webhook-id` | `msg_` plus the mention id. It stays the same on retries, so use it to skip duplicates. |
| `webhook-timestamp` | Unix seconds when the request was signed. |
| `webhook-signature` | `v1,` plus the base64 HMAC-SHA256 of `{webhook-id}.{webhook-timestamp}.{body}`, keyed with the base64-decoded part of the secret after `whsec_`. |

### Retries

Any response outside 2xx, or no response within 10 seconds, counts as a failure. A failed delivery is retried with increasing delays, up to 5 attempts in total.

