Skip to content
Try the API

Run a hunt

Start a hunt of a live asset or backup on demand, or hunt backwards through an asset’s recovery points to find the last clean one. Then follow the hunt until it finishes and pull what it found.

  • A personal access token with access to hunts and Hunt findings. Starting a hunt needs write access. See Authentication.
  • The cloud identifiers of the target, such as the EC2 instance ID, AWS account and region. Find assets returns them.
  • For AWS targets, a Cloud Connector deployed in that account and region. See Connect cloud accounts.

POST /gateway/api/v1/scans/schedule (Schedule hunts and investigations) takes a scans array. Each entry picks a target with a type discriminator and sets what to look for in scan_type. Supported type values:

Platform type values
AWS ec2, aws_ebs, aws_ebs_snapshot, aws_efs, aws_s3, aws_backup_ec2_rp, aws_backup_ebs_rp, aws_ec2_ami
Elastio recovery points erp_scan
Azure azure_vm, azure_managed_disk, azure_blob_container, azure_file_share, azure_machine_image
IBM ibm_cos_bucket
GCP gcp_compute_vm, gcp_compute_disk, gcp_cloud_storage_bucket, gcp_compute_machine_image

For most targets, scan_type accepts malware, ransomware, entropy, data_classification, hunt with hunt_rules, and pursuit with an optional pursuit_playbook. At least one option must be true, hunt_rules must be non-empty, or a Pursuit playbook must be set. erp_scan is the exception: it takes malware, ransomware and fs_check, all three required. Custom hunt rules aren’t available for on-demand Azure, IBM or GCP hunts.

POST
/gateway/api/v1/scans/scheduleSchedule hunts and investigations
Try it
Terminal window
curl -X POST "https://acme.app.elastio.com/gateway/api/v1/scans/schedule" \
-H "Authorization: Bearer $ELASTIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"scans": [
{
"type": "ec2",
"aws_instance_id": "i-0abc123def4567890",
"aws_account_id": "123456789012",
"aws_region": "us-east-1",
"scan_type": { "malware": true, "ransomware": true }
}
]
}'
{
"results": [
{
"result": "job_id",
"job_id": "5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
"resource": "aws_ec2",
"aws_ec2": { "aws_instance_id": "i-0abc123def4567890", "aws_region": "us-east-1", "aws_account_id": "123456789012" }
}
]
}

Each result’s result field tells you which other field is set:

  • job_id: the hunt’s job ID. Use it to poll the hunt and read what it found.
  • error_message: this hunt couldn’t be scheduled. Other entries in the same request can still succeed.
  • queued: Azure, IBM and GCP hunts are queued on a standalone cluster. You get cluster_name and position, but no job ID to poll.

Start a hunt across recovery points to work backwards in time through an AWS asset’s backups. Without oldest_timestamp it keeps going until it finds a clean one. With oldest_timestamp it only hunts backups newer than that time. Set exactly one property of asset_kind:

  • ec2_backup: AWS Backup recovery points of an EC2 instance
  • ec2_drs: AWS DRS recovery snapshots of an EC2 instance
  • ebs: EBS snapshots of a volume
  • ebs_backup: AWS Backup recovery points of an EBS volume

scan_type is one of none, malware, ransomware, encryption-detection, ransomware-malware, ransomware-encryption-detection, malware-encryption-detection or full. max_parallel_scan_jobs can be 1–50. aws_backup_vault defaults to Default, and asset_account_id defaults to the connector’s account.

POST
/gateway/scans/v1/threat-huntStart a hunt across recovery points
Try it
Terminal window
curl -X POST "https://acme.app.elastio.com/gateway/scans/v1/threat-hunt" \
-H "Authorization: Bearer $ELASTIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tenant_name": "acme",
"cloud_connector": { "aws_account_id": "123456789012", "aws_region": "us-east-1" },
"asset_kind": { "ec2_backup": { "instance_id": "i-0abc123def4567890" } },
"scan_type": "ransomware-malware",
"max_parallel_scan_jobs": 5
}'
{
"success": true,
"message": "…",
"job_id": "…",
"aws_backup_vault": "Default",
"timestamp": "2026-10-12T09:15:03Z"
}

