Skip to content

Alerts & Notifications

Configure email and webhook notifications to stay informed about expiring credentials, failed operations, and security events.


Overview

CertifyClouds alerts keep your team notified:

  • Multiple channels: Email, Slack, Microsoft Teams, PagerDuty, custom webhooks
  • 8 consolidated alert types covering expiry, rotation, sync, credential status, and operational events
  • Source and Status scoping: One rule per concern, refined with optional filters
  • Delivery modes: Realtime (on trigger) or scheduled digest
  • Flexible scheduling: Configure when digests are sent
  • Subscription filtering: Scope alert rules to specific Azure subscriptions (via the API)

Alert Types

CertifyClouds has 8 alert types. The multi-variant ones (expiry, rotation, sync, credential_status) cover all their sub-cases with one type; optional Source and Status scopes narrow a rule instead of separate types.

Alert Type Trigger
expiry A credential is expiring within the rule's threshold, or has already expired
rotation A rotation run completed or failed
credential_status A managed credential was orphaned or adopted
sync A sync operation completed, failed, hit a conflict, or has source lag
scan_completed Discovery scan finished
discovery_completed Rotation discovery finished
vault_error Error accessing a Key Vault
worker_stale A background worker stopped heartbeating

Source scope (expiry only)

An expiry rule covers all credential sources by default; the Source select narrows it to one:

Source Covers Tier
All sources Everything below Any
Key Vault secrets Key Vault secrets, certificates, and keys STARTER+
App Registration credentials App Registration secrets and certificates STARTER+
B2C credentials B2C tenant app credentials PRO
Service credentials CertifyClouds' own managed credentials PRO

On STARTER, B2C and Service rows are never evaluated, even by an "All sources" rule.

Status scope

expiry, rotation, sync, and credential_status rules accept an optional Scope that narrows which sub-statuses fire. Default is all.

Alert Type Scope values
expiry Expiring only, Expired only
rotation Completed only, Failed only
sync Completed, Failed, Conflict, Source lag
credential_status Orphaned only, Adopted only

For example, a failure-only rotation rule is rotation with Scope = Failed only; there is no separate rotation_failed type.

Upgrading from pre-1.6.2

Releases before 1.6.2 had 17 standalone alert types (secret_expiring, rotation_failed, b2c_credentials_expiring, ...). Existing rules are migrated automatically at upgrade: each old type becomes the matching new type plus Source/Status scopes, preserving exactly what the rule fired on. Alert history rows written before the upgrade keep their original type names.

When expiry alerts fire

Expiry rules are evaluated by a time-driven daily monitor that checks the persisted inventory; no scan is required. Days-remaining is recomputed from the absolute expiry timestamp at evaluation time. Fresh discovery scans also trigger evaluation, so a scan surfaces newly expiring credentials immediately rather than waiting for the next daily tick.


Notification Channels

Email

Send alerts to individuals or distribution lists.

Configuration (Settings > Alerts):

  1. Click Create Alert Rule
  2. Select alert type (e.g., Credential Expiry)
  3. Enable Email delivery
  4. Enter recipient(s)
  5. Set threshold (for expiry rules)
  6. Save

Unified expiry email

Realtime and digest expiry emails render the same table: one Source column covering every credential source, grouped into Expired, Critical (inside the critical window), and Warning sections.

Owner-aware fan-out

For expiry, rotation, and credential-status alerts, credential owners recorded in CertifyClouds each receive a separate email containing only their own credentials. The rule's configured recipients still receive the full batch. Owner fan-out is email-only; webhooks always carry the full batch to the team channel.

SMTP Setup Required:

Configure email in your environment:

SMTP_HOST=mail.smtp2go.com
SMTP_PORT=2525
SMTP_USERNAME=<your-username>
SMTP_PASSWORD=<your-password>
SMTP_FROM_EMAIL=alerts@yourcompany.com
SENDGRID_API_KEY=<YOUR_SENDGRID_API_KEY>
SENDGRID_FROM_EMAIL=alerts@yourcompany.com

