Skip to content

Datadog

Datadog alerts reach the platform through Halo's stock Datadog integration, which posts a webhook payload to your instance and opens a ticket. The vendor's setup gets alerts in the door. This page covers what we change on top of it, so an incoming alert lands as a properly typed, categorized Alert ticket that carries its technical detail and maps to your compliance framework automatically.

Quick Summary

  • Follow Halo's guide for the base connection: the integration module, credentials, the API application, and the webhook.
  • Point the payload at the Alert ticket type rather than the integration's default ticket type, so alerts enter the triage-and-escalate workflow.
  • Set category_1 on every payload. Category is not cosmetic here -- it drives the framework control, requirement, and KSI linkage the platform derives automatically.
  • Reference custom fields by name, not by numeric id, so the same payload works in every instance.
  • Set the Incident SLA and a priority level on every payload -- priorities are scoped to their SLA, so one without the other is ambiguous.
  • Datadog cannot vary a category or priority from a single webhook, so create one webhook per category and route monitors to the right one.

Navigation

Configuration > Integrations on the GRC-ITSM website navigation, then the Datadog module.


Start with the vendor guide

Halo documents the base integration end to end. Follow it first, then apply the refinements below to the webhook payload.

Datadog Integration (Halo guide 2283)

Its setup, in brief:

  1. Enable the Datadog module under Configuration > Integrations.
  2. Enter your Datadog Site URL and API Key, plus an Application Key if you are forwarding security signals.
  3. Create an API application in the platform (Client ID and Secret, Login Type: Agent) for Datadog to authenticate against.
  4. In Datadog, add an Auth Method using OAuth 2.0 client credentials pointed at your token endpoint.
  5. Create the webhook, pointed at https://<your instance>/api/notify/datadog.
  6. Notify the webhook from a monitor or detection rule with @webhook-<name>.

Everything from here changes only the webhook payload and how many webhooks you create.


Why the payload matters

The stock payload opens a ticket with a summary, a priority, and a link back to Datadog. That is enough to notice an alert, and not enough to work one. Three things follow from the payload in GRC-ITSM:

What the payload sets What it drives
Ticket type Whether the alert enters the Alert triage workflow and can escalate in place to an Incident, carrying its history forward
Category The framework linkage. The platform derives the FedRAMP controls, requirements, KSIs, and CMMC controls on a ticket from its category, so the category you set is what ties the alert to your compliance evidence
Custom fields Whether a responder opens a ticket with the host, indicators, and detection source already in place, or has to pivot back to Datadog to find them

Target the Alert ticket type

Set the ticket type explicitly in the payload rather than relying on the integration's Default Ticket Type:

"tickettype_id": "21"

21 is the Alert ticket type. Confirm the value in your own instance under Configuration > Ticket Types -- the ID appears in the URL when you open the type.

Alerts are the entry point for anything a monitoring or detection tool reports. After triage an alert is either resolved as benign or escalated in place to an Incident. See Alert for the workflow, and the Incident Response playbook for what happens after escalation.


Set the category

Category is the field that earns the most from this integration, because framework linkage derives from it. An uncategorized alert is a ticket nobody can trace to a control.

Add the full category path to the payload:

"category_1": "Alerts and Incidents>Security>Suspicious Activity"

Use the path exactly as written, with > separators and no spaces around them. The Alert ticket type accepts these categories:

Security

Category path
Alerts and Incidents>Security
Alerts and Incidents>Security>Audit Log Failure
Alerts and Incidents>Security>Data Exfiltration
Alerts and Incidents>Security>Denial of Service
Alerts and Incidents>Security>Integrity Violation
Alerts and Incidents>Security>Malware
Alerts and Incidents>Security>Phishing
Alerts and Incidents>Security>Policy Violation
Alerts and Incidents>Security>Suspicious Activity
Alerts and Incidents>Security>Unauthorized Access
Alerts and Incidents>Security>Unauthorized Change
Alerts and Incidents>Security>Unauthorized Software

Availability

Category path
Alerts and Incidents>Availability
Alerts and Incidents>Availability>Automation Error
Alerts and Incidents>Availability>Backup Failure
Alerts and Incidents>Availability>KSI
Alerts and Incidents>Availability>Resource Exhaustion
Alerts and Incidents>Availability>Security Functionality
Alerts and Incidents>Availability>System Error
Alerts and Incidents>Availability>System Outage

Performance

Category path
Alerts and Incidents>Performance
Alerts and Incidents>Performance>Disk Full
Alerts and Incidents>Performance>High Resource Usage
Alerts and Incidents>Performance>Network Latency

