Alerts & notifications¶
CertIntel can push certificate and security events to a webhook destination as
they happen, instead of relying on someone checking the dashboard. Configure
destinations on the Alert Settings page, scoped to one organization or
(tenant administrators, or a tenant-wide role holding notifications.create)
Entire workspace (all organizations). Viewing, creating, editing, testing and
deleting destinations are separate permissions (notifications.read / .create /
.update / .test / .delete); the built-in Alert Manager role holds all five,
the read-only Observer and Auditor roles can view destinations and their
delivery history (Viewer cannot), and a custom role can hold any subset - see
Organizations, users & roles. Alert destinations are a plan feature; a plan without them shows
Alert destinations are not included in this subscription.
Alert contacts - email recipients without a CertIntel
login - have their own permissions, alert_contacts.read and
alert_contacts.update.
Destination kinds¶
| Kind | Payload shape |
|---|---|
| Generic webhook | A JSON POST in CertIntel's own schema (version 4, below) - the default choice for custom automation. |
| Slack | A Block Kit message: emoji header, the labelled fields, one section per finding category, an Open CertIntel button, plus a plain-text fallback for notifications. |
| Discord | A colour-coded embed (red for critical, amber for warning, green for a resolved renewal): the labelled fields in the description, one field per category. |
| Microsoft Teams | An Adaptive Card 1.4 (full width) with a tinted banner, the labelled fields as a fact set, bold headings per category and an Open CertIntel action. |
| A multipart message: an HTML body in the CertIntel look with your tenant's custom colors, plus a plain-text alternative. | |
| Pushover | Pushover's API with HTML formatting (bold, coloured headings, link), a severity-shifted priority and a supplementary dashboard URL. |
| ntfy | A Markdown message with Title, Priority, Tags (emoji), Click and an Open CertIntel action on a topic on ntfy or a self-hosted instance. |
What every alert says¶
Every destination receives the same shape, so an alert reads the same whether it lands in Slack, Teams, a mailbox or a phone:
- Header -
<emoji> <event type> ā <what happened> ā <organization>, for example šØ ACME renewal failed ā api.acme.example ā Production or ā ļø Warning alert ā 2 certificate(s) approaching expiry ā All organizations. A daily summary is headed Daily summary ā ā¦. Only the header is large. - Destination - the name of the alert destination the message was sent to.
- Type - ACME renewal failed, Security warning, New findings Ā· Critical, Daily summary Ā· Warning, Test message, and so on.
- Organization - the organization the alert is about. A destination scoped to the entire workspace says so: Production (tenant-wide alert) or All organizations (tenant-wide alert).
- Description - what happened and why, in a sentence or two: which categories an alert or a daily summary covers, or what an agent reported for a renewal.
- Error and What to do - on a failed renewal (ACME renewal failed):
the first line of the renewal's error (at most 200 characters) and the
advice the renewal's page gives, read when the message is sent. The advice
is never cut inside a sentence: text over 1,500 characters ends at a
sentence with The renewal's page has the rest.
The advice names the one Agent command that applies:
certintel certificates issue IDfor a certificate that was never issued,certintel certificates force-renew IDotherwise. - Next attempt - on a failed renewal: when the Agent tries again by itself, or that it stopped retrying and what starts it again (see When the Agent tries again).
- <CA> status - on a failed ACME issuance only, never on a failed
installation: what the certificate authority's own status page says (an
ongoing incident, maintenance in progress, something just resolved, or
nothing reported), with a link to that page, for the CAs that publish one.
It is left out when the error is the DNS-01 record's, not the CA's: the
Agent's CNAME check (a CNAME that points elsewhere, or none), publishing
the TXT record, or an NXDOMAIN for the
_acme-challengename. - Links - the renewal, activity log or filtered list page for each finding
category, followed by Alert Settings. Links open your workspace's own
address (
https://<slug>.app.certin.tel) when your plan includes a workspace address, so recipients land where they sign in; otherwise they use the platform's shared address. Links appear only when the platform has a public origin configured. Unsubscribe links always use the shared address.
An alert with findings, and a daily summary, then lists each finding under its category heading, every item linked to its certificate, endpoint, CRL or agent. A certificate without a subject CN is named by its first DNS name. An alert that lists only what is new closes with the number of other findings that are still open (3 other findings are still open; they are listed in the daily summary.).
Slack, Discord and Teams are destination kinds of their own, so a generic webhook only offers the JSON format, JSON (CertIntel schema v4). A destination created earlier with a chat format on a generic webhook keeps working and shows that format as (legacy) when edited.
Severity, emoji and priority¶
Every message is headed by its severity: šØ Critical (a certificate inside the critical window, a failing monitor, an overdue or unreadable CRL, a failed renewal), ā ļø Warning (approaching expiry or next update, a security warning, an endpoint still serving an old certificate, a new name set in Certificate Transparency, an overridden deployment window), ā Resolved (a successful renewal) or š§Ŗ Test. Each finding category inside an alert or a daily summary carries its own heading, emoji and colour.
For Pushover and ntfy the Priority you choose is a baseline: a critical
alert is sent one step higher, a test message one step lower, and anything else
at the baseline. Pushover never escalates to its emergency priority on its own.
ntfy also receives the severity as tags (rotating_light, warning,
white_check_mark, test_tube) and certintel, so you can filter or route on
them.
When the platform has a public origin configured, chat cards, push messages and emails carry an Open CertIntel button (the first finding category's list page, the renewal, or Alert Settings for a test) beside the Links field.
Email¶
Platform email server sends from the platform's configured address and
needs no further settings; the custom SMTP fields are hidden until you choose
Custom SMTP server. Both transports send the same message: an HTML body in
the CertIntel look (with the tenant's primary colour and light-mode palette
overrides applied, see Branding & appearance) and a
plain-text alternative. The subject starts with the severity emoji and what
happened to which certificate or agent, followed by
CertIntel alert ā <organization> [<tier>], so filters on that part keep
matching: šØ Installation failed: api.example.com ā CertIntel alert ā
Production [critical], Revoked: web.example.com (keyCompromise) ā ā¦,
Agent offline: web01 ā ā¦. An alert with findings names its most severe
category: its finding when it has one, otherwise its heading, and +N more
counts the other categories. A daily summary starts Daily summary: 4 findings
open ā CertIntel alert ā ā¦, so the inbox tells the two apart. Push
notifications and the webhook title use the same text. The message is fluid: it fills the
reading pane up to 1100 px wide, so a wide preview pane shows more of each
line, and a phone gets a single edge-to-edge column. The footer names the
destination and links to Alert Settings; scheduled report emails use the
same layout and link to Scheduled Reports.
An email destination sends to up to 20 addresses entered under Recipients and up to 50 alert contacts; enter recipients, choose contacts, or both. Every alert and scheduled-report email goes out as one message per recipient, so nobody sees the other recipients' addresses. This includes custom SMTP servers. Each message carries that recipient's own unsubscribe link.
Alert and report emails never contain a link to download a private key or a certificate.
With MSP co-branding (Enterprise) turned on for an organization, alert emails of destinations scoped to that organization and its scheduled reports are headed <workspace> for <client>. This is text only; emails carry no client logo.
Alert contacts¶
An alert contact is a named email recipient who does not need a CertIntel login - an on-call mailbox, a service owner, a customer's administrator. Manage contacts in the Alert contacts section of the Alert Settings page, then choose them under Contacts on an email destination.
- Permissions -
alert_contacts.readto see contacts andalert_contacts.updateto add, edit and delete them. The built-in Alert Manager and Administrator roles hold both; Observer and Auditor hold read. A custom role can hold either. Anyone who can read contacts sees the section, also while it is empty (No alert contacts yet. An administrator adds them here.). - Scope - a contact belongs to one organization or to the Entire workspace (all organizations). A workspace contact can be chosen on any email destination; an organization's contact only on that organization's destinations. The scope is set when the contact is created and cannot be changed afterwards; delete the contact and add it again instead.
- Deleting a contact stops every destination that lists it from sending to it.
An address that used its unsubscribe link is marked unsubscribed in the list and on the destination's contact picker. Contacts cannot yet be chosen on scheduled reports; a report's recipients are still typed in, and an unsubscribed address is skipped there too.
Unsubscribe links¶
Every alert and scheduled-report email has a per-recipient line in its footer
and in the plain-text part: Sent to <address>. Unsubscribe from these
emails. The message also carries the List-Unsubscribe and
List-Unsubscribe-Post headers, so mail clients that support RFC 8058
one-click unsubscribe offer their own button.
- Opening the link shows a confirmation page (Unsubscribe from CertIntel email); nothing changes until the recipient chooses Unsubscribe. The same link later offers Subscribe again.
- An unsubscribe applies to that address across the whole workspace: it stops every alert and scheduled-report email from the workspace to it, whichever destination, contact entry or report named it. An administrator cannot override it; only the recipient can subscribe again, from the same link.
- The pages are reachable from anywhere, including a workspace with an IP allowlist.
- Unsubscribing and subscribing again are recorded in the activity log
(
email.unsubscribed,email.resubscribed). Each skipped send to an unsubscribed address is recorded asalert.recipient_suppressed; it is not a delivery failure.
The links need the platform's public address (CERTINTEL_PUBLIC_BASE_URL).
On a deployment without one, the footer says To stop these emails, ask your
CertIntel administrator. and no unsubscribe headers are sent.
Generic webhook JSON¶
The JSON schema is the easiest shape to consume from automation platforms,
functions and ticketing systems. Each version keeps every field of the one
before it; version 4 adds the labelled fields shown above (destination,
type, organization_label, tenant_wide, description, links):
{
"product": "CertIntel",
"schema_version": 4,
"kind": "digest",
"organization": "Production",
"tier": "critical",
"severity_label": "Critical",
"title": "Expiring soon: api.acme.example (expires 2026-10-21) ā CertIntel alert ā Production [critical]",
"headline": "šØ Critical alert ā 1 certificate(s) expiring soon ā Production",
"summary": "*Critical* ā 1 certificate(s) expiring soon:\n⢠api.acme.example (expires 2026-10-21)",
"destination": "Ops Slack",
"type": "New findings Ā· Critical",
"organization_label": "Production",
"tenant_wide": false,
"description": "New or changed in Production since this destination was last told, in the categories it subscribes to: 1 certificate(s) expiring soon. Each finding is listed below. It is not sent again on its own: while it stays open, the daily summary lists it.",
"links": [
{"label": "1 certificate(s) expiring soon", "url": "https://app.certin.tel/certificates?attention=1&tier=critical"},
{"label": "Alert Settings", "url": "https://app.certin.tel/alerts"}
],
"generated_at": "2026-10-18T14:30:00+00:00",
"item_count": 1,
"sections": [
{"key": "expiring_critical", "severity": "critical",
"heading": "1 certificate(s) expiring soon", "count": 1, "total": 1,
"url": "https://app.certin.tel/certificates?attention=1&tier=critical",
"items": ["api.acme.example (expires 2026-10-21)"],
"entries": [{"text": "api.acme.example (expires 2026-10-21)",
"url": "https://app.certin.tel/certificates?detail=ā¦"}]}
],
"expiring_critical": ["api.acme.example (expires 2026-10-21)"],
"expiring_warning": [], "expired": [], "revoked": [], "discovered": [],
"unreachable": [], "cert_invalid": [], "crl_critical": [], "crl_warning": [],
"served_mismatch": [], "agents_silent": [], "ct_new_name_sets": [],
"link": "https://app.certin.tel/alerts",
"digest_type": "new_findings",
"still_open": 3,
"delivery_id": "digest:ā¦"
}
A scheduled message says which of the two it is in digest_type, still within
schema version 4:
digest_type |
Lists | Extra field |
|---|---|---|
new_findings |
Only the findings that are new or changed for this destination. | still_open: how many findings it was already sent are still open and not listed. |
daily_summary |
Everything still open. | new_count: how many of the listed findings are new since the last message; their lines start with New:. |
A digest sent with Send digest now carries "on_request": true instead
and none of these three keys; it lists everything open.
kind is digest (an alert with findings, a daily summary or a digest sent
on request), event or test. A queued event (renewal.success,
renewal.failure, deployment.window_override, auth.warning,
agent.late, the Private CA rotation events) also carries
event, event_id, organization_id and a one-line summary, with a single
section holding that summary. The section keys of findings are expiring_critical,
expiring_warning, expired, revoked, discovered, unreachable,
cert_invalid, crl_critical, crl_warning, served_mismatch,
agents_silent and ct_new_name_sets; a queued event uses the event name.
The same keys appear as flat top-level lists (empty when the destination does
not subscribe to that category or nothing matched).
Two queued events carry an extra object, still within schema version 4:
renewal.failurefor an Agent installation failure carriesfailure_output- the step that failed and the redacted end of its output (see Failed step output):
"failure_output": {
"step_id": "reload-nginx",
"action": "process.execute",
"exit_code": 1,
"stdout_tail": "Testing nginx configuration...\n",
"stderr_tail": "nginx: [emerg] cannot load certificate key ... (password: [redacted])\n",
"truncated": false,
"redacted": true
}
deployment.window_overridecarriesdeployment_window_override-reason(expires_before_window),window_opens_at,certificate_expires_atandmargin_hours.
The two Private CA rotation events carry private_ca - id, label,
successor_ca_id and predecessor_ca_id - on a platform build that offers
rotation.
Two more fields, within the same schema version: a renewal.failure whose
failed step printed nothing carries failure_error, the step's error (at most
its last 2,000 characters), a renewal.failure carries error_first_line (the
first line of the error, at most 200 characters) and what_to_do (at most 1,500)
while the renewal still records the failure, and next_attempt (the Next
attempt line as text) when the Agent reported what it does next, and a renewal.success that follows a failure of
the same renewal carries recovered - deployment after an installation
failure, renewal after another failure (see Events). A
renewal.success of a certificate's first issuance carries
first_issuance: true, and an agent.late message saying the Agent reports
again carries recovered: "agent".
Receivers that ignore unknown keys need no change.
A destination must be an HTTPS URL without embedded credentials or a fragment
(Use an HTTPS webhook URL without user credentials or a fragment.). At
delivery time the host must resolve to a public address: private, loopback,
link-local and carrier-grade NAT ranges (including 100.64.0.0/10, used by
Tailscale) fail with Last error: BlockedTargetError on the destination's
row.
Events¶
Each destination subscribes to one or more of eighteen event types (sixteen on platform builds without Private CA rotation). The Alert Settings form groups them as shown; a new destination starts with the twelve marked default selected:
| Group | Event | Fires on |
|---|---|---|
| Certificates | certificate.expiry (default) |
A certificate inside the critical expiry window |
| Certificates | certificate.expiry_warning (default) |
A certificate inside the warning expiry window |
| Certificates | certificate.expired (default) |
An expired certificate still in the inventory |
| Certificates | certificate.revoked (default) |
A revoked certificate still in the inventory |
| Certificates | certificate.discovered |
A certificate first seen since the destination's previous alert or daily summary |
| Public endpoints | monitor.failure (default) |
A public endpoint unreachable or failing TLS on two probes in a row (see Failed probes are retried within minutes) |
| Public endpoints | monitor.cert_invalid (default) |
A public endpoint presenting an invalid certificate (expired, revoked, untrusted chain, hostname mismatch, self-signed) |
| Public endpoints | monitor.served_mismatch (default) |
Public or internal endpoint still serving an old certificate: a public or internal endpoint linked to a managed certificate that still serves an older certificate after the grace period (see Served versus issued). A paused internal endpoint is not alerted on. |
| CRL distribution points | crl.expiry |
A monitored CRL distribution point whose published CRL is overdue or nearly due for its next update, or could not be read |
| Agents | agent.silent |
Agents that stopped reporting: an Agent that is offline, with no report for 24 hours (see the Agents page). At 5 days offline it is alerted once more: its line says so and the message is critical. |
| Agents | agent.late |
Agents that are late (two missed hourly reports), and when they report again: an Agent that sends hourly reports and has sent none for 2 hours 15 minutes, once per outage and before it counts as offline (Agent late: web01), and Agent reporting again when it reports, only to the destinations that were told it was late |
| ACME renewals | renewal.success |
A successful ACME renewal |
| ACME renewals | renewal.failure (default) |
Failed ACME renewals: a failed ACME renewal, including an Agent installation failure, sent with the type Installation failed and its failed step output |
| ACME renewals | deployment.window_override (default) |
Deployment window overridden: an Agent installed a renewed certificate outside its deployment window because the installed certificate would otherwise expire first |
| Certificate Transparency | ct.new_name_set (default) |
New name set in Certificate Transparency: a set of names never seen before for a watched domain, on a certificate CertIntel neither issued nor holds (see CT Log Watch) |
| Private CA | private_ca.rotated (default) |
Private CA rotated: a successor issuing CA now issues new certificates; the previous CA keeps issuing and publishing its CRL until it expires (see Rotation) |
| Private CA | private_ca.rotation_awaiting_signature (default) |
Private CA rotation awaiting signature: a subordinate CA is due for rotation and its successor's CSR waits to be signed by your root |
| Security | auth.warning |
Failed sign-ins and other security warnings; workspace-wide destinations only |
The events under ACME renewals, Private CA and Security, and
agent.late, are queued and sent as they happen. Every other event is a
finding category: each finding is sent once when it happens and then
listed in the daily summary while it stays open (see
When findings are sent). Findings are evaluated from the
current state, so one that has been fixed - an endpoint that now serves
the renewed certificate, for example - is simply absent from the next message.
auth.warning concerns the whole workspace (failed sign-ins and refused
requests are recorded before or without an organization), so only a
destination for the Entire workspace (all organizations) receives it. An
organization's destination refuses it with Failed sign-ins and security
warnings (auth.warning) concern the whole workspace and go only to a
destination for the entire workspace. Leave them out here, or add a
workspace-wide destination.; one saved with it earlier keeps saving, with
that event dropped (unless it was its only event).
An existing destination keeps exactly the events it subscribed to; tick an
event on it to receive it. ct.new_name_set is sent only for
organizations whose plan includes Certificate Transparency monitoring.
An Agent installation failure is reported as a failed renewal event, so it can
reach a destination subscribed to renewal.failure. Every installation
failure after issuance is headed Installation failed (subject, title, type
and the chat and push headlines), with or without the failed step's output;
without it the description says the CA issued the certificate, installing it
or the check after it failed, and the Agent retries the installation. ACME
renewal failed is used only when the certificate was not issued. When a later attempt of
the same renewal succeeds - the Agent retries under the same run - a
destination that was sent the failure alert is told, headed
Installation succeeded after an earlier failure (after an Installation
failed alert) or Renewal succeeded after an earlier failure,
with a description that says the earlier alert needs nothing more. A
destination that was not sent the failure alert gets the plain success when it
subscribes to renewal.success, and nothing when it subscribes to failures
only.
The Installation failed alert of a certificate's first installation (no earlier certificate replaced, no earlier success of that renewal) waits 15 minutes and is sent only if the renewal still records the failure then: the Agent checks a new certificate's installation again every 30 seconds for about 15 minutes, so a server pointed at the files in that time sends neither the failure nor a recovery. It is one held alert per certificate and hold window: a failure that changes within those 15 minutes (the server stopped for a moment, then the first error again) adds no alert, and the one alert carries the latest failure when it is sent. After the window, a different failure is alerted on its own again. The success or recovery of a certificate's first issuance says it was issued and installed, not renewed.
agent.late is not selected by default. It warns earlier than
agent.silent: once per outage, when an Agent that sends hourly reports has
missed two (no report for 2 hours 15 minutes, when the
Agents page says Late), with
what to check on the device and a link to the Agent's details, and once more,
Agent reporting again, when it reports. Disabled, unregistered or
unapproved Agents, paused or removed devices and Agents without hourly
reports are never late.
A revoked certificate's line under certificate.revoked gives the
date, the reason given to the CA and who asked on which Agent (as the Agent
reported them), and the next step: replace it: on the agent host run
certintel certificates issue ID; if it is no longer needed, remove it from
the agent's configuration (with a new key after a key compromise). For a
certificate no Agent manages it says to replace it on the server that uses
it.
agent.silent is selected by default on a new destination, and agent.late
stays optional. While no enabled destination
subscribes to it, Alert Settings and the Overview (its Agent reporting
card, and Needs attention while an Agent is late or offline) say No alert
destination subscribes to "Agents that stopped reporting", so nobody is told
when an agent stops reporting. (or No alert destination exists yet, ā¦),
with Add a destination for it - /alerts?add=agent.silent opens the new
destination form with that event ticked - or, for a role that cannot add one,
An administrator can add it on Alert Settings. CA certificates on an
effective ignore list are excluded from expiry alerts; only
CA certificates can be ignored, so acknowledge a site certificate instead.
Acknowledging a certificate or a failed renewal also suppresses its attention
item without changing its recorded result.
Failed probes are retried within minutes¶
A public endpoint whose probe fails (unreachable, a reset, a timeout) is
probed again after 2 minutes, then 4, 8 and so on, never later than the
endpoint's own check interval (nor 6 hours). monitor.failure needs two
failures in a row, so the failure that alerts comes about 2 minutes after the
first one, and a recovered endpoint is seen as soon as a retry succeeds.
Until the retry decides, an endpoint that was already serving an invalid
certificate stays an open finding with the invalid status of its last
successful check.
Expiry findings use each certificate's owning organization thresholds, including short-lifetime scaling. Tenant-wide destinations can therefore contain items evaluated under different organization settings. Endpoint findings also include recorded chain trust, expiry, and hostname validation failures; a successful probe is not automatically a valid certificate. See expiry severity.
Failed step output¶
When an installation step of an Agent workflow fails, the
Agent reports which step failed, its action, its exit code and the end of its
output. The platform shows it in a Failed step output section of the
renewal's detail, open by default on a failure, and adds it to the
renewal.failure alert:
- What is captured - the last 8 KiB of standard output and of standard
error for a
process.executestep; the combined output of a Linuxhook.runscript (reported as standard output); and the combined output of a legacy plan's installation program. Output that was cut is marked as truncated. - Redaction - before the output leaves the device, the Agent replaces
every secret it knows of with
[redacted]: workflow secrets, protected step inputs (including passwords and environment values), the platform API key, EAB keys, DNS delegation secrets and legacy archive passwords, each also in its base64 forms, followed by patterns that look like credentials. The platform also strips control characters other than newline and tab. - Redaction is best effort. A program that encodes, splits or otherwise
transforms a secret before printing it is not caught, and values shorter
than four bytes are not replaced. Keep scripts from printing secrets,
and turn reporting off where output may still contain them: set
report_step_outputtofalsefor the whole Agent or for one workflow (see Reporting failed step output). The step, action and exit code are still reported. - A step that printed nothing - a TCP or endpoint check, for example - is
not shown as an empty block: the description says The failed step printed
nothing; its error is below., the output block reads The step printed
nothing (or this agent is set not to report step output)., and the step's
error follows (Pushover shows it in place of standard error; the generic
webhook adds
failure_error). The exit code stays in the heading when the step has one.
Each destination shows the end of each stream, with a leading ⦠when it is
shortened:
| Destination | Shown |
|---|---|
| Generic webhook | The whole failure_output object (up to 8,192 characters per stream) |
| The last 4,000 characters of each stream | |
| Slack | The last 2,800 characters, both streams in one block |
| Microsoft Teams | The last 4,000 characters, both streams in one block |
| Discord | The last 1,000 characters of each stream, one field each |
| ntfy | The last 2,000 characters, both streams in one block |
| Pushover | The last 300 characters of standard error, only if the message has room |
An Agent installation failure is sent as renewal.failure with the type
Installation failed and the summary Installation failed after issuance: <name>:
the CA issued the certificate, a deployment step on the host failed, so the new
certificate is not in use yet, and the Agent keeps it and retries the
deployment. Other ACME clients and failures before installation
report no step output; their alerts say ACME renewal failed.
When findings are sent¶
A finding is something that is wrong now: a certificate close to expiry, expired or revoked, a newly discovered certificate, a public endpoint that fails or serves an invalid certificate, an endpoint still serving an old certificate, a CRL next-update problem, an offline Agent, a new Certificate Transparency name set. CertIntel checks every destination's findings every 5 minutes by default (select the destination's name on Alert Settings for the actual frequency) and sends two kinds of message: once when it happens, then the daily summary.
- An alert, once. Each finding is sent once, when it is new or has changed. The alert lists only what is new for the destination, each item with its link, and says how many other findings are still open.
- At most one alert per alert interval. Each destination has an Alert
interval (seconds) (300 seconds to 30 days, default 3600; the API field is
min_interval_seconds), counted from the destination's last alert. Findings that turn up together arrive together, so a flapping monitor does not become a flood of notifications. - The daily summary. Everything still open is listed in one daily summary, 24 hours after the previous one, so it keeps its time of day. The first one follows 24 hours after the alert that listed everything open. The alert interval does not hold a summary back.
- New shortly before a summary. A finding that turns up in the hour before a summary is due is sent in that summary, marked New, instead of in an alert of its own.
- Nothing open, nothing sent. A finding that goes away is not announced. If it comes back, it is alerted again.
- A changed finding is alerted once more: a certificate moving from the warning window to the critical one and from there to expired, an endpoint's new outage after it had recovered, a CRL's next publication, an Agent reaching 5 days offline.
- Each destination has its own record of what it was sent. A new destination is told at once what is open for it. Subscribing a destination to another category alerts what is open in that category; unsubscribing forgets it.
- A failed delivery is retried after 15 minutes and records nothing: the same findings are still new at the retry.
Renewal, deployment-window and sign-in (security) events are sent as they occur. They are not findings and are not held back by the alert interval. The form for a destination on Alert Settings states the same rule.
Delivery status¶
Alert Settings lists the destinations, one line each: name, type, scope,
status, how many notification types it sends, the next message and the last
delivery. Edit is on the line and the other actions are under āÆ. Under
its name a destination shows where it sends: the URL's scheme, host, a port
other than the default, and path, with ids, tokens and other long or
secret-looking path segments shown as ā¦; the query string, fragment and any
user part are never shown (a query string appears as ?ā¦). The API's
url_hint is the same.
Select a destination's name to open what it does next and what it did last:
- Findings - Each is sent once when it is new or changed, at most one alert every ā¦; checked every ā¦. What stays open is listed in a daily summary. (or None for a destination that receives only events sent as they happen).
- Next message - which message is next and when: An alert with what is new, or The daily summary when nothing is new for the destination. It will contain lists the findings it would carry now; under an alert it also says how many findings already sent are still open and which daily summary lists them. With nothing open it reads Nothing due: nothing is open, so no alert or summary is sent with the next check and First expected: the first expiry alert due by the organization's thresholds, in one sentence with the date and one number, for example A warning on 2027-01-12 16:50 UTC, when 21 full days are left on api.example.com. (A critical alert on ā¦; An alert on ā¦, when ⦠expires; for a short-lived certificate when 60% of its lifetime (6 days) is left). For a certificate whose Agent plans its renewal it says web.example.com renews by itself on 2026-12-18 16:55 UTC; you are warned only if it has not renewed by 2026-12-19 16:55 UTC. The preview and the Nothing is due answer of Send digest now use the same sentence. A paused destination shows none.
- Last delivery - the time, the kind (New findings, Daily summary, Event or Test message) and the result, and Recent deliveries - the last five with their items and, for a failure, the hint. A digest sent with Send digest now is listed as Digest (sent on request).
- Last error with the failure class after a failed attempt, so you can tell a genuinely broken webhook URL from a destination that simply hasn't fired yet.
Preview digest shows the next message the destination would receive - an alert with what is new for it, or its daily summary - with the headline, fields, links and findings, and the webhook JSON or the plain text, without sending or recording anything. It says when that message goes out, and under an alert how many findings already sent are still open and when the daily summary that lists them is due. It and the next-message content under a destination's name need permission to read certificates in the destination's scope.
Send test sends a sample message to check that the destination receives messages at all; it is not a real alert. Its sample certificate is dated five days ahead and marked as such (example.certin.tel (expires ā¦) ā a sample for this test, not a real certificate), and its section is headed Sample: ⦠with no link to the certificate list, in every format (also the generic JSON's section); the message still links to Alert Settings. The answer names the destination: Test message delivered to Ops email. It is a sample, not a real alert: ⦠or Test message not delivered to Ops email (ā¦). with the failure class and its hint. A test updates Last success or Last error but not the schedule: the next alert and the daily summary still go out as the destination's row shows.
Every row has the same actions, so each also carries the destination's name for screen readers and text-based tools - Send test to Ops email, Preview digest for Ops email, Delete Ops email and so on - while the visible label stays the same. The delete confirmation and the digest preview's Send digest now name the destination too, and the alert contacts' Edit and Delete name the contact.
Send digest now, under ⯠on the destination's row and on the preview,
sends the destination
everything that is open for it at once.
It is a real alert, labelled sent on request in its title, headline, type
and description (and "on_request": true in the
CertIntel JSON). It changes neither the schedule nor
the record of what the destination was sent: the next alert and the daily
summary still go out as the destination's row shows, and a finding that was
not alerted yet
is still alerted. When nothing is open, nothing is sent and the answer
says so, followed by the first expected alert when there is one. It needs notifications.test and permission to read
certificates (certificates.read) across the destination's whole scope, is
refused for a paused destination, has the same limits as Send test (see
below), and is recorded in Recent deliveries and in the activity log
(alert_channel.digest_now). Through the API it is
POST /api/v1/notification-channels/destinations/{id}/send-digest.
Background Jobs lists what the platform did for your workspace in the background (endpoint checks, CT lookups, scheduled report deliveries, alerts sent as an event happens, emails). Alerts with findings, daily summaries and test messages are not listed there; select a destination's name on Alert Settings for its recent deliveries.
Limits on sends and checks started by hand¶
Actions that make CertIntel send or probe something on demand are limited per
object and per person (or API key). Over the limit the dashboard says so and
the API answers 429 with Retry-After:
| Action | Limit |
|---|---|
| Send test on a destination | 3 per destination and 10 per person, per minute (Too many test messages for this destination: try again in N seconds.) |
| Send digest now on a destination | 3 per destination and 10 per person, per minute (Too many digests sent on request to this destination: ā¦) |
| Send now and Re-send of a scheduled report | 3 per report and 10 per person, per hour (Too many sends of this report: ā¦) |
Check on a public endpoint (POST /api/v1/targets/{id}/check) |
3 per endpoint and 30 per person, per minute (Too many checks of this endpoint: ā¦) |
The answer names the limit that refused the request. Your own limit is counted first: when it is spent the answer reads You have sent too many test messages (at most 10 per minute, all together): try again in N seconds. (You have sent too many reports by hand (at most 10 per hour, all together) for reports, You have started too many checks (at most 30 per minute, all together) for endpoints), and the destination, report or endpoint keeps its own allowance for everyone else. When the object's limit refuses, the answer uses the texts in the table and the attempt does not count against your own limit, since nothing was sent.
Changing a destination through the API¶
PUT and PATCH /api/v1/notification-channels/destinations/{id} change only
what they send: fields left out keep their values, config is merged key by
key, and the write-only URL and secret settings, left out or sent empty, keep
the stored ones (the dashboard form works the same way). Changing a
destination's kind starts from an empty URL, format and settings, so send
the new kind's URL and secrets with it. The merged result is validated as a
whole; a 422 names the field, never its value.
Delivery is at least once. A logical delivery keeps the same ID on retry;
generic HTTPS webhooks receive it in the Idempotency-Key header and the
delivery_id payload field. A queued event's delivery ID is
event:<destination>:<event>:<id>, so a renewal that failed and then succeeded
sends two events with two IDs. A failure that differs from the one before it
in the same renewal run - another step, other step output or another error,
such as a deployment failure after a DNS-01 failure - is alerted again as
renewal.failure with its own ID,
event:<destination>:renewal.failure:<id>:<occurrence>; the same failure
reported again by the Agent's retries is not alerted again. Store that ID in your receiver and acknowledge a
duplicate without repeating its side effect. A network interruption or worker
restart after the receiver accepts a request can cause another attempt; a
successful remote request is not an exactly-once guarantee.
Your receiver should answer quickly with a small body: CertIntel reads at most 64 KiB of the response and gives up at the configured timeout, recording the delivery as failed. Pushover responses must be JSON.
Scheduled reports¶
Alerts tell you about a change as it happens. Scheduled reports are the periodic overview: an email that summarises the inventory for one organization or the entire workspace, generated daily, weekly or monthly. Manage them on Settings ā Scheduled Reports (the Alert Settings page links there). The feature shares the alert-destinations plan entitlement, so a plan without alert destinations shows Scheduled reports are not included in this subscription.
A report has:
- Scope - one organization, or Entire workspace (all organizations) for a
tenant-wide holder of
scheduled_reports.create. - Recipients - 1 to 20 email addresses.
- Frequency - Daily, Weekly (with a day of week) or Monthly (day of month 1-28), plus Hour (UTC); the default is weekly on Monday at 07:00 UTC.
- Sections - any of Inventory summary, Expiring, expired and revoked certificates, ACME renewals since the last report, Certificates discovered since the last report, Public endpoint health, CRL distribution points, Agent reporting status, Alert delivery since the last report, Certificate Transparency findings since the last report and Full list of current certificates (at least one).
The Certificate Transparency section counts the name sets first seen since the last report - new, issued by CertIntel, and already in the inventory - and lists the new ones with a link to each finding. It covers only organizations whose plan includes Certificate Transparency monitoring; see CT Log Watch.
"Since the last report" sections cover the period from the previous successful send (or one period back for the first run). Send now generates and sends a report immediately; every generated report is stored and listed under Generated reports, where Re-send delivers the stored copy to the recipients it was generated for. A send that fails is retried every 15 minutes, up to three attempts in total. Stored copies are kept for 400 days by default (a platform setting). Report emails use the same branded layout as alert emails and end with a link back to Scheduled Reports. Like alert emails, they go out one message per recipient with an unsubscribe link, and an address that unsubscribed is skipped.
Permissions are scheduled_reports.read / .create / .update / .delete /
.run (run covers Send now and Re-send); the built-in Alert Manager
role holds all five, and custom roles can hold any subset. The same operations
are available under /api/v1/scheduled-reports (see the
API overview).
Security note¶
A webhook URL is a secret in its own right - anyone who has it can potentially see that your certificates are about to expire, or (for some destination kinds) receive messages formatted to look like they came from your CertIntel deployment. Treat a destination URL with the same care as an API key.