Loading

Cases action steps

Cases action steps let workflows create, query, update, and manage cases. The cases.* namespace provides full coverage of the Cases API through a single, consistent set of step types so you can automate case workflows without leaving the Elastic platform.

Use Cases steps for patterns like:

  • Create a case when a detection rule fires, then attach the alert and relevant observables.
  • Open a case, assign it to an on-call user, and post a notification to a team channel.
  • Find similar cases for deduplication before creating a new one.
  • Close a case automatically when a condition is met, and append an analyst note first.

Every cases.* step shares the same conventions, so once you learn one step the others are predictable.

Parameter casing. Case-level parameters use snake_case: case_id, not caseId. The editor rejects camelCase for these fields. Individual payloads, such as the alert object attached by cases.addAlerts, use the casing of the originating API (for example, alertId, index) because they match external API shapes.

Optional push-case config. Most cases.* steps accept an optional top-level push-case boolean (defaults to false). When true, the step pushes the updated case to a connected external system (for example, Jira or ServiceNow) after the workflow operation succeeds.

push-case applies only to steps that change a case. It is not supported on the read-only and internal steps: cases.deleteCase, cases.findCases, cases.findSimilarCases, cases.getAllAttachments, cases.getCase, cases.getCases, cases.getCasesByAlertId, and cases.updateObservable.

- name: create_and_push
  type: cases.createCase
  push-case: true
  with:
    title: "Triage required"
    severity: high
		

Getting the case ID. The response from cases.createCase includes the new case ID at steps.<step_name>.output.case.id. Reference it in subsequent steps:

- name: new_case
  type: cases.createCase
  with:
    title: "..."

- name: tag_case
  type: cases.addTags
  with:
    case_id: "{{ steps.new_case.output.case.id }}"
    tags: ["triaged"]
		

The 27 Cases steps group into six operational categories. Jump to any step:

Create, fetch, and search cases.createCase · cases.createCaseFromTemplate · cases.getCase · cases.getCases · cases.findCases · cases.findSimilarCases · cases.getCasesByAlertId

Update fields cases.updateCase · cases.updateCases · cases.setStatus · cases.setSeverity · cases.setTitle · cases.setDescription · cases.setCategory · cases.setCustomField · cases.closeCase

Attach content cases.addComment · cases.addAlerts · cases.addEvents · cases.addObservables · cases.getAllAttachments

Tags and assignees cases.addTags · cases.assignCase · cases.unassignCase

Update and delete observables cases.updateObservable · cases.deleteObservable

Delete cases.deleteCases


Create a case with a title, description, severity, tags, and optional assignees. Accepts an optional top-level connector-id to associate the case with a configured external connector (for example, Jira or ServiceNow).

Parameter Location Type Required Description
connector-id top level string No ID of a configured external connector to attach to the case.
title with string Yes Case title.
description with string Yes Case description. Markdown supported.
owner with string Yes Case owner: securitySolution, observability, or cases.
severity with string No low, medium, high, or critical.
tags with string[] No Tags to apply to the case.
assignees with array No Array of { uid } objects.
category with string No Case category.
customFields with array No Custom field values.
settings with object No Case settings, for example syncAlerts.
- name: create_case
  type: cases.createCase
  with:
    title: "{{ event.rule.name }} on {{ event.alerts[0].host.name }}"
    description: "Automatically created from detection rule."
    severity: high
    tags: ["auto-triage", "malware"]
    owner: "securitySolution"
		

Create a case from a configured case template. Useful when a team has pre-defined case shapes (default title, description, tags, severity) for common scenarios.

Parameter Location Type Required Description
case_template_id with string Yes ID of the template to apply.
overwrites with object No Fields to override on the templated case, for example title, tags.
- name: create_from_template
  type: cases.createCaseFromTemplate
  with:
    case_template_id: "malware-triage-template"
    overwrites:
      title: "Malware: {{ event.alerts[0].host.name }}"
		

Retrieve a complete case object by ID. Optionally include comments and attachments in the response.

Parameter Location Type Required Description
case_id with string Yes Case ID.
include_comments with boolean Yes Whether to include comments and attachments in the response.
- name: fetch_case
  type: cases.getCase
  with:
    case_id: "{{ inputs.case_id }}"
    include_comments: true
		

Retrieve up to 1000 cases in a single request. IDs that can't be fetched are reported in the errors array on the output. Use this to avoid N sequential cases.getCase calls in fan-out workflows.

Parameter Location Type Required Description
case_ids with string[] Yes Array of case IDs. Maximum 1000.

Output: { cases: array, errors: array }. The errors array contains entries for any IDs that couldn't be fetched.

- name: fetch_cases
  type: cases.getCases
  with:
    case_ids: ["case-1", "case-2", "case-3"]
		

Search for cases matching filter criteria. Supports paging, sorting, and filtering by many fields. The output includes a cases array plus per-status counts (count_open_cases, count_in_progress_cases, count_closed_cases), page, per_page, and total.

