Skip to content
Try the API

Findings and violations

A finding is something Elastio wants you to act on: a Hunt finding on an asset, a policy violation, or a sensitive-data result. This guide covers how to count and list findings, and how to move them through their lifecycle from a script, including restoring a compromised asset from a clean recovery point.

Every finding has a disposition of open, acknowledged, suppressed or resolved. The finding endpoints all take a findingId, which comes in one of these forms:

Finding class findingId format Where to get it
Hunt finding (Elastio hunts and Pursuit) threat:{asset_id}:{hunt} finding.id on an incident
Hunt finding (custom hunts) threat:{asset_id}:custom:{finding_id} finding.id on an incident
Violation The violation’s UUID id on a row from GET /gateway/api/v2/violations

Not every transition is allowed for every class:

  • Acknowledge marks that an analyst owns the finding. It’s optional, and no other transition requires it.
  • Suppress silences a finding that isn’t actionable. It requires a reason and an expiry. A suppressed finding doesn’t re-alert on any channel.
  • Resolve records that the problem is fixed. Hunt findings only. Violations are resolved by the evaluator, and resolving a violation ID returns 409 UNSUPPORTED_FINDING_CLASS. If a resolved finding is found again, it reopens automatically.
  • Recover restores the asset from a clean recovery point and resolves the finding when the restore job succeeds. Hunt findings only.
  • Reopen moves a suppressed or resolved finding back to open. Calling it on an open or acknowledged finding returns 409.
GET
/gateway/api/v2/findings/countGet findings counts
Try it

This returns how many Hunt findings, open violations and assets with sensitive data you can see, plus how many unique assets are affected in each bucket. It’s a cheap call for a dashboard tile or a health check.

Terminal window
curl "https://acme.app.elastio.com/gateway/api/v2/findings/count" \
-H "Authorization: Bearer $ELASTIO_TOKEN"

Example response:

{
"threats": 7,
"violations": 54,
"data_classification": 12,
"affected_assets": {
"threats": 4,
"violations": 31,
"data_classification": 12,
"total": 40
}
}
GET
/gateway/api/v2/violationsGet list of open asset violations
Try it

The violations list returns open violations by default. Pass status=all, or a single status (open, acknowledged, suppressed, resolved), to see others. violation_code, severity, category, policy_id and asset_id each take comma-separated values. Use policy_id=unpoliced to find assets that no policy covers. The list uses token pagination: page_size (default 10, max 100) and next_page_token.

Terminal window
curl -G "https://acme.app.elastio.com/gateway/api/v2/violations" \
-H "Authorization: Bearer $ELASTIO_TOKEN" \
--data-urlencode "severity=critical,high" \
--data-urlencode "page_size=100"

Example response (trimmed):

{
"total": 18,
"data": [
{
"id": "0c3e5a7b-1d2f-4a6b-9c8d-7e6f5a4b3c2d",
"asset_id": "2b7e9c1d-3f4a-4b5c-8d6e-7f8091a2b3c4",
"asset_name": "prod-db-01",
"asset_kind": "ec2",
"platform": "aws",
"platform_details": { "account_id": "123456789012", "region": "us-east-1" },
"policies": [],
"violation_code": "…",
"title": "…",
"category": "…",
"severity": "critical",
"status": "open",
"created_at": "2026-10-01T06:00:00Z",
"last_evaluated_at": "2026-10-12T06:00:00Z",
"suppressed_until": null,
"resolved_at": null,
…
}
],
"pagination": { "next_page_token": "…" }
}
POST
/gateway/api/v2/findings/{findingId}/suppressSuppress a finding
Try it

reason and until are both required. until is an RFC 3339 UTC timestamp and must be in the future. By convention, reason takes the form <disposition>: <note>. A successful call returns 204 No Content.

Terminal window
curl -X POST "https://acme.app.elastio.com/gateway/api/v2/findings/0c3e5a7b-1d2f-4a6b-9c8d-7e6f5a4b3c2d/suppress" \
-H "Authorization: Bearer $ELASTIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "reason": "accepted risk: legacy test bucket, decommission scheduled", "until": "2026-12-31T00:00:00Z" }'

Acknowledge (/acknowledge) and resolve (/resolve) work the same way. Both take an optional note of up to 1024 characters. Reopen (/reopen) takes an optional reason. All three return 204 on success.

Recover an asset from a clean recovery point

Section titled “Recover an asset from a clean recovery point”
POST
/gateway/api/v2/findings/{findingId}/recoverRecover a finding by restoring from a clean recovery point
Try it

Recover schedules a restore of the finding’s asset and returns 202 Accepted with a job handle. recovery_point_id is required. The recovery point must protect the finding’s asset, and its health must be clean. When the job succeeds, the finding is resolved automatically and the restore is recorded in its history. This only works for Hunt findings.

Terminal window
curl -X POST "https://acme.app.elastio.com/gateway/api/v2/findings/threat:2b7e9c1d-3f4a-4b5c-8d6e-7f8091a2b3c4:ransomware/recover" \
-H "Authorization: Bearer $ELASTIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "recovery_point_id": "5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d", "note": "INC-000042" }'

Example response (202 Accepted):

{
"job_id": "7e6f5a4b-3c2d-4e1f-9a8b-0c1d2e3f4a5b",
"finding_id": "threat:2b7e9c1d-3f4a-4b5c-8d6e-7f8091a2b3c4:ransomware",
"recovery_point_id": "5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
"state": "scheduled"
}

Follow the restore in the jobs catalog. See Track jobs.

GET
/gateway/api/v2/findings/{findingId}/status-logGet a finding's status log
Try it

The status log is an append-only record of every transition, newest first. It includes automatic ones: suppression expiry, a finding being found again, and recover completion. It uses token pagination (page_size, next_page_token).

Terminal window
curl "https://acme.app.elastio.com/gateway/api/v2/findings/0c3e5a7b-1d2f-4a6b-9c8d-7e6f5a4b3c2d/status-log" \
-H "Authorization: Bearer $ELASTIO_TOKEN"

Example response (trimmed):

{
"total": 2,
"data": [
{
"id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"at": "2026-10-12T10:15:00Z",
"actor": "analyst@example.com",
"from": "open",
"to": "suppressed",
"verb": "suppress",
"source": "manual",
"reason": "accepted risk: legacy test bucket, decommission scheduled",
"until": "2026-12-31T00:00:00Z",
"note": null,
"job_id": null,
"recovery_point_id": null
},
…
],
"pagination": { "next_page_token": "…" }
}

To review dispositions across the tenant, list them with GET /gateway/api/v2/findings/suppressions (filter by class; add include_expired=true to include lapsed suppressions) and GET /gateway/api/v2/findings/resolutions (filter by class and by source=manual or source=recover).

The v1 Issues endpoints (GET /gateway/api/v1/issues and GET /gateway/api/v1/issues-filters) list protection-coverage problems per asset. You can filter by issue_types, asset_type, platform, account_ids, policy_coverage (covered, not_covered) and tags, and pass type=asset to get one row per affected asset instead of one per issue. Call the filters endpoint to get the valid filter values for your tenant.