Scan Results & Status
Track scan progress, retrieve findings, and understand the complete scan lifecycle from submission to completion.
Scan Status Lifecycle
Every scan passes through a well-defined set of states:
┌──────────┐
POST /scans ──→ │ queued │
└────┬─────┘
│
┌────▼─────┐
│ running │──── POST /:id/cancel ──→ cancelled
└────┬─────┘
│
┌──────────┼──────────┐
│ │
┌─────▼──────┐ ┌──────▼─────┐
│ completed │ │ failed │
└────────────┘ └────────────┘
| Status | Description | Results Available | Terminal |
|---|---|---|---|
queued | Request accepted, waiting for scanner capacity | No | No |
running | Scanner is actively executing | No (partial progress available) | No |
completed | Scan finished successfully | Yes | Yes |
failed | Scan encountered a fatal error | Error details available | Yes |
cancelled | Scan was cancelled by user | Partial results may be available | Yes |
Check Scan Status
Endpoint
GET /api/v1/scans/:scanId
Required scope: scans:read
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
scanType | string | nmap | The scan engine type (must match the original scan) |
Request
curl -X GET "https://api.cert-ix.com/scan-api/api/v1/scans/$SCAN_ID?scanType=nmap" \
-H "X-API-Key: $CERTIX_API_KEY"
Response — Running
{
"success": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"scanType": "nmap",
"name": "Weekly network audit",
"target": "example.com",
"status": "running",
"progress": 67,
"createdAt": "2026-03-06T10:00:00Z",
"startedAt": "2026-03-06T10:00:02Z"
}
}
Response — Completed
{
"success": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"scanType": "nmap",
"status": "completed",
"progress": 100,
"resultCount": 12,
"durationMs": 135000,
"createdAt": "2026-03-06T10:00:00Z",
"startedAt": "2026-03-06T10:00:02Z",
"completedAt": "2026-03-06T10:02:15Z"
}
}
Response — Failed
{
"success": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"scanType": "nmap",
"status": "failed",
"progress": 23,
"error": "Target unreachable: connection timed out after 120s",
"durationMs": 120340
}
}
Always pass the correct scanType query parameter matching the engine used when creating the scan. The default is nmap, so if your scan used zap, you must specify ?scanType=zap or you'll get a 404 SCAN_NOT_FOUND error.
Retrieve Results
Once a scan reaches completed status, full results are available.
Endpoint
GET /api/v1/scans/:scanId/results
Required scope: results:read
Request
curl -X GET "https://api.cert-ix.com/scan-api/api/v1/scans/$SCAN_ID/results?scanType=nmap" \
-H "X-API-Key: $CERTIX_API_KEY"
Response (200 OK)
{
"success": true,
"data": {
"scanId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"scanType": "nmap",
"target": "example.com",
"status": "completed",
"startedAt": "2026-03-06T10:00:02Z",
"completedAt": "2026-03-06T10:02:15Z",
"results": { ... }
}
}
The structure of the results field varies by scan engine — see the schemas below.
Result Schemas by Engine
Nmap Results
{
"hosts": [
{
"ip": "93.184.216.34",
"hostname": "example.com",
"state": "up",
"os": { "name": "Linux", "version": "5.x", "accuracy": 95 },
"ports": [
{
"port": 80,
"protocol": "tcp",
"state": "open",
"service": "http",
"version": "nginx 1.25.4",
"scripts": [{ "id": "http-title", "output": "Example Domain" }]
}
]
}
],
"stats": {
"hostsUp": 1,
"hostsDown": 0,
"openPorts": 2,
"closedPorts": 1022,
"filteredPorts": 0
}
}
ZAP Results
{
"alerts": [
{
"name": "Cross-Site Scripting (Reflected)",
"risk": "High",
"confidence": "Medium",
"description": "Cross-site Scripting (XSS) is an attack technique...",
"solution": "Validate all input and encode output...",
"cweid": 79,
"wascid": 8,
"instances": [
{
"uri": "https://app.example.com/search",
"method": "GET",
"param": "q",
"attack": "<script>alert(1)</script>",
"evidence": "<script>alert(1)</script>"
}
]
}
],
"summary": { "high": 2, "medium": 5, "low": 12, "informational": 8, "total": 27 }
}
Trivy Results
{
"vulnerabilities": [
{
"vulnerabilityID": "CVE-2024-1234",
"pkgName": "openssl",
"installedVersion": "3.0.11",
"fixedVersion": "3.0.13",
"severity": "CRITICAL",
"title": "OpenSSL: Buffer overflow in X.509 certificate verification",
"cvss": {
"nvd": { "v3Score": 9.8, "v3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" }
}
}
],
"summary": { "critical": 1, "high": 3, "medium": 7, "low": 2, "total": 13 }
}
Nuclei Results
{
"findings": [
{
"templateId": "CVE-2023-44487",
"name": "HTTP/2 Rapid Reset Attack",
"severity": "high",
"type": "http",
"host": "https://api.example.com",
"matchedAt": "https://api.example.com/",
"tags": ["cve", "cve2023", "dos", "http2"]
}
],
"summary": { "critical": 0, "high": 1, "medium": 3, "low": 5, "info": 12, "total": 21 }
}
theHarvester Results
{
"emails": ["[email protected]", "[email protected]"],
"subdomains": ["www.example.com", "mail.example.com", "api.example.com"],
"ips": ["93.184.216.34"],
"hosts": [{ "hostname": "www.example.com", "ip": "93.184.216.34" }],
"summary": { "emailsFound": 2, "subdomainsFound": 3, "ipsFound": 1 }
}
Sentinel Results
Sentinel aggregates results from multiple engines into a unified report:
{
"overallRiskScore": 7.2,
"riskLevel": "high",
"enginesUsed": ["nmap", "nuclei", "harvester"],
"executionTime": "12m 34s",
"correlatedFindings": [
{
"title": "Exposed Admin Panel with Known CVE",
"severity": "critical",
"engines": ["nmap", "nuclei"],
"description": "Port 8080 is open (nmap) running a version affected by CVE-2024-1234 (nuclei)",
"recommendation": "Restrict port 8080 access and update the application"
}
],
"summary": { "critical": 1, "high": 4, "medium": 8, "low": 15, "total": 50 }
}
Polling Strategy
When polling for scan completion, use an adaptive strategy to balance responsiveness and API efficiency:
| Phase | Interval | Duration |
|---|---|---|
| Initial (0–2 min) | Every 5 seconds | Quick feedback for short scans |
| Active (2–10 min) | Every 15 seconds | Most scans complete in this window |
| Extended (10–60 min) | Every 30 seconds | Deep or full scans |
| Long-running (60+ min) | Every 60 seconds | Large network scans or Sentinel |
Implementation Example
import time
import requests
def poll_scan(base_url, api_key, scan_id, scan_type="nmap"):
"""Poll scan status with adaptive intervals."""
headers = {"X-API-Key": api_key}
url = f"{base_url}/scans/{scan_id}?scanType={scan_type}"
start = time.time()
terminal_statuses = {"completed", "failed", "cancelled"}
while True:
response = requests.get(url, headers=headers)
data = response.json()["data"]
status = data["status"]
progress = data.get("progress", 0)
print(f"Status: {status} | Progress: {progress}%")
if status in terminal_statuses:
return data
elapsed = time.time() - start
if elapsed < 120:
interval = 5
elif elapsed < 600:
interval = 15
elif elapsed < 3600:
interval = 30
else:
interval = 60
time.sleep(interval)
For production integrations, use webhooks instead of polling. Webhooks are more efficient and provide instant notifications.
Real-Time Notifications
Instead of polling, configure webhooks to receive push notifications when scan events occur:
| Event | Trigger |
|---|---|
scan.started | Scan transitions from queued to running |
scan.completed | Scan finishes successfully |
scan.failed | Scan encounters a fatal error |
scan.cancelled | Scan is cancelled |
See Webhooks for setup instructions.
Next Steps: