Manage incidents
An incident is an episode built around one finding (a Hunt finding, a violation or a data-classification result) on one asset. This guide shows how to pull the open queue into your own tooling, read an incident’s audit history, and assign, comment on or close it from a script.
Incidents and findings are separate
Section titled “Incidents and findings are separate”Each incident row has two statuses that change independently:
statusis the episode lifecycle:openorclosed.finding.statusis the disposition of the underlying finding:open,acknowledged,suppressedorresolved. You change it with the finding endpoints in Findings and violations.
finding is null when the finding is no longer available. Your code should handle that.
List the open queue
Section titled “List the open queue”With no parameters the list returns open incidents sorted by SEVERITY_ASC. That puts critical first, Hunt findings before violations, and oldest first. The filters below are all optional. Severity, finding status and type take comma-separated lists.
| Parameter | Values |
|---|---|
status |
open, closed, all |
finding_status |
open, acknowledged, suppressed, resolved |
severity |
critical, high, medium, low, info |
type |
threat, violation, data_classification |
assignee |
me, unassigned, or a tenant member UUID |
search |
Substring match over handle, finding key, asset name or ID, title and method |
sort_by |
SEVERITY_ASC, SEVERITY_DESC, OPENED_AT_ASC, OPENED_AT_DESC, HANDLE_ASC, HANDLE_DESC, ASSET_NAME_ASC, ASSET_NAME_DESC, ASSIGNEE_ASC, ASSIGNEE_DESC |
limit, offset |
Offset pagination. limit defaults to 20, which is also the maximum. |
This example fetches every unassigned critical or high incident built on a Hunt finding (type=threat), one page at a time:
curl -G "https://acme.app.elastio.com/gateway/api/v2/incidents" \ -H "Authorization: Bearer $ELASTIO_TOKEN" \ --data-urlencode "severity=critical,high" \ --data-urlencode "type=threat" \ --data-urlencode "assignee=unassigned" \ --data-urlencode "sort_by=OPENED_AT_ASC" \ --data-urlencode "limit=20" \ --data-urlencode "offset=0"import os, requests
BASE = "https://acme.app.elastio.com"HEADERS = {"Authorization": f"Bearer {os.environ['ELASTIO_TOKEN']}"}
params = { "severity": "critical,high", "type": "threat", "assignee": "unassigned", "sort_by": "OPENED_AT_ASC", "limit": 20, "offset": 0,}incidents = []while True: resp = requests.get(f"{BASE}/gateway/api/v2/incidents", headers=HEADERS, params=params, timeout=30) resp.raise_for_status() page = resp.json() incidents.extend(page["data"]) params["offset"] += params["limit"] if params["offset"] >= page["total"]: break
for inc in incidents: finding = inc["finding"] or {} print(inc["handle"], finding.get("severity"), finding.get("title"), finding.get("asset_name"))$Base = "https://acme.app.elastio.com"$Headers = @{ Authorization = "Bearer $env:ELASTIO_TOKEN" }
$offset = 0$all = @()do { $uri = "$Base/gateway/api/v2/incidents?severity=critical,high&type=threat&assignee=unassigned&sort_by=OPENED_AT_ASC&limit=20&offset=$offset" $page = Invoke-RestMethod -Uri $uri -Headers $Headers $all += $page.data $offset += 20} while ($offset -lt $page.total)
$all | Select-Object handle, @{ n = "severity"; e = { $_.finding.severity } }, @{ n = "asset"; e = { $_.finding.asset_name } }Example response (trimmed):
{ "total": 3, "data": [ { "id": "6f1c2a3e-8b4d-4e2a-9c1f-0a1b2c3d4e5f", "handle": "INC-000042", "finding_type": "threat", "asset_id": "2b7e9c1d-3f4a-4b5c-8d6e-7f8091a2b3c4", "status": "open", "assignee_id": null, "opened_at": "2026-10-08T14:02:11Z", "last_observed_at": "2026-10-11T09:30:00Z", "closed_at": null, "closure_reason": null, "version": 1, "finding": { "id": "threat:2b7e9c1d-3f4a-4b5c-8d6e-7f8091a2b3c4:ransomware", "class": "threat", "severity": "critical", "status": "open", "asset_name": "prod-db-01", "asset_kind": "ec2", "platform": "aws", "platform_details": { "account_id": "123456789012", "region": "us-east-1" }, "files_affected": 118, … }, … } ]}Build filter chips with facet counts
Section titled “Build filter chips with facet counts”The filters endpoint takes the same filters as the list, without pagination or sort, and returns a count for each value of each facet. Each facet ignores its own filter. So if you filter by severity=critical, the severity facet still shows counts for every severity, while the other facets count only critical incidents.
curl "https://acme.app.elastio.com/gateway/api/v2/incidents/filters?status=open&type=threat" \ -H "Authorization: Bearer $ELASTIO_TOKEN"resp = requests.get( f"{BASE}/gateway/api/v2/incidents/filters", headers=HEADERS, params={"status": "open", "type": "threat"}, timeout=30,)resp.raise_for_status()facets = resp.json()print({f["value"]: f["count"] for f in facets["severity"]})$facets = Invoke-RestMethod -Uri "$Base/gateway/api/v2/incidents/filters?status=open&type=threat" -Headers $Headers$facets.severity | Format-Table value, countExample response (trimmed):
{ "total": 12, "severity": [ { "value": "critical", "count": 3 }, { "value": "high", "count": 9 } ], "finding_status": [ { "value": "open", "count": 10 }, { "value": "acknowledged", "count": 2 } ], "type": [ { "value": "threat", "count": 12 }, … ], "assignee": [ … ], "status": [ … ]}Read an incident and its audit history
Section titled “Read an incident and its audit history”The detail call returns the same fields as a list row, plus history, the append-only audit trail for the episode. Note the version field. Every write in the next section must send the current version, so read the incident right before you change it.
curl "https://acme.app.elastio.com/gateway/api/v2/incidents/6f1c2a3e-8b4d-4e2a-9c1f-0a1b2c3d4e5f" \ -H "Authorization: Bearer $ELASTIO_TOKEN"incident_id = "6f1c2a3e-8b4d-4e2a-9c1f-0a1b2c3d4e5f"resp = requests.get(f"{BASE}/gateway/api/v2/incidents/{incident_id}", headers=HEADERS, timeout=30)resp.raise_for_status()incident = resp.json()print(incident["handle"], incident["status"], "version", incident["version"])for entry in incident["history"]: print(entry.get("at"), entry.get("actor"), entry.get("event"))$incidentId = "6f1c2a3e-8b4d-4e2a-9c1f-0a1b2c3d4e5f"$incident = Invoke-RestMethod -Uri "$Base/gateway/api/v2/incidents/$incidentId" -Headers $Headers$incident.history | Format-Table at, actor, eventExample response (trimmed):
{ "id": "6f1c2a3e-8b4d-4e2a-9c1f-0a1b2c3d4e5f", "handle": "INC-000042", "status": "open", "assignee_id": null, "opened_at": "2026-10-08T14:02:11Z", "version": 1, "finding": { "id": "threat:2b7e9c1d-3f4a-4b5c-8d6e-7f8091a2b3c4:ransomware", "class": "threat", "severity": "critical", … }, "history": [ { "id": "…", "at": "2026-10-08T14:02:11Z", "actor": "…", "event": "…", "details": { … } } ], …}Assign, comment on and close an incident
Section titled “Assign, comment on and close an incident”Assign, comment, close and reopen are all POST calls on the incident. Each one records an audit entry and takes the incident’s current version for optimistic concurrency. If someone else has changed the incident since you read it, the version no longer matches and the call fails. Re-read the incident and try again.
Find someone to assign
Section titled “Find someone to assign”This returns the active tenant members who can be assigned. The spec doesn’t document the response body, so check the API reference or inspect a live response before you parse it.
Assign
Section titled “Assign”The body takes version and assignee_id, both required, plus an optional comment. Send "assignee_id": null to unassign.
curl -X POST "https://acme.app.elastio.com/gateway/api/v2/incidents/6f1c2a3e-8b4d-4e2a-9c1f-0a1b2c3d4e5f/assign" \ -H "Authorization: Bearer $ELASTIO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "version": 1, "assignee_id": "9d8c7b6a-5f4e-4d3c-8b2a-1f0e9d8c7b6a", "comment": "Taking this one during the on-call shift." }'resp = requests.post( f"{BASE}/gateway/api/v2/incidents/{incident_id}/assign", headers=HEADERS, json={ "version": incident["version"], "assignee_id": "9d8c7b6a-5f4e-4d3c-8b2a-1f0e9d8c7b6a", "comment": "Taking this one during the on-call shift.", }, timeout=30,)resp.raise_for_status()$body = @{ version = $incident.version assignee_id = "9d8c7b6a-5f4e-4d3c-8b2a-1f0e9d8c7b6a" comment = "Taking this one during the on-call shift."} | ConvertTo-JsonInvoke-RestMethod -Method Post -Uri "$Base/gateway/api/v2/incidents/$incidentId/assign" ` -Headers $Headers -ContentType "application/json" -Body $bodyAdd a note
Section titled “Add a note”The comment body takes version and comment, both required. Re-read the incident first, because the assignment above changed its version.
curl -X POST "https://acme.app.elastio.com/gateway/api/v2/incidents/6f1c2a3e-8b4d-4e2a-9c1f-0a1b2c3d4e5f/comment" \ -H "Authorization: Bearer $ELASTIO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "version": 2, "comment": "Isolated the instance; restoring from the last clean recovery point." }'incident = requests.get(f"{BASE}/gateway/api/v2/incidents/{incident_id}", headers=HEADERS, timeout=30).json()resp = requests.post( f"{BASE}/gateway/api/v2/incidents/{incident_id}/comment", headers=HEADERS, json={"version": incident["version"], "comment": "Isolated the instance; restoring from the last clean recovery point."}, timeout=30,)resp.raise_for_status()$incident = Invoke-RestMethod -Uri "$Base/gateway/api/v2/incidents/$incidentId" -Headers $Headers$body = @{ version = $incident.version; comment = "Isolated the instance; restoring from the last clean recovery point." } | ConvertTo-JsonInvoke-RestMethod -Method Post -Uri "$Base/gateway/api/v2/incidents/$incidentId/comment" ` -Headers $Headers -ContentType "application/json" -Body $bodyClosing requires version, comment and a reason. The reason must be one of remediated, false_positive, accepted_risk or duplicate. Closing the episode doesn’t change the finding’s disposition. If the problem is fixed, also resolve the finding (see Findings and violations).
curl -X POST "https://acme.app.elastio.com/gateway/api/v2/incidents/6f1c2a3e-8b4d-4e2a-9c1f-0a1b2c3d4e5f/close" \ -H "Authorization: Bearer $ELASTIO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "version": 3, "reason": "remediated", "comment": "Restored from clean recovery point; follow-up hunt found nothing." }'incident = requests.get(f"{BASE}/gateway/api/v2/incidents/{incident_id}", headers=HEADERS, timeout=30).json()resp = requests.post( f"{BASE}/gateway/api/v2/incidents/{incident_id}/close", headers=HEADERS, json={ "version": incident["version"], "reason": "remediated", "comment": "Restored from clean recovery point; follow-up hunt found nothing.", }, timeout=30,)resp.raise_for_status()$incident = Invoke-RestMethod -Uri "$Base/gateway/api/v2/incidents/$incidentId" -Headers $Headers$body = @{ version = $incident.version reason = "remediated" comment = "Restored from clean recovery point; follow-up hunt found nothing."} | ConvertTo-JsonInvoke-RestMethod -Method Post -Uri "$Base/gateway/api/v2/incidents/$incidentId/close" ` -Headers $Headers -ContentType "application/json" -Body $bodyTo undo a close, call POST /gateway/api/v2/incidents/{id}/reopen with version and comment. The spec doesn’t document a success response body for any of these four calls. Check the HTTP status, then re-read the incident to see its new state.
Set how long incident history is kept
Section titled “Set how long incident history is kept”Incident history retention is a tenant-wide setting. The body takes retention_days, an integer of at most 730. Read the current value with GET /gateway/api/v2/incident-settings.
curl -X PUT "https://acme.app.elastio.com/gateway/api/v2/incident-settings" \ -H "Authorization: Bearer $ELASTIO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "retention_days": 365 }'resp = requests.put( f"{BASE}/gateway/api/v2/incident-settings", headers=HEADERS, json={"retention_days": 365}, timeout=30,)resp.raise_for_status()Invoke-RestMethod -Method Put -Uri "$Base/gateway/api/v2/incident-settings" ` -Headers $Headers -ContentType "application/json" -Body (@{ retention_days = 365 } | ConvertTo-Json)All endpoints
Section titled “All endpoints”Incidents
10 operations in the reference →- GET
/gateway/api/v2/incident-assigneesList active tenant members eligible for assignment - GET
/gateway/api/v2/incidentsList retained incident episodes - GET
/gateway/api/v2/incidents/filtersGet contextual filter options for incidents - GET
/gateway/api/v2/incidents/{id}Get an incident and its retained audit history - POST
/gateway/api/v2/incidents/{id}/closeClose an incident - POST
/gateway/api/v2/incidents/{id}/reopenReopen an incident - POST
/gateway/api/v2/incidents/{id}/commentComment on an incident - POST
/gateway/api/v2/incidents/{id}/assignAssign an incident - GET
/gateway/api/v2/incident-settingsGet tenant incident history retention - PUT
/gateway/api/v2/incident-settingsSet tenant incident history retention, at most 730 days