Alerts and Incidents on its own is valid when no child fits, but prefer the most specific category that applies -- the more precise the category, the more precise the derived control linkage.

One webhook per category

A Datadog webhook sends a fixed payload, and Datadog's alert variables return display strings ($PRIORITY returns values like normal) that will not match a category path or a numeric priority. You cannot select a category dynamically from one webhook.

Create one webhook per category you actually use -- Halo-Alert-Security-Malware, Halo-Alert-Availability-System-Outage, and so on -- each with its category and priority hard-coded, then point each monitor or detection rule at the matching one with @webhook-<name>. This is the standard pattern for any field a Datadog variable cannot express.


Set the SLA and priority

Alerts run on the Incident SLA, which tracks both a response and a resolution clock. Priority levels in the platform are scoped to their SLA, so a priority level only means what you intend when the SLA is set alongside it. Send both:

"sla_id": "3",
"priority_id": "2"

The Incident SLA's levels:

priority_id Priority Response target Resolution target
1 Critical 0.5 hours 1 hour
2 High 1 hour 4 hours
3 Medium 4 hours 8 hours
4 Low 8 hours 24 hours

Choose the level deliberately, because the clock starts the moment the ticket opens. An automated alert firing overnight at Critical carries a 30-minute response target, so reserve level 1 for conditions that genuinely warrant waking someone. Confirm the SLA and priority IDs in your own instance under Configuration > Service Level Agreements.


Map the Alert custom fields

Reference custom fields by name rather than by the numeric id the vendor guide uses. Field IDs differ between instances, so a payload built on IDs breaks the moment it is reused; names are stable:

"customfields": [
  { "name": "CFDetectionSource", "value": "Datadog" }
]

The Alert ticket type carries these fields:

Field Name to use in the payload Populate from the webhook?
Detection Source CFDetectionSource Yes -- static. Datadog for monitors; add $SECURITY_RULE_NAME for signals so the ticket names the rule that fired
Internal Indicators CFInternalIndicators Yes -- $HOSTNAME for the affected host, and $ALERT_SCOPE for the tags that triggered the alert
External Indicators CFExternalIndicators No -- Datadog exposes no scalar variable for a client IP or domain. Fill during triage; see the warning below
Related CVEs CFRelatedCVEs No -- no webhook variable carries a CVE. Fill during triage
MITRE Tactics CFMITRETactics No -- no variable carries it. Fill during triage; see MITRE fields below
MITRE Techniques CFMITRETechniques No -- fill during triage
MITRE Subtechniques CFMITRESubtechniques No -- fill during triage
Root Cause CFrootcauses No -- After Action Report field, written during response
Lessons Learned CFLessonsLearned No -- After Action Report field
Corrective Actions CFCorrectiveActions No -- After Action Report field

Field names are case-sensitive and must be sent exactly as shown, including CFrootcauses, whose lowercase spelling is deliberate and differs from the pattern the other fields follow.

The framework fields on the ticket (FedRAMP Controls, FedRAMP Requirements, FedRAMP KSIs, FedRAMP Rules, CMMC Controls, CMMC Requirements) are never set in the payload. They derive from the category.

Which Datadog variables are worth mapping

Datadog's webhook variables are fixed -- you cannot traverse into an object or transform a value in the payload. These are the ones that carry something a responder wants:

Variable Returns Useful for
$HOSTNAME The host associated with the event Internal Indicators
$ALERT_SCOPE Comma-separated triggering tags, e.g. availability-zone:us-east-1a, role:computing-node Internal Indicators -- often more useful than the hostname alone
$ALERT_QUERY The monitor query that fired Details, when the ticket needs the detection logic
$ALERT_METRIC The metric name, e.g. system.load.1 Details on metric monitors
$SECURITY_RULE_NAME The detection rule's name Detection Source
$SECURITY_RULE_TYPE The rule type, e.g. log_detection Detection Source, where you distinguish rule classes
$SECURITY_SIGNAL_SEVERITY The signal's severity, on Cloud SIEM's info through critical scale Details -- it is a string, so it cannot drive priority_id
$ALERT_TRANSITION Triggered, Re-Triggered, Recovered, Renotify, and similar Filtering which events open tickets at all -- see below
$ALERT_CYCLE_KEY An ID linking every event from trigger through resolution Correlating follow-up events to the original ticket