Parameter Location Type Required Description
search with string No Free-text search.
searchFields with string \| string[] No Fields to search in.
defaultSearchOperator with string No AND or OR for multi-term search.
status with string \| string[] No Filter by status.
severity with string \| string[] No Filter by severity.
tags with string \| string[] No Filter by tag.
category with string \| string[] No Filter by category.
owner with string \| string[] No Filter by case owner.
assignees with string \| string[] No Filter by assignee UID.
reporters with string \| string[] No Filter by reporter.
customFields with object No Map of custom-field ID to allowed values.
from with string No Start of the time range.
to with string No End of the time range.
page with number No Page number. Defaults to 1.
perPage with number No Results per page. Defaults to 20.
sortField with string No title, category, createdAt, updatedAt, closedAt, status, or severity.
sortOrder with string No asc or desc.
- name: find_open_high_sev
  type: cases.findCases
  with:
    owner: "securitySolution"
    status: "open"
    severity: ["high", "critical"]
    tags: ["investigation"]
    sortField: "updatedAt"
    sortOrder: "desc"
    perPage: 20
		

Find cases similar to a given case, matched by shared observables. Useful for deduplication before creating a new case.

Parameter Location Type Required Description
case_id with string Yes Source case ID to find similar cases for.
page with integer Yes Page number (1-based).
perPage with integer Yes Results per page.

The output includes a cases array, page, and per_page.

- name: find_similar
  type: cases.findSimilarCases
  with:
    case_id: "{{ steps.create_case.output.case.id }}"
    page: 1
    perPage: 20
		

Find every case that contains a specific alert. The canonical "does a case already exist for this alert?" query.

Parameter Location Type Required Description
alert_id with string Yes Alert signal ID.
owner with string No Filter by case owner.
- name: check_existing
  type: cases.getCasesByAlertId
  with:
    alert_id: "{{ event.alerts[0]._id }}"
		

Update one case's fields. Changes go inside a required updates object. An optional version field enforces optimistic concurrency.

Parameter Location Type Required Description
case_id with string Yes Case ID.
version with string No Case version for optimistic concurrency.
updates with object Yes Fields to update. At least one field required. Includes title, description, status, severity, category, tags, assignees, settings, and more.
- name: escalate
  type: cases.updateCase
  with:
    case_id: "{{ steps.find.output.cases[0].id }}"
    updates:
      status: "in-progress"
      severity: "critical"
      tags: ["escalated"]
		
Important

Update fields must sit inside the updates object, not at the top level of with. updates: { status: open } is valid; with: { status: open, case_id: ... } is not.

Bulk-update multiple cases. Each element specifies its own case_id, optional version, and updates object.

Parameter Location Type Required Description
cases with array Yes Array of { case_id, version?, updates } objects.
- name: bulk_close
  type: cases.updateCases
  with:
    cases:
      - case_id: "c1"
        updates:
          status: "closed"
      - case_id: "c2"
        updates:
          status: "closed"
		

Set a case's status.

Parameter Location Type Required Description
case_id with string Yes Case ID.
status with string Yes open, in-progress, or closed.
- name: mark_in_progress
  type: cases.setStatus
  with:
    case_id: "{{ steps.create_case.output.case.id }}"
    status: "in-progress"
		

Set a case's severity.

Parameter Location Type Required Description
case_id with string Yes Case ID.
severity with string Yes low, medium, high, or critical.

Update a case's title.

Parameter Location Type Required Description
case_id with string Yes Case ID.
title with string Yes New title.

Update a case's description.

Parameter Location Type Required Description
case_id with string Yes Case ID.
description with string Yes New description. Markdown supported.

Set a case's category.

Parameter Location Type Required Description
case_id with string Yes Case ID.
category with string Yes Category name.
owner with string No Case owner. Optional, helps with auto-completion.

Set a single custom-field value on a case. The field_name parameter is the system-set custom-field identifier (a UUID-style string), not the human-readable label you see in the UI.

Parameter Location Type Required Description
case_id with string Yes Case ID.
field_name with string Yes Custom-field identifier. System-set, typically a UUID.
value with string \| number \| boolean Yes Field value.
owner with string No Case owner. Optional, helps with auto-completion.
version with string No Case version for optimistic concurrency.
- name: set_investigation_owner
  type: cases.setCustomField
  with:
    case_id: "{{ steps.create_case.output.case.id }}"
    field_name: "4b8c9d2e-1a5f-4f7a-9c3b-2d6e8f1a3b5c"
    value: "soc-team"
		

Close a case.

Parameter Location Type Required Description
case_id with string Yes Case ID.
version with string No Case version for optimistic concurrency.
- name: close_case
  type: cases.closeCase
  with:
    case_id: "{{ steps.find.output.cases[0].id }}"
		

To record why a case was closed, pair with cases.addComment beforehand:

- name: note_reason
  type: cases.addComment
  with:
    case_id: "{{ inputs.case_id }}"
    comment: "Closing: duplicate of case {{ inputs.duplicate_of }}."

