Notifications
Set up Slack, Telegram, Teams, Discord, webhooks and email
Available on the Pro, Agency and Provider plansUpdated September 2026
Every channel is added on Team → Notifications by an owner or admin. Once it is connected, pick its events in the matrix and click Send test. For how events, retries and the delivery log work, see Notifications. Team channels never receive events about private links.
On this page
Slack
Add to Slack (when shown) is the easiest way: Slack asks which channel to post to, and you land back on the Notifications page with the channel connected.
Without that button, click Add Slack webhook and paste an incoming webhook URL (https://hooks.slack.com/services/…). Create one in Slack under Apps → Incoming Webhooks for the channel you want.
Telegram
Click “Connect Telegram”
You get a one-time link and a QR code for your phone, valid for 10 minutes.
Open the bot and press Start
That connects your private chat. To send events to a group instead, choose Use in a group and pick the group; the bot joins it and confirms.
Wait for the dialog to confirm
The channel appears as soon as the bot has connected. Sending
/stopin the chat later disables it.
Microsoft Teams and Discord
- Teams: create a Workflows webhook (“Post to a channel when a webhook request is received”) or an incoming webhook in the channel, then click Add Teams and paste its URL. Accepted hosts are
*.webhook.office.com,*.logic.azure.comand*.environment.api.powerplatform.com. - Discord: in the channel settings go to Integrations → Webhooks, create one and copy its URL, then click Add Discord and paste it.
Email address
Add email sends events to any address, typically a shared inbox or a distribution list. Personal emails to each member are separate and are set by each person in Settings → Notifications.
Webhook to your own system
Click Add webhook and enter an https:// URL on a public host. DNSPeek shows the channel’s signing secret once: copy it into your endpoint’s configuration. Lost it? Rotate signing secret in the channel menu gives you a new one; the old one stops working at once.
Each event is a POST with a JSON body and these headers:
| Header | Value |
|---|---|
X-DNSPeek-Event | Event type, such as qa.completed (test for “Send test”). |
X-DNSPeek-Delivery | Delivery ID. The same delivery may be retried, so use it to ignore duplicates. |
X-DNSPeek-Timestamp | Unix time in seconds when the request was signed. |
X-DNSPeek-Signature | sha256= followed by the hex HMAC-SHA256 of “<timestamp>.<raw body>”, keyed with the channel’s signing secret. |
{
"id": "evt-uuid",
"type": "qa.completed",
"version": 1,
"createdAt": "2026-09-26T10:00:00.000Z",
"workspace": { "id": "…", "name": "Acme" },
"link": { "id": "…", "alias": "shop", "domain": "shop.example.com", "spaceId": null },
"data": { "linkId": "…", "reportId": "…", "score": 87, "pagesCrawled": 12, "requestedBy": "…" },
"message": {
"title": "QA report ready for shop.example.com (score 87)",
"body": "…",
"severity": "success",
"url": "https://…",
"fields": [{ "label": "Score", "value": "87" }]
}
}Answer with any 2xx status within 5 seconds. Timeouts, 408, 429 and 5xx answers are retried; other 4xx answers fail the delivery. Redirects are not followed.
Verify the webhook signature
Always check the signature before trusting a request, and reject old timestamps so a captured request cannot be replayed:
import { createHmac, timingSafeEqual } from 'node:crypto';
// rawBody: the request body exactly as received, before JSON parsing.
export function verifyDnspeek(rawBody, headers, secret, toleranceSeconds = 300) {
const timestamp = headers['x-dnspeek-timestamp'];
const signature = headers['x-dnspeek-signature'] ?? '';
if (!timestamp || Math.abs(Date.now() / 1000 - Number(timestamp)) > toleranceSeconds) return false; // replay
const expected = 'sha256=' + createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex');
const a = Buffer.from(signature);
const b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
}