Three fields have no usable source and belong to triage:

  • External Indicators. Client IPs live inside $SECURITY_SIGNAL_ATTRIBUTES, which returns an object such as {"network":{"client":{"ip":"1.2.3.4"}}, "service": ["agent"]}. There is no scalar variable for the IP alone, and no way to reach into the object from the payload.
  • Related CVEs. No webhook variable carries one.
  • MITRE fields. Covered below.

MITRE fields

Datadog detection rules carry MITRE ATT&CK metadata as rule tags in the form tactic:TA0001-Initial-Access and technique:T1566-Phishing, and those tags are what place a rule on Datadog's ATT&CK map. No webhook variable exposes them, so they cannot travel with the alert.

Fill all three during triage. The responder has the signal in front of them and can read the rule's tags directly, which beats any value baked into a webhook -- a payload's value would be wrong for every rule that does not happen to share it.

MITRE Tactics is a lookup field, so its value must match one of your instance's options exactly. Check the current options under Configuration > Custom Objects > Custom Fields. The platform's options correspond to the MITRE ATT&CK enterprise tactics, so a rule's tag translates directly:

Datadog rule tag Value to send
tactic:TA0043-Reconnaissance Reconnaissance
tactic:TA0042-Resource-Development Resource Development
tactic:TA0001-Initial-Access Initial Access
tactic:TA0002-Execution Execution
tactic:TA0003-Persistence Persistence
tactic:TA0004-Privilege-Escalation Privilege Escalation
tactic:TA0005-Defense-Evasion Defense Evasion
tactic:TA0006-Credential-Access Credential Access
tactic:TA0007-Discovery Discovery
tactic:TA0008-Lateral-Movement Lateral Movement
tactic:TA0009-Collection Collection
tactic:TA0011-Command-and-Control Command & Control
tactic:TA0010-Exfiltration Exfiltration
tactic:TA0040-Impact Impact

MITRE Techniques and MITRE Subtechniques are free-form, so a responder can paste the rule's technique tag, such as T1566-Phishing, as written.


The payload

Monitor alerts

For availability and performance monitors:

{
  "datadog_id": "$ID",
  "tickettype_id": "21",
  "category_1": "Alerts and Incidents>Availability>System Outage",
  "summary": "$EVENT_TITLE",
  "details": "$TEXT_ONLY_MSG",
  "sla_id": "3",
  "priority_id": "2",
  "customfields": [
    { "name": "CFDetectionSource", "value": "Datadog" },
    { "name": "CFInternalIndicators", "value": "Host: $HOSTNAME | Scope: $ALERT_SCOPE" },
    { "name": "CFExternalIndicators", "value": "" },
    { "name": "CFRelatedCVEs", "value": "" },
    { "name": "CFMITRETactics", "value": "" },
    { "name": "CFMITRETechniques", "value": "" },
    { "name": "CFMITRESubtechniques", "value": "" }
  ],
  "new_external_link": {
    "table_id": "1",
    "module_id": "391",
    "third_party_id": "$ID",
    "third_party_url": "$LINK",
    "third_party_desc": "$EVENT_TITLE"
  }
}

Security signals

For Cloud SIEM detection rules, which carry signal context the monitor payload does not:

{
  "datadog_id": "$ID",
  "security_signal_id": "$SECURITY_SIGNAL_ID",
  "tickettype_id": "21",
  "category_1": "Alerts and Incidents>Security>Suspicious Activity",
  "summary": "$EVENT_TITLE",
  "details": "$EVENT_MSG",
  "sla_id": "3",
  "priority_id": "2",
  "customfields": [
    { "name": "CFDetectionSource", "value": "Datadog Cloud SIEM: $SECURITY_RULE_NAME ($SECURITY_RULE_TYPE)" },
    { "name": "CFInternalIndicators", "value": "Host: $HOSTNAME | Scope: $ALERT_SCOPE" },
    { "name": "CFExternalIndicators", "value": "" },
    { "name": "CFRelatedCVEs", "value": "" },
    { "name": "CFMITRETactics", "value": "" },
    { "name": "CFMITRETechniques", "value": "" },
    { "name": "CFMITRESubtechniques", "value": "" }
  ],
  "new_external_link": {
    "table_id": "1",
    "module_id": "391",
    "third_party_id": "$ID",
    "third_party_url": "$LINK",
    "third_party_desc": "$SECURITY_SIGNAL_ID"
  }
}

The empty fields are deliberate. They are carried in the payload as placeholders so the full Alert field set is visible in one place, and so anyone extending the webhook can see what is available without cross-referencing this page. Fill in any your own instance can supply -- a monitor that always covers one service might reasonably carry a static value another would not -- and delete the lines you do not want set. Confirm field names and lookup options against your instance under Configuration > Custom Objects > Custom Fields before relying on them.