tenant_name is your tenant identifier (in these examples, the acme subdomain). The hunt runs asynchronously. If submission fails, success is false and error explains why.

Read the hunt result through the asset it targeted. The response lists every entry in scans, each with its own kind, status and type, plus the job’s overall health and the sources that triggered it.

GET
/gateway/api/v1/assets/{assetId}/scanjobs/{scanJobId}Get a hunt for an asset
Try it
Terminal window
curl "https://acme.app.elastio.com/gateway/api/v1/assets/6f1c2a9e-3b4d-4e8f-9a7b-1c2d3e4f5a6b/scanjobs/5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d" \
-H "Authorization: Bearer $ELASTIO_TOKEN"
{
"job_id": "5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
"scans": [
{
"id": "8e7d6c5b-4a3f-4e2d-9c1b-0a9f8e7d6c5b",
"target": { "id": "6f1c2a9e-3b4d-4e8f-9a7b-1c2d3e4f5a6b", "kind_tag": "asset" },
"job_id": "5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
"kind": "ransomware_scan",
"status": "…",
"type": "direct",
"created_at": "2026-10-12T09:15:04Z",
"updated_at": "2026-10-12T09:31:47Z"
}
],
"health": "…",
"type": "direct",
"timestamp": "2026-10-12T09:31:47Z",
"triggered_by_sources": [],
"triggered_by": null
}
  • Hunts take minutes, not seconds. Poll every 30–60 seconds and back off for long-running jobs. Don’t poll in a tight loop.
  • Give up after a timeout that suits the asset’s size, and log the job ID so you can come back to it.
  • The spec doesn’t list the possible status values for an entry in scans. Check the values your tenant returns before you hard-code a terminal state.
  • GET /gateway/api/v1/assets/{assetId}/scanjobs lists recent hunt results for an asset. Filter by kind, type, backupType, triggerSource or days, and page with pageSize and pageToken. This is useful when you don’t have the job ID, for example for hunts a policy started.
  • Azure, IBM and GCP hunts that come back as queued have no job ID to poll. Follow them through the asset’s hunt history instead.

When the hunt has finished, page through its findings. Filter by asset_id, threat_kind, threat_status (comma-separated) or suppressed. Pagination uses page_size (default 10) with next_page_token and prev_page_token.

GET
/gateway/api/v1/scanjobs/{scanJobId}/threatsList what a hunt found
Try it
Terminal window
curl "https://acme.app.elastio.com/gateway/api/v1/scanjobs/5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d/threats?page_size=50&suppressed=false" \
-H "Authorization: Bearer $ELASTIO_TOKEN"
{
"status": 200,
"total": 1,
"pagination": { "next_page_token": "", "prev_page_token": "" },
"data": [
{
"id": "e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b",
"cc_id": "…",
"backup_ids": ["4b3a2c1d-0e9f-4a8b-9c7d-6e5f4a3b2c1d"],
"name": "…",
"location": "/var/www/uploads/invoice.pdf.exe",
"kind": "…",
"status": "…",
"detected_at": "2026-10-12T09:31:40Z",
"ignored_at": null,
"resolved_at": null,
"detected_by_scan_ids": ["8e7d6c5b-4a3f-4e2d-9c1b-0a9f8e7d6c5b"],
"suppressed_until": null,
"suppression_reason": null,
"file_name": "invoice.pdf.exe",
"sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
}
],
"message": "OK"
}

Related reads for the same hunt:

  • GET /gateway/api/v1/scanjobs/{scanJobId}/backups: the backups the hunt covered, with their check statuses and protected assets.
  • GET /gateway/api/v2/scanjobs/{scanJobId}/threats/pursuit/findings: Pursuit findings from an investigation that ran in this job. See Investigate with Pursuit.
  • GET /gateway/api/v2/scanjobs/{scanJobId}/threats/custom/findings: custom hunt matches from this hunt, one row per target and rule. See Hunt rules.

To suppress a finding you’ve triaged, see Review Hunt findings.