Apply a bulk action to detection rules

POST /api/detection_engine/rules/_bulk_action

Apply a bulk action, such as bulk edit, duplicate, or delete, to multiple detection rules. The bulk action is applied to all rules that match the query or to the rules listed by their IDs.

The edit action allows you to add, delete, or set tags, index patterns, investigation fields, rule actions, and schedules for multiple rules at once. The edit action is idempotent, meaning that if you add a tag to a rule that already has that tag, no changes are made. The same is true for other edit actions, for example removing an index pattern that is not specified in a rule will not result in any changes.

When used with API key authentication, the user's key gets assigned to the affected rules. If the user's key gets deleted or the user becomes inactive, the rules will stop running.

If the API key that is used for authorization has different privileges than the key that created or most recently updated the rule, the rule behavior might change.

Query parameters

  • dry_run boolean

    Enables dry run mode for the request call.

    Enable dry run mode to verify that bulk actions can be applied to specified rules. Certain rules, such as prebuilt Elastic rules, can’t be edited and will return errors in the request response. Error details will contain an explanation, the rule name and/or ID, and additional troubleshooting information.

    To enable dry run mode on a request, add the query parameter dry_run=true to the end of the request URL. Rules specified in the request will be temporarily updated. These updates won’t be written to Elasticsearch.

    Dry run mode is not supported for the export bulk action. A 400 error will be returned in the request response.

application/json

Body object

One of:

Responses

  • 200 application/json

    OK

    One of:
POST /api/detection_engine/rules/_bulk_action
curl \
 --request POST 'http://localhost:5601/api/detection_engine/rules/_bulk_action' \
 --user "username:password" \
 --header "Content-Type: application/json" \
 --data '{"query":"alert.attributes.tags: \"test\"","action":"enable"}'
