Cases

Cases let you open and track issues directly in Kibana: add assignees and tags, set severity and status, attach comments, alerts, and files, and push cases to external incident-management systems. kibana-py exposes the full Cases API as client.cases.

Creating Cases

from kibana import Kibana

client = Kibana("http://localhost:5601", api_key="your_api_key")

case = client.cases.create(
    title="Suspicious login activity",
    description="Multiple failed logins detected from unusual locations.",
    tags=["security", "auth"],
    severity="high",
)

case_id = case.body["id"]
case_version = case.body["version"]
print(f"Created case {case_id} (status: {case.body['status']})")

Key arguments:

  • owner — the application that owns the case: "cases" (Stack Management, the default), "observability", or "securitySolution"

  • severity"low" (default), "medium", "high", or "critical"

  • connector — an external incident-management connector ({"id", "name", "type", "fields"}); defaults to the “none” connector

  • settings — e.g. {"syncAlerts": True}; defaults to {"syncAlerts": False}

  • assignees — a list of {"uid": ...} user profile objects (Platinum+ license)

  • category and custom_fields — additional classification

Reading and Searching Cases

# Get a case by ID
case = client.cases.get(case_id=case_id)
print(case.body["title"], case.body["status"])

# Search cases with filters
found = client.cases.find(
    status="open",
    severity="high",
    tags="security",
    search="login",
    sort_field="createdAt",
    sort_order="desc",
    per_page=20,
)
print(f"{found.body['total']} matching cases "
      f"({found.body['count_open_cases']} open)")
for c in found.body["cases"]:
    print(f"  {c['id']}: {c['title']}")

# Aggregations across your cases
tags = client.cases.get_tags()          # all tags in use (JSON array)
reporters = client.cases.get_reporters()  # all reporters (JSON array)

Updating Cases

The Cases update endpoint is a bulk PATCH with optimistic concurrency: every update must include the case’s current version. kibana-py offers a single-case-friendly form:

# Fetch the current version first
case = client.cases.get(case_id=case_id)

updated = client.cases.update(
    id=case_id,
    version=case.body["version"],
    status="in-progress",
    severity="critical",
)
# The response body is a LIST of updated cases
print(updated.body[0]["status"])

To update several cases at once, pass cases with raw API field names:

client.cases.update(
    cases=[
        {"id": "case-1", "version": "WzUsMV0=", "status": "closed"},
        {"id": "case-2", "version": "WzYsMV0=", "tags": ["triaged"]},
    ]
)

Note

A stale version raises ConflictError — re-fetch the case and retry. This protects concurrent workflows from clobbering each other’s changes.

Comments and Alerts

# Add a text comment
updated = client.cases.add_comment(
    case_id=case_id,
    comment="Investigating the failed logins.",
)
print(f"Comments: {updated.body['totalComment']}")

# Attach an alert to the case
client.cases.add_comment(
    case_id=case_id,
    type="alert",
    owner="cases",
    alert_id="alert-uuid",
    index=".alerts-observability.logs.alerts-default",
    rule={"id": "rule-id", "name": "My rule"},
)

# List attachments (paginated)
comments = client.cases.get_comments(case_id=case_id, per_page=10)
for comment in comments.body["comments"]:
    print(comment["type"], comment.get("comment", ""))

# Update / delete comments
first = comments.body["comments"][0]
client.cases.update_comment(
    case_id=case_id,
    id=first["id"],
    version=first["version"],
    comment="Updated comment text.",
)
client.cases.delete_comment(case_id=case_id, comment_id=first["id"])

# Alerts attached to a case, and cases attached to an alert
alerts = client.cases.get_alerts(case_id=case_id)          # JSON array
cases_for_alert = client.cases.get_cases_by_alert(alert_id="alert-uuid")

Attaching Files

with open("evidence.png", "rb") as f:
    client.cases.add_file(
        case_id=case_id,
        file=f.read(),
        filename="evidence.png",
        mime_type="image/png",
    )

Files are stored as externalReference attachments backed by a file saved object.

User Actions (Audit Trail)

Every change to a case is recorded as a user action:

actions = client.cases.find_user_actions(case_id=case_id, sort_order="asc")
for action in actions.body["userActions"]:
    print(action["type"], action["action"], action["created_at"])

External Incident Management

Push a case to a configured connector (Jira, ServiceNow, etc.):

# Find connectors usable with cases (JSON array)
connectors = client.cases.find_connectors()
for conn in connectors.body:
    print(conn["id"], conn["name"])

pushed = client.cases.push(case_id=case_id, connector_id="connector-id")
print(pushed.body["external_service"]["external_url"])

Case Configuration

Configure default connectors, closure behavior, custom fields, and templates per owner:

config = client.cases.get_configuration()

created = client.cases.create_configuration(
    closure_type="close-by-user",
    connector={"id": "none", "name": "none", "type": ".none", "fields": None},
    owner="cases",
)

client.cases.update_configuration(
    configuration_id=created.body["id"],
    version=created.body["version"],
    closure_type="close-by-pushing",
)

Deleting Cases

delete() accepts one ID or a list (max 100):

client.cases.delete(ids=case_id)
client.cases.delete(ids=["case-1", "case-2"])

Space-Scoped Cases

All operations accept space_id, or use a space-scoped client:

case = client.cases.create(
    title="Marketing incident",
    description="...",
    space_id="marketing",
)

marketing = client.space("marketing")
found = marketing.cases.find(status="open")

Complete Example: Case Lifecycle

from kibana import Kibana

with Kibana("http://localhost:5601", api_key="your_api_key") as client:
    # Open a case
    case = client.cases.create(
        title="kbnpy demo case",
        description="Created by kibana-py.",
        tags=["demo"],
        severity="medium",
    )
    case_id = case.body["id"]

    try:
        # Work the case
        client.cases.add_comment(case_id=case_id, comment="Looking into it.")

        current = client.cases.get(case_id=case_id)
        client.cases.update(
            id=case_id,
            version=current.body["version"],
            status="in-progress",
        )

        # Resolve it
        current = client.cases.get(case_id=case_id)
        client.cases.update(
            id=case_id,
            version=current.body["version"],
            status="closed",
        )
    finally:
        client.cases.delete(ids=case_id)

Next Steps

  • Configure Connectors to push cases to external systems

  • Combine cases with Alerting to track alert investigations

  • Browse examples/cases_management.py in the repository for a runnable end-to-end script