Slack

Post alerts to Slack channels using incoming webhooks.

Setup:

  1. In Slack, create an Incoming Webhook:
  2. Go to your Slack workspace settings
  3. Apps > Manage > Custom Integrations > Incoming Webhooks
  4. Create webhook and copy URL
  5. In CertifyClouds:
  6. Settings > Alerts > Add Rule
  7. Select Webhook delivery
  8. Choose type: Slack
  9. Paste webhook URL
  10. Save

Payload Format:

{
  "attachments": [
    {
      "color": "#EF4444",
      "title": "Credential Expiry Alert",
      "text": "Found 3 credentials expiring within 30 days",
      "footer": "CertifyClouds",
      "fields": [
        {"title": "Vault", "value": "kv-production", "short": true},
        {"title": "Items", "value": "api-key, db-password", "short": true}
      ]
    }
  ]
}

Microsoft Teams

Post to Teams channels using Incoming Webhooks.

Setup:

  1. In Teams, create an Incoming Webhook:
  2. Go to channel settings > Connectors
  3. Add Incoming Webhook
  4. Copy webhook URL
  5. In CertifyClouds:
  6. Settings > Alerts > Add Rule
  7. Select Webhook delivery
  8. Choose type: Teams
  9. Paste webhook URL
  10. Save

Payload Format:

{
  "@type": "MessageCard",
  "@context": "https://schema.org/extensions",
  "themeColor": "EF4444",
  "title": "Credential Expiry Alert",
  "text": "Found 3 credentials expiring within 30 days",
  "sections": [
    {
      "facts": [
        {"name": "Vault", "value": "kv-production"},
        {"name": "Items", "value": "api-key, db-password"}
      ]
    }
  ]
}

Generic Webhook

For custom integrations not covered by Slack / Teams / PagerDuty.

Payload Format:

{
  "title": "Credential Expiry Alert",
  "message": "Found 3 credentials expiring within 30 days",
  "color": "#EF4444",
  "timestamp": "2026-05-20T12:00:00+00:00",
  "source": "CertifyClouds",
  "fields": [
    {"title": "Vault", "value": "kv-production"},
    {"title": "Items", "value": "api-key, db-password"}
  ]
}

For Slack and Microsoft Teams payload shapes see Webhook Delivery.

PagerDuty

Page on-call directly via the PagerDuty Events API v2. CertifyClouds posts to https://events.pagerduty.com/v2/enqueue (hardcoded server-side); the per-service Integration Key is the credential.

Setup

  1. In PagerDuty: Services → Service Directory → New Service → "Events API v2" integration. Name it "CertifyClouds".
  2. Copy the 32-character Integration Key.
  3. In CertifyClouds: Settings → Alerts → New Rule → Webhook → Type: PagerDuty, paste the Integration Key in the "Routing Key" field.
  4. Click Test webhook. A test incident appears in PagerDuty.

Per-item incidents for expiry alerts

Expiry alerts page one PagerDuty event per credential, not one per batch. Each credential gets its own incident with its own trigger/resolve lifecycle, keyed on a stable per-credential dedup key, so repeated alerts about the same credential collapse into one incident instead of flooding the on-call. Email, Slack, Teams, and generic webhooks keep a single batched message; only PagerDuty splits per item.

Severity mapping

Expiry severity is computed per credential:

Expiry state PagerDuty severity
Already expired critical
Inside the critical window (default 7 days) error
Otherwise (expiring within threshold) warning

Other alert types page per batch:

Event PagerDuty severity
rotation failed error
sync failed error
sync conflict / source lag warning
credential_status orphaned error
credential_status adopted warning
vault_error, worker_stale error

Auto-resolve

