Skip to main content
GET
/
api
/
scans
/
{id}
/
progress
/
stream
curl -N -H "Authorization: Bearer YOUR_API_TOKEN" \
  "https://api.heimdall.dev/api/scans/550e8400-e29b-41d4-a716-446655440000/progress/stream"
event: stage_update
data: {"scan_id":"550e8400-e29b-41d4-a716-446655440000","stage":"ingest","status":"running","timestamp":"2026-03-12T10:00:05Z"}

event: stage_update
data: {"scan_id":"550e8400-e29b-41d4-a716-446655440000","stage":"ingest","status":"completed","timestamp":"2026-03-12T10:01:23Z"}

event: status_change
data: {"scan_id":"550e8400-e29b-41d4-a716-446655440000","status":"hunting","timestamp":"2026-03-12T10:01:25Z","finding_count":0,"critical":0,"high":0,"medium":0,"low":0}

event: stage_update
data: {"scan_id":"550e8400-e29b-41d4-a716-446655440000","stage":"hunt","status":"running","timestamp":"2026-03-12T10:01:25Z"}

event: finding_added
data: {"scan_id":"550e8400-e29b-41d4-a716-446655440000","finding_id":"3f7a8b9c-0d1e-2f3a-4b5c-6d7e8f9a0b1c","title":"SQL Injection in user authentication","severity":"critical"}

: keepalive

event: stage_update
data: {"scan_id":"550e8400-e29b-41d4-a716-446655440000","stage":"hunt","status":"completed","timestamp":"2026-03-12T10:10:45Z"}

event: scan_complete
data: {"scan_id":"550e8400-e29b-41d4-a716-446655440000","finding_count":42,"critical":5,"high":12,"medium":18,"low":7,"timestamp":"2026-03-12T10:15:30Z"}

Path Parameters

id
string
required
The unique identifier (UUID) of the scan to monitor

Response

This endpoint returns a Server-Sent Events (SSE) stream that sends real-time updates about the scan progress.

Connection Details

  • Content-Type: text/event-stream
  • Cache-Control: no-cache
  • Connection: Keep-alive stream
  • Keepalive Interval: 15 seconds

Initial State

When you first connect, the endpoint sends the current scan state fetched from the database, including:
  • Current scan status and finding counts
  • Status of all scan stages (ingest, tyr, static_analysis, etc.)
  • Any error messages if the scan has failed

Event Types

The stream emits the following event types:
status_change
event
Emitted when the overall scan status changesData fields:
  • scan_id (string): The scan UUID
  • status (string): New status value
  • timestamp (string): ISO 8601 timestamp
  • finding_count (integer): Total findings discovered
  • critical (integer): Critical severity count
  • high (integer): High severity count
  • medium (integer): Medium severity count
  • low (integer): Low severity count
stage_update
event
Emitted when a scan stage (e.g., ingest, hunt, garmr) changes statusData fields:
  • scan_id (string): The scan UUID
  • stage (string): Stage name (e.g., “ingest”, “tyr”, “hunt”)
  • status (string): Stage status (“pending”, “running”, “completed”, “failed”)
  • timestamp (string): ISO 8601 timestamp
  • error (string, optional): Error message if stage failed
finding_added
event
Emitted when a new vulnerability finding is discoveredData fields:
  • scan_id (string): The scan UUID
  • finding_id (string): The finding UUID
  • title (string): Brief title of the vulnerability
  • severity (string): Severity level (“critical”, “high”, “medium”, “low”)
scan_complete
event
Emitted when the scan finishes successfully. This is a terminal event - the stream will close after sending it.Data fields:
  • scan_id (string): The scan UUID
  • finding_count (integer): Total findings discovered
  • critical (integer): Critical severity count
  • high (integer): High severity count
  • medium (integer): Medium severity count
  • low (integer): Low severity count
  • timestamp (string): ISO 8601 timestamp
error
event
Emitted when the scan fails. This is a terminal event - the stream will close after sending it.Data fields:
  • scan_id (string): The scan UUID
  • error (string): Error message describing what went wrong
  • timestamp (string): ISO 8601 timestamp

SSE Format

Events follow the standard SSE format:
event: status_change
data: {"scan_id":"550e8400-e29b-41d4-a716-446655440000","status":"running","timestamp":"2026-03-12T10:00:00Z"}

event: stage_update
data: {"scan_id":"550e8400-e29b-41d4-a716-446655440000","stage":"ingest","status":"running","timestamp":"2026-03-12T10:00:05Z"}

: keepalive

Keepalive Messages

The server sends keepalive comments (: keepalive\n\n) every 15 seconds to prevent connection timeouts.

Stream Termination

The stream automatically closes when:
  • A scan_complete event is sent (successful completion)
  • An error event is sent (scan failed)
  • The client disconnects
  • The scan is cancelled
curl -N -H "Authorization: Bearer YOUR_API_TOKEN" \
  "https://api.heimdall.dev/api/scans/550e8400-e29b-41d4-a716-446655440000/progress/stream"
event: stage_update
data: {"scan_id":"550e8400-e29b-41d4-a716-446655440000","stage":"ingest","status":"running","timestamp":"2026-03-12T10:00:05Z"}

event: stage_update
data: {"scan_id":"550e8400-e29b-41d4-a716-446655440000","stage":"ingest","status":"completed","timestamp":"2026-03-12T10:01:23Z"}

event: status_change
data: {"scan_id":"550e8400-e29b-41d4-a716-446655440000","status":"hunting","timestamp":"2026-03-12T10:01:25Z","finding_count":0,"critical":0,"high":0,"medium":0,"low":0}

event: stage_update
data: {"scan_id":"550e8400-e29b-41d4-a716-446655440000","stage":"hunt","status":"running","timestamp":"2026-03-12T10:01:25Z"}

event: finding_added
data: {"scan_id":"550e8400-e29b-41d4-a716-446655440000","finding_id":"3f7a8b9c-0d1e-2f3a-4b5c-6d7e8f9a0b1c","title":"SQL Injection in user authentication","severity":"critical"}

: keepalive

event: stage_update
data: {"scan_id":"550e8400-e29b-41d4-a716-446655440000","stage":"hunt","status":"completed","timestamp":"2026-03-12T10:10:45Z"}

event: scan_complete
data: {"scan_id":"550e8400-e29b-41d4-a716-446655440000","finding_count":42,"critical":5,"high":12,"medium":18,"low":7,"timestamp":"2026-03-12T10:15:30Z"}

Notes

  • The SSE stream is designed for fan-out to multiple clients - multiple connections to the same scan will all receive updates
  • If events are produced faster than they can be consumed, the broadcast channel may lag and skip events (you’ll receive a lag notification)
  • The broadcast channel is automatically cleaned up after the scan completes
  • For historical scan data or to check the current state without streaming, use the Get Scan endpoint instead

Build docs developers (and LLMs) love