Slack & webhook alerts
Alongside email, Pro accounts can send alerts to a Slack channel or to any HTTPS endpoint you control. Up to 5 of each. Configure them under Settings in the dashboard.
When an alert fires
Every channel receives the same alerts, decided by the renewal-failure logic — not fixed countdowns. A threshold is one of:
renewal_failure— the certificate passed its expected renewal point (under ⅓ of its lifetime left) and no new certificate has been observed.7dand1d— the safety net: always sent at 7 days and 1 day before expiry. Only the one matching the days left is sent, so a domain added with 1 day left gets the 1-day alert alone.expired— sent once when the certificate being served has already expired.- Any other
Ndvalue, such as30d— an extra early warning you added under Settings → Alert schedule (Pro).
Each alert is sent once per certificate, per threshold, per channel. When the certificate is renewed, state resets. The full rules are in how alerts work.
Slack
- In Slack, create an app at api.slack.com/apps and enable Incoming Webhooks.
- Choose Add New Webhook to Workspace and pick the channel for alerts.
- Paste the URL (
https://hooks.slack.com/services/…) into Settings → Slack. We send a test message before saving, so a mistyped URL fails immediately.
Custom webhook
We POST JSON to your URL. When you add the endpoint, a signing secret is shown once — store it; it's used to verify requests came from NetworkAI.
{
"type": "certificate.alert",
"created_at": "2026-10-05T09:00:00.000Z",
"data": {
"hostname": "example.com",
"threshold": "renewal_failure",
"title": "Renewal failure: example.com's certificate hasn't renewed",
"expires_at": "2026-11-20T00:00:00.000Z",
"fingerprint": "AB:CD:EF:…",
"dashboard_url": "https://networkaitools.com/en/app"
}
}type is certificate.alert for real alerts and test for the test sent when you add a channel or press “Send test”.
Headers
| Header | Value |
|---|---|
| X-NetworkAI-Timestamp | Unix seconds when the request was signed |
| X-NetworkAI-Signature | sha256=HMAC_SHA256(secret, "timestamp.body") |
| User-Agent | NetworkAI-Alerts/1.0 |
Verify the signature
Compute the HMAC over the timestamp, a dot, and the raw request body, then compare in constant time. Reject requests whose timestamp is more than a few minutes old.
import crypto from "node:crypto";
// rawBody must be the exact bytes received — verify BEFORE JSON.parse.
export function verifyNetworkAI(secret, headers, rawBody) {
const timestamp = headers["x-networkai-timestamp"];
const signature = headers["x-networkai-signature"];
if (!timestamp || !signature) return false;
// Reject old requests so a captured one can't be replayed.
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected =
"sha256=" +
crypto.createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signature);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}import hmac, hashlib, time
def verify_networkai(secret: str, headers: dict, raw_body: bytes) -> bool:
timestamp = headers.get("X-NetworkAI-Timestamp")
signature = headers.get("X-NetworkAI-Signature")
if not timestamp or not signature:
return False
# Reject old requests so a captured one can't be replayed.
if abs(time.time() - int(timestamp)) > 300:
return False
signed = timestamp.encode() + b"." + raw_body
expected = "sha256=" + hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)Delivery rules
- Respond with any
2xxwithin 10 seconds to acknowledge. - Failures that may be temporary (network errors,
408,429,5xx) are retried 3 times with backoff. Other4xxresponses are not retried. - If all attempts fail, the alert is retried on the next daily check, and the error is shown on the channel in Settings.
- Redirects are not followed. The URL must be
httpsand publicly reachable — private, loopback and link-local addresses are refused. - Your handler should be idempotent: during retries you may occasionally see the same alert twice.