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.

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 on a Basic subscription, 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 enables the rule with the specified ID.
{
  "ids": [
    "748694f0-6977-4ea5-8384-cd2e39730779"
  ],
  "action": "enable"
}
The following request disables the rule with the specified ID.
{
  "ids": [
    "748694f0-6977-4ea5-8384-cd2e39730779"
  ],
  "action": "disable"
}
The following request adds tags tag-1 and tag-2 to the rules that have the IDs sent in the payload
{
  "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 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",
    "13199674-aff1-418a-9e93-04f585fe36d1"
  ],
  "action": "export"
}
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
}