Fire one test alert into a non-production instance before going live. MITRE Tactics is a lookup field, and how a given instance treats an empty value on a lookup is worth confirming rather than assuming -- if the blank placeholder is rejected, drop that line and set the field during triage instead.

Keep the vendor guide's datadog_id, security_signal_id, and new_external_link values as it defines them. The identifiers tie the ticket to the originating alert, and the external link is what lets a responder reach the Datadog graph or signal in one click.

Validate $SECURITY_SIGNAL_ATTRIBUTES before relying on it

It is tempting to map $SECURITY_SIGNAL_ATTRIBUTES into External Indicators to capture client IPs. That variable expands to a JSON object rather than a plain string, so placing it inside a quoted payload value can produce invalid JSON and a webhook that fails without warning -- and because detection rules cannot be test-fired, you would not find out until a real signal was dropped.

Leave External Indicators for triage unless you have confirmed the behavior with a live signal in a non-production instance first.

HIPAA-enabled Datadog organizations cannot send security signals to webhooks

Datadog does not deliver security notifications over webhooks for HIPAA-enabled accounts. If your organization is HIPAA-enabled, detection rules referencing Signals or Findings will not reach the platform through this integration; the notifications are simply not sent, so there is no later delivery to wait for. Confirm your organization's status with Datadog before building the security-signal path, and request an exception through your Datadog account team if you need it. Monitor alerts are unaffected.


Control which events open tickets

By default a webhook fires on every state change a monitor goes through, so a single flapping monitor can open a ticket on trigger, another on renotify, and another on recovery. $ALERT_TRANSITION identifies which is which, returning values including Triggered, Re-Triggered, Recovered, Renotify, Warn, and No Data.

Two ways to keep the queue clean:

  • Notify the webhook only on the transitions you want. A handle placed outside a conditional block fires on every state transition; one placed inside fires only when that condition matches. Wrapping the mention in the alert condition keeps recoveries from ever reaching the platform:

    {{#is_alert}}@webhook-Halo-Alert-Availability-System-Outage{{/is_alert}}
    

    A webhook scoped this way still fires on renotification, since a renotify re-sends the alert message. - Include $ALERT_TRANSITION in the ticket details where you do forward multiple transitions, so a responder can see at a glance whether they are looking at a new condition or a repeat.

$ALERT_CYCLE_KEY stays constant from the moment an alert triggers until it resolves, which makes it the right identifier if you later automate matching follow-up events to an existing ticket rather than opening a new one.

Field reference

Payload key Source Notes
tickettype_id Static The Alert ticket type
category_1 Static, per webhook Drives framework control linkage
summary $EVENT_TITLE Becomes the ticket summary
details $EVENT_MSG or $TEXT_ONLY_MSG $TEXT_ONLY_MSG strips Datadog's markdown, which reads better in the ticket body
sla_id Static The Incident SLA, which alerts run on
priority_id Static, per webhook Scoped to the SLA above. Datadog's $PRIORITY returns a display string, not an ID
customfields[].name Static Field names from the table above
new_external_link $ID, $LINK The link back to Datadog

Datadog allows each webhook request 15 seconds and retries up to five times on a 5XX response or an internal error, so a brief platform outage will not lose an alert outright.


Assets

The Alert ticket type carries the Asset field, but Datadog identifies a host by name and the platform links assets by record. Send $HOSTNAME into Internal Indicators as shown above, and link the asset during triage so the alert joins that asset's history. Where a monitor's hosts map predictably to inventory records, a ticket rule can match the hostname and set the asset automatically.


Verify the setup

  1. In Datadog, open the webhook and use Test Notifications to fire a sample monitor alert. Detection rules cannot be tested this way and require a real signal.
  2. Confirm the ticket opens as an Alert, not the integration's default type.
  3. Confirm the category is set and the framework fields populated from it.
  4. Confirm Detection Source and Internal Indicators carry values, and the Datadog link resolves.
  5. Run one alert all the way through triage, including escalation to an Incident, before pointing production monitors at the webhook.

This is an external connection

Datadog sits outside the platform, so this integration is a data flow crossing your authorization boundary. Document the interconnection in the System Security Plan, including what alert content leaves Datadog and enters the platform, and confirm the Datadog offering you use carries an authorization appropriate to your environment before enabling it in a FedRAMP or CUI boundary. See the Integrations overview for the full pre-enablement checklist.

Related documentation