The following request activates all rules with the test tag.
{
  "query": "alert.attributes.tags: \"test\"",
  "action": "enable"
}
The following request adds two tags at the same time, tag-1 and tag-2, to the rules that have the IDs sent in the payload. If the tags already exist for a rule, no changes are made.
{
  "ids": [
    "8bc7dad0-9320-11ec-9265-8b772383a08d",
    "8e5c1a40-9320-11ec-9265-8b772383a08d"
  ],
  "edit": [
    {
      "type": "add_tags",
      "value": [
        "tag-1",
        "tag-2"
      ]
    }
  ],
  "action": "edit"
}
The following request removes the tag "tag-1" from the rules with the specified IDs. If the tag does not exist for a rule, no changes are made.
{
  "ids": [
    "8bc7dad0-9320-11ec-9265-8b772383a08d",
    "8e5c1a40-9320-11ec-9265-8b772383a08d"
  ],
  "edit": [
    {
      "type": "delete_tags",
      "value": [
        "tag-1"
      ]
    }
  ],
  "action": "edit"
}
The following request sets the tags "tag-1" and "tag-2" for the rules with the specified IDs, overwriting any existing tags. If the set of tags is the same as the existing tags, no changes are made.
{
  "ids": [
    "8bc7dad0-9320-11ec-9265-8b772383a08d",
    "8e5c1a40-9320-11ec-9265-8b772383a08d"
  ],
  "edit": [
    {
      "type": "set_tags",
      "value": [
        "tag-1",
        "tag-2"
      ]
    }
  ],
  "action": "edit"
}
The following request adds the index pattern "test-*" to the rules with the specified IDs. If the index pattern already exists for a rule, no changes are made.
{
  "ids": [
    "81aa0480-06af-11ed-94fb-dd1a0597d8d2",
    "dc015d10-0831-11ed-ac8b-05a222bd8d4a"
  ],
  "edit": [
    {
      "type": "add_index_patterns",
      "value": [
        "test-*"
      ]
    }
  ],
  "action": "edit"
}
The following request removes the index pattern "test-*" from the rules with the specified IDs. If the index pattern does not exist for a rule, no changes are made.
{
  "ids": [
    "81aa0480-06af-11ed-94fb-dd1a0597d8d2",
    "dc015d10-0831-11ed-ac8b-05a222bd8d4a"
  ],
  "edit": [
    {
      "type": "delete_index_patterns",
      "value": [
        "test-*"
      ]
    }
  ],
  "action": "edit"
}
The following request sets the index patterns "test-*" and "prod-*" for the rules with the specified IDs, overwriting any existing index patterns. If the set of index patterns is the same as the existing index patterns, no changes are made.
{
  "ids": [
    "81aa0480-06af-11ed-94fb-dd1a0597d8d2",
    "dc015d10-0831-11ed-ac8b-05a222bd8d4a"
  ],
  "edit": [
    {
      "type": "set_index_patterns",
      "value": [
        "test-*"
      ]
    }
  ],
  "action": "edit"
}
The following request adds investigation field to the rules with the specified IDs.
{
  "ids": [
    "12345678-1234-1234-1234-1234567890ab",
    "87654321-4321-4321-4321-0987654321ba"
  ],
  "edit": [
    {
      "type": "add_investigation_fields",
      "value": {
        "field_names": [
          "alert.status"
        ]
      }
    }
  ],
  "action": "edit"
}
The following request deletes investigation fields from the rules with the specified IDs.
{
  "ids": [
    "12345678-1234-1234-1234-1234567890ab",
    "87654321-4321-4321-4321-0987654321ba"
  ],
  "edit": [
    {
      "type": "delete_investigation_fields"
    }
  ],
  "value": [
    "field1",
    "field2"
  ],
  "action": "edit"
}
The following request sets investigation fields for the rules with the specified IDs, overwriting any existing investigation fields.
{
  "ids": [
    "12345678-1234-1234-1234-1234567890ab",
    "87654321-4321-4321-4321-0987654321ba"
  ],
  "edit": [
    {
      "type": "set_investigation_fields",
      "value": [
        "field1",
        "field2"
      ]
    }
  ],
  "action": "edit"
}
The following request sets a timeline for the rules with the specified IDs.
{
  "ids": [
    "11223344-5566-7788-99aa-bbccddeeff00"
  ],
  "edit": [
    {
      "type": "set_timeline",
      "value": null,
      "timeline_id": "timeline-123",
      "timeline_title": "Investigation Timeline"
    }
  ],
  "action": "edit"
}
The following request enables the rule with the specified ID.
{
  "ids": [
    "748694f0-6977-4ea5-8384-cd2e39730779"
  ],
  "action": "enable"
}
The following request sets a schedule for the rules with the specified IDs.
{
  "ids": [
    "99887766-5544-3322-1100-aabbccddeeff"
  ],
  "edit": [
    {
      "type": "set_schedule",
      "value": {
        "interval": "1h",
        "lookback": "30m"
      }
    }
  ],
  "action": "edit"
}
The following request adds rule actions to the rules with the specified IDs.
{
  "ids": [
    "aabbccdd-eeff-0011-2233-445566778899"
  ],
  "edit": [
    {
      "type": "add_rule_actions",
      "value": null,
      "actions": [
        {
          "id": "action-123",
          "group": "default",
          "params": {
            "key": "value"
          }
        }
      ],
      "throttle": "1h"
    }
  ],
  "action": "edit"
}
The following request sets rule actions for the rules with the specified IDs.
{
  "ids": [
    "ffeeddcc-bbaa-9988-7766-554433221100"
  ],
  "edit": [
    {
      "type": "set_rule_actions",
      "value": null,
      "actions": [
        {
          "id": "action-456",
          "group": "notification",
          "params": {
            "key": "another-value"
          }
        }
      ],
      "throttle": "rule"
    }
  ],
  "action": "edit"
}
The following request disables the rule with the specified ID.
{
  "ids": [
    "748694f0-6977-4ea5-8384-cd2e39730779"
  ],
  "action": "disable"
}
The following request will validate that the add_index_patterns bulk action can be successfully applied to three rules. The dry_run parameter is specified in query parameters, e.g. POST api/detection_engine/rules/_bulk_action?dry_run=true
{
  "ids": [
    "81aa0480-06af-11ed-94fb-dd1a0597d8d2",
    "dc015d10-0831-11ed-ac8b-05a222bd8d4a",
    "de8f5af0-0831-11ed-ac8b-05a222bd8d4a"
  ],
  "edit": [
    {
      "type": "add_index_patterns",
      "value": [
        "test-*"
      ]
    }
  ],
  "action": "edit"
}
The following request duplicates rules with the specified IDs, including exceptions but not expired exceptions.
{
  "ids": [
    "748694f0-6977-4ea5-8384-cd2e39730779",
    "461a4c22-416e-4009-a9a7-cf79656454bf"
  ],
  "action": "duplicate",
  "duplicate": {
    "include_exceptions": true,
    "include_expired_exceptions": false
  }
}
The following request deletes the rule with the specified ID.
{
  "ids": [
    "cf4abfd1-7c37-4519-ab0f-5ea5c75fac60"
  ],
  "action": "delete"
}
The following request runs the rule with the specified ID within the given date range.
{
  "ids": [
    "748694f0-6977-4ea5-8384-cd2e39730779"
  ],
  "run": {
    "end_date": "2025-03-10T23:59:59.999Z",
    "start_date": "2025-03-01T00:00:00.000Z"
  },
  "action": "run"
}
The following request exports the rules with the specified IDs.
{
  "ids": [
    "748694f0-6977-4ea5-8384-cd2e39730779"
  ],
  "action": "export"
}
The following request adds the tag "tag-1" to the rules with the specified IDs. If the tag already exists for a rule, no changes are made.
{
  "ids": [
    "8bc7dad0-9320-11ec-9265-8b772383a08d",
    "8e5c1a40-9320-11ec-9265-8b772383a08d"
  ],
  "edit": [
    {
      "type": "add_tags",
      "value": [
        "tag-1"
      ]
    }
  ],
  "action": "edit"
}
Response examples (200)
In this response one rule was updated and one was skipped. Objects returned in attributes.results.skipped will only include rules' id, name, and skip_reason.
{
  "success": true,
  "attributes": {
    "results": {
      "created": [],
      "deleted": [],
      "skipped": [
        {
          "id": "51658332-a15e-4c9e-912a-67214e2e2359",
          "name": "Skipped rule",
          "skip_reason": "RULE_NOT_MODIFIED"
        }
      ],
      "updated": [
        {
          "id": "8bc7dad0-9320-11ec-9265-8b772383a08d",
          "to": "now",
          "from": "now-45m",
          "name": "DNS Tunneling [Duplicate]",
          "tags": [
            "Elastic",
            "Network",
            "Threat Detection",
            "ML"
          ],
          "type": "machine_learning",
          "setup": "",
          "author": [
            "Elastic"
          ],
          "threat": [],
          "enabled": true,
          "license": "Elastic License v2",
          "rule_id": "7289bf08-4e91-4c70-bf01-e04c4c5d7756",
          "version": 6,
          "interval": "15m",
          "severity": "low",
          "immutable": false,
          "created_at": "2022-02-21T14:14:13.801Z",
          "created_by": "elastic",
          "references": [
            "https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"
          ],
          "risk_score": 21,
          "updated_at": "2022-02-21T17:05:50.883Z",
          "updated_by": "elastic",
          "description": "A machine learning job detected unusually large numbers of DNS queries for a single top-level DNS domain, which is often used for DNS tunneling. DNS tunneling can be used for command-and-control, persistence, or data exfiltration activity. For example, dnscat tends to generate many DNS questions for a top-level domain as it uses the DNS protocol to tunnel data.",
          "max_signals": 100,
          "exceptions_list": [],
          "false_positives": [
            "DNS domains that use large numbers of child domains, such as software or content distribution networks, can trigger this alert and such parent domains can be excluded."
          ],
          "required_fields": [],
          "severity_mapping": [],
          "anomaly_threshold": 50,
          "execution_summary": {
            "last_execution": {
              "date": "2022-03-23T16:06:12.787Z",
              "status": "partial failure",
              "message": "This rule attempted to query data from Elasticsearch indices listed in the \"Index pattern\" section of the rule definition, but no matching index was found.",
              "metrics": {
                "execution_gap_duration_s": 0,
                "total_search_duration_ms": 135,
                "total_indexing_duration_ms": 15
              },
              "status_order": 20
            }
          },
          "risk_score_mapping": [],
          "related_integrations": [],
          "machine_learning_job_id": [
            "packetbeat_dns_tunneling"
          ]
        }
      ]
    },
    "summary": {
      "total": 2,
      "failed": 0,
      "skipped": 1,
      "succeeded": 1
    }
  },
  "rules_count": 1
}
If processing of any rule fails, a partial error outputs the ID and/or name of the affected rule and the corresponding error, as well as successfully processed rules (in the same format as a successful 200 request).
{
  "value": {
    "message": "Bulk edit partially failed",
    "success": false,
    "attributes": {
      "errors": [
        {
          "rules": [
            {
              "id": "8bc7dad0-9320-11ec-9265-8b772383a08d",
              "name": "DNS Tunneling [Duplicate]"
            }
          ],
          "message": "Index patterns can't be added. Machine learning rule doesn't have index patterns property",
          "status_code": 500
        }
      ],
      "results": {
        "created": [],
        "deleted": [],
        "skipped": [],
        "updated": [
          {
            "id": "8e5c1a40-9320-11ec-9265-8b772383a08d",
            "to": "now",
            "from": "now-6m",
            "name": "External Alerts [Duplicate]",
            "tags": [
              "Elastic",
              "Network",
              "Windows",
              "APM",
              "macOS",
              "Linux"
            ],
            "type": "query",
            "index": [
              "apm-*-transaction*",
              "traces-apm*",
              "auditbeat-*",
              "filebeat-*",
              "logs-*",
              "packetbeat-*",
              "winlogbeat-*",
              "added-by-id-*"
            ],
            "query": "event.kind:alert and not event.module:(endgame or endpoint)\n",
            "setup": "",
            "author": [
              "Elastic"
            ],
            "threat": [],
            "actions": [],
            "enabled": true,
            "license": "Elastic License v2",
            "rule_id": "941faf98-0cdc-4569-b16d-4af962914d61",
            "version": 5,
            "interval": "5m",
            "language": "kuery",
            "severity": "medium",
            "immutable": false,
            "created_at": "2022-02-21T14:14:17.883Z",
            "created_by": "elastic",
            "references": [],
            "risk_score": 47,
            "updated_at": "2022-02-21T16:56:22.818Z",
            "updated_by": "elastic",
            "description": "Generates a detection alert for each external alert written to the configured indices. Enabling this rule allows you to immediately begin investigating external alerts in the app.",
            "max_signals": 10000,
            "exceptions_list": [],
            "false_positives": [],
            "required_fields": [],
            "severity_mapping": [
              {
                "field": "event.severity",
                "value": "21",
                "operator": "equals",
                "severity": "low"
              },
              {
                "field": "event.severity",
                "value": "47",
                "operator": "equals",
                "severity": "medium"
              },
              {
                "field": "event.severity",
                "value": "73",
                "operator": "equals",
                "severity": "high"
              },
              {
                "field": "event.severity",
                "value": "99",
                "operator": "equals",
                "severity": "critical"
              }
            ],
            "execution_summary": {
              "last_execution": {
                "date": "2022-03-23T16:06:12.787Z",
                "status": "partial failure",
                "message": "This rule attempted to query data from Elasticsearch indices listed in the \"Index pattern\" section of the rule definition, but no matching index was found.",
                "metrics": {
                  "execution_gap_duration_s": 0,
                  "total_search_duration_ms": 135,
                  "total_indexing_duration_ms": 15
                },
                "status_order": 20
              }
            },
            "risk_score_mapping": [
              {
                "field": "event.risk_score",
                "value": "",
                "operator": "equals"
              }
            ],
            "rule_name_override": "message",
            "timestamp_override": "event.ingested",
            "related_integrations": []
          }
        ]
      },
      "summary": {
        "total": 2,
        "failed": 1,
        "skipped": 0,
        "succeeded": 1
      }
    },
    "rules_count": 2,
    "status_code": 500
  }
}
The attributes.errors section of the response shows that two rules failed to update and one succeeded. The same results would be returned if you ran the request without dry run mode enabled. Notice that there are no arrays in attributes.results. In dry run mode, rule updates are not applied and saved to Elasticsearch, so the endpoint wouldn’t return results for rules that have been updated, created, or deleted.
{
  "message": "Bulk edit partially failed",
  "attributes": {
    "errors": [
      {
        "rules": [
          {
            "id": "81aa0480-06af-11ed-94fb-dd1a0597d8d2",
            "name": "Unusual AWS Command for a User"
          }
        ],
        "message": "Elastic rule can't be edited",
        "err_code": "IMMUTABLE",
        "status_code": 500
      },
      {
        "rules": [
          {
            "id": "dc015d10-0831-11ed-ac8b-05a222bd8d4a",
            "name": "Suspicious Powershell Script [Duplicate]"
          }
        ],
        "message": "Machine learning rule doesn't have index patterns",
        "err_code": "MACHINE_LEARNING_INDEX_PATTERN",
        "status_code": 500
      }
    ],
    "results": {
      "created": [],
      "deleted": [],
      "skipped": [],
      "updated": []
    },
    "summary": {
      "total": 3,
      "failed": 2,
      "skipped": 0,
      "succeeded": 1
    }
  },
  "status_code": 500
}