- name: close
  type: cases.closeCase
  with:
    case_id: "{{ inputs.case_id }}"
		

Add a Markdown-formatted comment to a case.

Parameter Location Type Required Description
case_id with string Yes Case ID.
comment with string Yes Comment body.
- name: add_triage_note
  type: cases.addComment
  with:
    case_id: "{{ steps.create_case.output.case.id }}"
    comment: |
      AI classification: **{{ steps.classify.output.category }}**

      Rationale: {{ steps.classify.output.rationale }}
		

Attach detection alerts to a case. Each entry is an object with alertId and index; the optional rule describes the rule that generated the alert.

Parameter Location Type Required Description
case_id with string Yes Case ID.
alerts with array Yes Array of { alertId, index, rule? } objects.
- name: attach_alert
  type: cases.addAlerts
  with:
    case_id: "{{ steps.create_case.output.case.id }}"
    alerts:
      - alertId: "{{ event.alerts[0]._id }}"
        index: "{{ event.alerts[0]._index }}"
        rule:
          id: "{{ event.rule.id }}"
          name: "{{ event.rule.name }}"
		
Important

alerts takes an array of objects, not an array of ID strings. Each alert object requires both alertId and the index where the alert document lives. Cases uses both to resolve the alert document.

Attach arbitrary event documents to a case. Each entry is { eventId, index }.

Parameter Location Type Required Description
case_id with string Yes Case ID.
events with array Yes Array of { eventId, index } objects.
- name: attach_context_events
  type: cases.addEvents
  with:
    case_id: "{{ steps.create_case.output.case.id }}"
    events:
      - eventId: "{{ steps.search_context.output.hits.hits[0]._id }}"
        index: "{{ steps.search_context.output.hits.hits[0]._index }}"
		

Add observables (indicators of compromise such as IPs, file hashes, domains, or URLs) to a case. typeKey must match one of the built-in observable types in Elastic Security.

Parameter Location Type Required Description
case_id with string Yes Case ID.
observables with array Yes Array of { typeKey, value, description? } objects.
- name: add_iocs
  type: cases.addObservables
  with:
    case_id: "{{ steps.create_case.output.case.id }}"
    observables:
      - typeKey: "observable-type-ipv4"
        value: "{{ event.alerts[0].source.ip }}"
        description: "Source of malicious activity"
      - typeKey: "observable-type-hash-sha256"
        value: "{{ event.alerts[0].file.hash.sha256 }}"
		

The typeKey must match one of the built-in observable type keys. Examples of accepted values include: observable-type-ipv4, observable-type-ipv6, observable-type-url, observable-type-domain, observable-type-hash-sha256, observable-type-hash-md5

Fetch every attachment associated with a case without pagination. Use this when you need the complete set of attachments for decision-making, for example when checking evidence before closing or escalating.

Parameter Location Type Required Description
case_id with string Yes Case ID.

The output is a list of attachments associated with the case you specified.

- name: list_attachments
  type: cases.getAllAttachments
  with:
    case_id: "{{ inputs.case_id }}"
		

Add tags to a case.

Parameter Location Type Required Description
case_id with string Yes Case ID.
tags with string[] Yes Tags to add.

Assign a case to one or more users.

Parameter Location Type Required Description
case_id with string Yes Case ID.
assignees with array Yes Array of { uid } objects.
- name: assign_oncall
  type: cases.assignCase
  with:
    case_id: "{{ steps.create_case.output.case.id }}"
    assignees:
      - uid: "{{ consts.oncall_uid }}"
		

Remove assignees from a case.

Parameter Location Type Required Description
case_id with string Yes Case ID.
assignees with array Yes Array of { uid } objects to remove. Pass an empty array ([]) to remove all assignees from the case.

Update an existing observable on a case.

Parameter Location Type Required Description
case_id with string Yes Case ID.
observable_id with string Yes Observable ID.
value with string Yes Updated value.
description with string \| null No Updated description.

Remove an observable from a case.

Parameter Location Type Required Description
case_id with string Yes Case ID.
observable_id with string Yes Observable ID.

Delete one or more cases permanently, including their attachments and comments.

Parameter Location Type Required Description
case_ids with string[] Yes Array of case IDs to delete.
- name: cleanup
  type: cases.deleteCases
  with:
    case_ids: ["old-case-1", "old-case-2"]
		
Warning

Deleted cases can't be recovered. If you don't want to permanently delete a case, use cases.closeCase instead.

In 9.3, case management lived under the kibana.* namespace. Those step types remain as deprecated aliases so existing workflows keep running, but new workflows must use cases.*:

Deprecated (9.3 alias) Current (9.4)
kibana.createCaseDefaultSpace cases.createCase
kibana.getCaseDefaultSpace cases.getCase
kibana.updateCaseDefaultSpace cases.updateCase
kibana.addCaseCommentDefaultSpace cases.addComment

Refer to Migrate from 9.3 to 9.4 for side-by-side replacement patterns.