> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trychert.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Notifications

> Reply notification card anatomy, the Review and reply deep link, and thread-reply triage with Chert Notifications.

When a lead replies, Chert Notifications posts a Block Kit card in the
bound channel. Operators triage from the card — either by clicking
through to the CRM or by replying directly in the Slack thread.

## Before You Begin

* Chert Notifications is installed and a channel is bound.
* `notificationMethod` is set to `slack` or `both` (see [Configuration](/slack/configuration)).

## Card anatomy

| Section                   | Purpose                                                                           |
| ------------------------- | --------------------------------------------------------------------------------- |
| **Headline**              | `:speech_balloon: Lead Name at Company replied`                                   |
| **Context strip**         | Project name, campaign name, phone line label, lead phone number                  |
| **Conversation tail**     | Up to the last 8 non-system messages, formatted as quoted blocks with timestamps  |
| **Suggested reply**       | Either a campaign-templated reply or an AI-drafted draft, in a code block         |
| **Review & reply button** | Opens the lead's conversation pane in the Chert console with the draft pre-filled |
| **In-thread hint**        | Reminder that you can reply in-thread to direct the bot                           |

The card ts is recorded in `convo.reply_notify_slack_ts`. Thread
replies use this ts as the join key back to the lead.

## Review & reply deep link

The button URL has the shape:

```
https://console.trychert.com/?project=<projectId>&lead=<leadId>&draft=ready
```

Clicking opens the slide-over conversation panel for that lead. If a
draft was attached to the notification, it is pre-filled in the reply
composer.

<Frame caption="The slide-over conversation panel a Slack reply card deep-links to.">
  <img src="https://mintcdn.com/cherttechnologiesinc/7NuyCzLl8sIsJEKo/images/screenshots/console/leads-with-slideover.png?fit=max&auto=format&n=7NuyCzLl8sIsJEKo&q=85&s=eb8501ca33636ba80e201053bde4e461" alt="The Chert console slide-over conversation panel that the Slack notification deep link opens" width="1518" height="832" data-path="images/screenshots/console/leads-with-slideover.png" />
</Frame>

## Thread-reply triage

Replying in the card's thread routes the message through Chert
Notifications' LLM, which classifies it as either a **question** or a
**draft**.

<Frame caption="Thread-reply triage flow">
  <img src="https://mintcdn.com/cherttechnologiesinc/7NuyCzLl8sIsJEKo/slack/diagrams/thread-reply-flow.svg?fit=max&auto=format&n=7NuyCzLl8sIsJEKo&q=85&s=4e36a59b2def65ead838cb4921cdf402" alt="Thread-reply flow" width="1000" height="540" data-path="slack/diagrams/thread-reply-flow.svg" />
</Frame>

### Direct mention is required

The bot only reacts to thread replies that include `@Chert
Notifications` (or whatever name the workspace gave the bot). Bare
in-thread chatter between operators is ignored, so two people
deliberating in a thread does not trigger anything.

### Question vs draft classification

| Heuristic                                                                                                                                  | Routing                                                                                                                      |
| ------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| Reply contains a `?`, or starts with `what / who / when / why / where / how / did / does / is / are / any / can you / could you / tell me` | Treated as a **question**. The bot answers in-thread using the lead's recent conversation, campaign, and phone-line context. |
| Otherwise                                                                                                                                  | Treated as a **draft**. The bot polishes the body and posts a confirmation card with ✅/❌ reactions.                          |
| Ambiguous                                                                                                                                  | Defaults to **draft** with a hedge — re-ask with a `?` to flip to question mode.                                             |

### Approving a drafted reply

When the bot posts a draft confirmation card, react with:

| Reaction                                                 | Effect                              |
| -------------------------------------------------------- | ----------------------------------- |
| ✅ `:white_check_mark:` or `:heavy_check_mark:` or `:+1:` | Send the drafted reply to the lead. |
| ❌ `:x:` or `:no_entry_sign:` or `:-1:`                   | Cancel. Nothing is sent.            |

Approval is processed as soon as Slack delivers the reaction event. A
fallback cron also resolves pending proposals, so a missed event still
gets reconciled.

### Card refinement

If you reply again in the thread while a draft confirmation is
pending, the previously pending card is auto-rejected and a fresh card
is posted with the refined draft. You always see exactly one live card
per thread.

Examples:

| Thread reply                    | Effect                                                     |
| ------------------------------- | ---------------------------------------------------------- |
| `make it shorter`               | Old card rejected. New card posted with a shorter draft.   |
| `add a calendar link`           | Old card rejected. New card posted with the link inserted. |
| `same idea but mention pricing` | Old card rejected. New card mentions pricing.              |

<Note>
  An auto-rejected proposal records `superseded by &lt;new id&gt;` in
  the audit trail so the history of refinements is preserved.
</Note>

## Webhook payload

When `notificationMethod` is `webhook` or `both`, every qualifying
reply is also POSTed to your `webhookUrl`.

```json theme={null}
{
  "event": "lead_reply",
  "event_id": "<leadid>:<sha256>",
  "timestamp": "2026-04-22T...",
  "project": { "id": "...", "name": "..." },
  "lead": {
    "id": "...", "name": "...", "phone": "...",
    "company": "...", "linkedin_url": "...",
    "custom_fields": { ... }
  },
  "inbound_message": { "text": "...", "timestamp": "..." },
  "conversation": [
    { "role": "outbound" | "inbound" | "system",
      "text": "...", "timestamp": "..." }
  ],
  "suggested_reply": "AI-drafted text or null",
  "crm_deep_link": "https://console.trychert.com/?project=...&lead=...&draft=ready",
  "meta": {
    "inbound_count": 2, "outbound_count": 1,
    "campaign_name": "...", "phone_line_label": "..."
  }
}
```

Headers:

| Header              | Purpose                                                                                   |
| ------------------- | ----------------------------------------------------------------------------------------- |
| `x-chert-event`     | Always `lead_reply`                                                                       |
| `x-chert-event-id`  | Dedup key for replays                                                                     |
| `x-chert-timestamp` | Unix seconds                                                                              |
| `x-chert-signature` | `v1,<ts>,<hex>` HMAC-SHA256 of `<ts>.<raw-body>`, only when `webhookSecret` is configured |

Retry on 5xx or network failure up to 3× with exponential backoff
(1s → 2s → 4s). 4xx is terminal.

## See Also

<CardGroup cols={2}>
  <Card title="Configuration" icon="gear" href="/slack/configuration">
    Notification routing and the Nth-reply filter.
  </Card>

  <Card title="Security" icon="shield" href="/slack/security">
    Signature verification and what the bot reads vs. writes.
  </Card>
</CardGroup>
