How delivery works

ChannelImmediate alertsWeekly digest
Email, Slack, Microsoft Teams, webhooksCritical changesYes (skipped when nothing changed)
PagerDutyCritical and high changesNever
JiraCritical and high changes, one issue request per changeNo
  • Examples of critical changes: a certificate from a CA you have not authorised, a sensitive port opening, a new vulnerability on the CISA KEV catalog, removal of a registrar transfer lock.
  • On MSP plans a channel can be scoped to one client workspace.
  • Every confirmed channel has a Send test button, which delivers a sample high-importance change for test.example.com.
  • Delivery failures are recorded on the channel and shown in the app; they never block other channels.

Email

Each address must confirm through a link before anything is sent to it.

Slack

Create an incoming webhook for the channel and paste its https://hooks.slack.com/… URL.

Microsoft Teams

  1. In the Teams channel, open Workflows and choose the template Post to a channel when a webhook request is received.
  2. Finish the wizard and copy the HTTP POST URL it gives you. It will be on *.logic.azure.com, *.powerplatform.com or *.webhook.office.com.
  3. Add a Microsoft Teams channel in Attack Surface Scan and paste the URL.

Messages are Adaptive Cards (version 1.4) listing up to 20 changes, with a button that opens the app. Teams channels get critical alerts and the weekly digest, like Slack.

PagerDuty

  1. In PagerDuty, open the service, Integrations → Add integration → Events API V2.
  2. Copy the 32-character Integration Key (routing key).
  3. Add a PagerDuty channel in Attack Surface Scan and paste the key.

Critical and high changes trigger events immediately (up to 20 per delivery); the digest is never sent to PagerDuty. Critical maps to PagerDuty severity critical and high to error. Each event's dedup_key is afs- followed by 32 hex characters derived from the target, the change kind and its new value, so a repeat of the same change updates the open incident instead of paging again. Resolve events are not sent: resolve the incident in PagerDuty once the next scan confirms the fix.

Jira (via Jira Automation)

No Jira credentials are stored with us. Jira Automation receives a webhook and creates the issue on your side, with your project, issue type and fields. One request is sent per critical or high change.

  1. In Jira, Project settings → Automation → Create rule. Choose the trigger Incoming webhook with No issues from the webhook. Copy the webhook URL, and the secret if one is shown.
  2. Add the action Create issue. Set Summary to {{webhookData.summary}} and Description to {{webhookData.description}}.
  3. Under Additional fields, paste:
    {
      "fields": {
        "priority": { "name": "{{webhookData.priority}}" },
        "labels": {{webhookData.labels.asJsonStringArray}}
      }
    }
  4. Add a Jira channel in Attack Surface Scan and paste the URL (it starts with https://automation.atlassian.com/ or https://api-private.atlassian.com/automation/webhooks/), plus the secret if you have one. The secret is sent in the X-Automation-Webhook-Token header.

Atlassian changes the Automation UI and webhook URL format from time to time; check Atlassian's current documentation if a step does not match what you see.

Payload

{
  "summary": "Critical: Port 5432 (PostgreSQL) started answering on db.example.com",
  "description": "…",
  "priority": "Highest",
  "importance": "critical",
  "labels": ["attack-surface-scan", "port-opened"],
  "target": "db.example.com",
  "kind": "port.opened",
  "dedupKey": "afs-…",
  "changeId": "3f0c…",
  "scanId": "…",
  "detectedAt": "2026-09-28T09:11:04.000Z",
  "url": "https://attacksurfacescan.com/app/…"
}

priority is Highest, High, Medium or Low.

Avoiding duplicate issues (optional)

The description includes the dedupKey. Before Create issue, add a Lookup issues action with the JQL

labels = attack-surface-scan AND text ~ "{{webhookData.dedupKey}}" AND statusCategory != Done

then a condition that {{lookupIssues.size}} equals 0, so a repeat of an open change does not create a second issue.

Generic webhooks

Any HTTPS endpoint on a public hostname. Literal IP addresses, localhost, .internal and .local names are rejected, redirects are not followed, and the request times out after 10 seconds. The default JSON body:

{
  "subject": "Critical change on example.com",
  "body": "Port 5432 (PostgreSQL) started answering on db.example.com",
  "changes": [
    {
      "changeId": "3f0c…",
      "target": "db.example.com",
      "kind": "port.opened",
      "importance": "critical",
      "title": "Port 5432 (PostgreSQL) started answering",
      "before": "closed",
      "after": "open",
      "scanId": "…",
      "detectedAt": "2026-09-28T09:11:04.000Z"
    }
  ]
}

importance is one of critical, high, medium or low. kind is one of:

AreaChange kinds
Hosts and inventorysubdomain.added subdomain.removed asset.added asset.removed candidate.found
DNS and domainsdns.changed domain.expiring domain.lock_changed lookalike.registered
Services and softwareport.opened port.closed tech.added tech.removed vuln.new
Certificatescert.issued cert.misissued cert.issuer_changed cert.expiring cert.renewed cert.stale monitor.unreachable
Findings and scorefinding.new finding.resolved score.changed
Reputationreputation.listed reputation.cleared

OCSF format for SIEMs

Set the webhook's format to OCSF (SIEM) to receive each delivery as a JSON array of Open Cybersecurity Schema Framework 1.3.0 Detection Finding events (class 2004), which Amazon Security Lake, Splunk, Microsoft Sentinel and other SIEMs ingest without a custom parser. Abridged example (the real event also carries the class, category, activity, severity and status names, a message, product metadata and finding times):

[
  {
    "class_uid": 2004,
    "category_uid": 2,
    "activity_id": 1,
    "type_uid": 200401,
    "severity_id": 5,
    "status_id": 1,
    "time": 1790586664000,
    "metadata": {
      "version": "1.3.0",
      "uid": "3f0c…",
      "event_code": "port.opened"
    },
    "finding_info": {
      "uid": "afs-…",
      "title": "Port 5432 (PostgreSQL) started answering"
    },
    "resources": [{ "type": "Host", "name": "db.example.com" }],
    "unmapped": { "importance": "critical", "before": "closed", "after": "open", "scan_id": "…" }
  }
]
FieldValue
severity_idcritical 5, high 4, medium 3, low 2
status_id1 (new)
timeDetection time, epoch milliseconds
metadata.uidThe change ID
metadata.event_codeThe change kind
finding_info.uidThe same dedup key PagerDuty and Jira receive
resourcesThe affected host
unmappedimportance, before, after, scan_id

Pulling instead of pushing

For scheduled pulls into a data warehouse or GRC tool, use the REST API (Growth and above) or the CSV exports on the Compliance page.