New lead notifications
Email the team, post to Slack or call a signed webhook the first time a visitor shares their contact details.
The first time a visitor shares their contact details, PepoChat can tell your team. Choose any mix of an email to the team, a card in your Slack channel and a signed webhook for Zapier, Make, n8n or your own endpoint. Returning contacts and chats from the test drawer never trigger a notification.
Turn it on
Open Widget Customization and scroll to When a new lead arrives, right under Lead Capture. Switch on the channels you want and click Save Settings. Each channel has its own test button, so you can see a sample lead land before a real visitor does; the test sends a lead called "Test Lead" with the email [email protected], marked as a test.
| Channel | What happens | Needs |
|---|---|---|
| Email the team | Every member gets an email with the lead's name, email, phone, company and source, and a button to the conversation (or to Contacts when the lead has no conversation yet). | The Starter or Growth plan; on Free, the switch opens the plans so you can upgrade in place. Members who don't want it can switch it off under Profile → Notifications → Email me when a new lead arrives. |
| Post to Slack | A short card with the same details and an Open conversation button, in the channel your Slack integration posts to. | Slack connected. Until then the switch is disabled and links you to App Integrations. |
| Send to a webhook URL | A JSON POST with the lead, signed with a secret shown on the card. | A public https:// URL: a Zapier Catch Hook, a Make or n8n webhook trigger, or an endpoint you host. |
Under each channel the card shows the latest result: Last sent 3 minutes ago, or Last attempt failed with the reason, for example HTTP 404: no_service when a Slack hook was revoked, or Slack is not connected.
When it fires
A notification is sent once per contact, the first time an email is captured in your workspace, whichever way it arrives: the pre-chat form, the agent's question, email verification or a booking. A returning visitor with the same email updates their contact but does not notify anyone again.
A lead from the pre-chat form is sent about 20 seconds after the form, so that the conversation the visitor starts right after it can be linked. If the visitor never sends a message, the notification links to the Contacts page instead.
The webhook
Paste the URL, switch the webhook on, click Send a test and then Save Settings. Saving generates the signing secret (whsec_…), shown on the card to owners and admins; use Rotate to replace it. Failed deliveries are retried after 1 minute and again after 10 minutes, then given up; a 2xx response counts as delivered, timeouts and 5xx responses are retried, and any other response (a 404, a 400, a redirect) fails immediately.
Payload
{
"event": "contact.created",
"deliveryId": "k57…",
"createdAt": "2026-09-28T10:00:00.000Z",
"test": false,
"workspace": { "id": "jh7…", "name": "Acme" },
"contact": {
"id": "k97…",
"email": "[email protected]",
"name": "Ada Lovelace",
"phone": null,
"company": "Analytical Engines",
"source": "form",
"firstSeenAt": "2026-09-28T09:59:40.000Z",
"url": "https://app.pepochat.com/contacts"
},
"conversation": {
"id": "k17…",
"url": "https://app.pepochat.com/conversations/k17…"
}
}
sourceisform(pre-chat form),chat(the agent asked),verification(verified email) orbooking.name,phoneandcompanyarenullwhen the visitor did not give them;conversationisnullwhen there is no conversation yet.testistruefor the card's Send a test; a real lead always hasfalse.- Field names never change; new fields may be added.
Headers
| Header | Value |
|---|---|
Content-Type | application/json |
User-Agent | PepoChat-Webhooks/1.0 |
X-PepoChat-Event | contact.created |
X-PepoChat-Delivery | The delivery id (also in the body), or test |
X-PepoChat-Signature | t=<timestamp>,v1=<signature> |
Verify the signature
The signature is an HMAC-SHA256 of the timestamp, a dot and the raw request body, keyed with your signing secret, in lowercase hex. Compare it with a constant-time comparison and reject timestamps older than a few minutes:
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyPepoChat(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(
signatureHeader.split(",").map((part) => part.split("=")),
);
const expected = createHmac("sha256", secret)
.update(`${parts.t}.${rawBody}`)
.digest("hex");
const fresh = Math.abs(Date.now() - Number(parts.t)) < 5 * 60 * 1000;
return (
fresh &&
expected.length === parts.v1.length &&
timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))
);
}
Zapier, Make and n8n accept the POST as it is; map contact.email, contact.name and conversation.url into whatever comes next. Their catch URLs are not signed on their side, so treat the URL itself as a secret and regenerate it there if it leaks.
Good to know
- All three channels use the same event, so a lead never arrives on one and not another unless a delivery failed; the card shows which.
- The team email is the one paid-only channel. If a subscription lapses, the emails stop and the card shows the switch off; Slack cards and the webhook keep working on every plan.
- Emails and Slack cards escape whatever the visitor typed, so a name cannot ping
@channel. - Each workspace is limited to 120 notifications an hour (bursts of 40). Past that, contacts are still saved and shown on the Contacts page; only the notifications are skipped.
- The webhook URL is visible to every member of the workspace on the card, like a connected integration's webhook URL. The signing secret is shown only to owners and admins, and only they can rotate it; other members see that one is set.
- Delivery results are kept for 30 days.
Something missing or wrong on this page? Tell us and we will fix it.