When a previously-paged credential is positively healthy in a fresh live scan (rotated or its expiry pushed beyond the rule's threshold), CertifyClouds sends event_action: resolve with the same dedup key, closing the PagerDuty incident automatically. Auto-resolve is PagerDuty-only and applies to realtime rules.

Routine completion events filtered

Successful rotations and syncs, scan_completed, and discovery_completed are not forwarded to PagerDuty by design - PagerDuty is for paging, not log stream. Use email / Slack / Teams for routine confirmations.

Dedup key

For expiry alerts the dedup key is the canonical per-credential identity (source + resource + credential), so each credential maps to exactly one incident across triggers and resolves. Other alert types derive a stable batch key (cc:<alert_type>:<affected items>) so repeated alerts about the same resource set collapse into one incident.

Networking requirement

CertifyClouds must reach events.pagerduty.com:443 outbound. If your deployment sits behind an egress proxy or in an air-gapped network, this hostname must be allow-listed; CertifyClouds does not currently support proxy-routed PagerDuty delivery.

Payload sent (one per credential for expiry alerts)

{
  "routing_key": "<your-integration-key>",
  "event_action": "trigger",
  "dedup_key": "kv:<subscription-id>/kv-prod/client-secret/secret",
  "client": "CertifyClouds",
  "payload": {
    "summary": "Key Vault: client-secret expired",
    "source": "CertifyClouds",
    "severity": "critical",
    "timestamp": "2026-05-20T15:00:00+00:00",
    "component": "expiry",
    "custom_details": {
      "message": "kv-prod / client-secret (secret) expired.",
      "alert_type": "expiry",
      "fields": [
        {"name": "Source", "value": "Key Vault"},
        {"name": "Resource", "value": "kv-prod"},
        {"name": "Credential", "value": "client-secret"}
      ]
    }
  }
}

Delivery Modes

Each rule delivers in exactly one mode: Realtime or Digest.

Realtime

Alerts sent when the triggering event is evaluated.

Best for:

  • Critical alerts (expired credentials)
  • Rotation failures
  • Security events

Digest

Alerts batched and sent on a schedule.

Best for:

  • Warning-level alerts (expiring soon)
  • Reducing notification fatigue
  • Non-urgent monitoring

Only expiry, rotation, and credential_status rules can use digest delivery. The remaining types are realtime-only; the UI hides the digest option and the API rejects it for them.


Scheduling

Digest Schedule

Configure when digest emails are sent:

Schedule Description
Daily 8:00 AM Once per day
Daily 9:00 AM + 5:00 PM Twice per day
Weekly Monday 9:00 AM Weekly summary

Configure Schedule

  1. Go to Settings > Alerts
  2. Click Digest Settings
  3. Select timezone; it defaults to your browser's local zone. Dropdown includes UTC, Europe/London, America/New_York, America/Chicago, America/Denver, America/Los_Angeles, Asia/Tokyo, Asia/Singapore, Australia/Sydney.
  4. Set delivery times

Timezone + DST handling

Digest schedules are stored alongside their IANA timezone (e.g. Europe/London, America/New_York). The scheduler handles Daylight Saving Time transitions automatically: a rule scheduled for 09:00 Europe/London fires at 08:00 UTC during BST (summer) and 09:00 UTC during GMT (winter) with no re-edit needed when clocks change.

Upgrading existing UTC-only rules

Rules created before timezone-aware scheduling are stored with the zone set to UTC so their original fire moment is preserved exactly (no behaviour change at upgrade time).

If you want one of those rules to follow your local timezone going forward (so DST is handled automatically), you must do both steps when you edit it:

  1. Re-enter the time as your desired local time (e.g. 09:00 to mean "9 AM my local time").
  2. Change the timezone dropdown from UTC to your real IANA zone (e.g. Europe/London).

Don't change the timezone without re-entering the time

Changing only the timezone dropdown re-interprets the stored time as local, which silently shifts the fire moment by your UTC offset. Example: a rule that was firing at 09:00 UTC (= 10:00 London time in summer) becomes a rule that fires at 09:00 London time (= 08:00 UTC). That's a 2-hour shift, easy to miss.

Always re-enter the picker time alongside the timezone change.

  1. Save

Creating Alert Rules

Step-by-Step

  1. Navigate: Settings > Alerts
  2. Create: Click "Create Alert Rule"
  3. Configure:
  4. Alert Name: Descriptive rule name
  5. Type: One of the 8 alert types
  6. Source (expiry only): All sources, Key Vault secrets, App Registration credentials, B2C credentials (PRO), or Service credentials (PRO)
  7. Scope (expiry, rotation, sync, credential_status): sub-status filter, defaults to all
  8. Alert X days before expiry (expiry only): 1-365, default 30
  9. Delivery Mode: Realtime Only or Digest Only (digest-eligible types only)
  10. Digest Schedule (digest rules): time, frequency, timezone
  11. Email: enable and enter recipient(s)
  12. Webhook: enable, choose Slack / Teams / Generic / PagerDuty, and enter the URL (or Integration Key for PagerDuty)
  13. Save: Enable and save the rule

Example Rules

Critical: Expired Key Vault assets (realtime)

  • Type: expiry
  • Source: Key Vault secrets
  • Scope: Expired only
  • Delivery: Email + Slack
  • Mode: Realtime
  • Recipients: security-team@company.com

Warning: Credentials expiring in 30 days (digest)

  • Type: expiry
  • Source: All sources
  • Threshold: 30 days
  • Delivery: Email
  • Mode: Digest (daily)
  • Recipients: ops-team@company.com

Info: Successful rotations (realtime)

  • Type: rotation
  • Scope: Completed only
  • Delivery: Teams webhook
  • Mode: Realtime

Testing Alerts

Test from the rule form

The rule create/edit form has a Send test message button for the configured webhook:

  1. Go to Settings > Alerts
  2. Open the rule (or start creating one) and configure the webhook
  3. Click Send test message
  4. Verify the notification arrived

Programmatic test

POST /api/alerts/test dispatches a test notification to the email recipients and/or webhook configuration supplied in the request body; no saved rule is needed. Admin-only and rate-limited. Request and response shapes are in your deployment's /docs.


Alert History

View all sent alerts:

  1. Go to Alerts tab
  2. Click History
  3. Filter by:
  4. Date range
  5. Alert type
  6. Delivery status

Statuses

Status Description
Delivered Successfully sent
Failed Delivery failed (check logs)
Pending In digest queue
Retrying Retry in progress

Retry Logic

Failed webhook deliveries are retried with exponential backoff. 2xx responses are treated as success; 4xx responses (except 408 / 429) are treated as permanent client errors and not retried; 5xx, 408, 429, timeouts, and connection errors are retried. Persistent failures eventually mark the alert as failed and surface in the rule's delivery history.

See Webhook Delivery for the receiver payload shapes.


Troubleshooting

Emails not received

  1. Check SMTP configuration in environment variables
  2. Verify recipient email address
  3. Check spam/junk folder
  4. Review application logs for errors

Webhook failures

  1. Verify webhook URL is correct
  2. Check if endpoint is accessible from CertifyClouds
  3. Ensure endpoint accepts POST requests
  4. Check for firewall/network restrictions

Duplicate notifications

  1. Check for overlapping rules (e.g. an "All sources" expiry rule alongside a source-scoped one)
  2. Review threshold settings
  3. Owners who are also rule recipients receive both the owner-scoped email and the full batch; this is by design

API access

Alert rules can be managed programmatically via /api/alerts/rules and delivery history queried via /api/alerts/history. The full endpoint catalogue is in API Endpoints; exact request and response shapes are in your deployment's /docs.


Best Practices

  1. Don't over-alert: Use digests for warnings, real-time for critical
  2. Route appropriately: Send security alerts to security team, ops alerts to ops
  3. Test regularly: Use the test button to verify delivery
  4. Monitor failures: Check alert history for delivery issues
  5. Use thresholds wisely: 30 days gives time to act without noise