Skip to main content
surfbot.

Scans

API endpoints for triggering, managing, and monitoring scans.

Trigger Scan

POST /api/v1/scans

Starts a scan for a verified domain. The scan is queued and processed asynchronously.

curl -X POST https://api.surfbot.io/api/v1/scans \
  -H "X-API-Key: sb_live_abc123def456" \
  -H "Content-Type: application/json" \
  -d '{"domain_id": "550e8400-e29b-41d4-a716-446655440000", "profile": "standard"}'

Request Body:

FieldTypeRequiredDescription
domain_idstringYesUUID of the domain to scan
typestringNodiscovery (default) or full
profilestringNopassive, standard (default), or deep

Response (202):

{
  "id": "770e8400-e29b-41d4-a716-446655440000",
  "domain_id": "550e8400-e29b-41d4-a716-446655440000",
  "type": "discovery",
  "status": "queued",
  "phase": "",
  "progress": 0,
  "stats": {
    "subdomains_found": 0,
    "ips_resolved": 0,
    "ports_scanned": 0,
    "open_ports": 0,
    "http_probed": 0,
    "tech_detected": 0,
    "cdn_detected": 0,
    "takeover_risks": 0,
    "findings_total": 0,
    "findings_critical": 0,
    "findings_high": 0,
    "findings_medium": 0,
    "findings_low": 0,
    "findings_info": 0
  },
  "tier": "free",
  "created_at": "2026-03-15T10:05:00Z"
}

Scan limits by plan:

PlanConcurrent ScansDaily Scans
Free12
Hunter310
Pro1050
Team25Unlimited
Enterprise50Unlimited

When a limit is reached:

{
  "error": "concurrent scan limit reached",
  "limit": 1
}

List Scans

GET /api/v1/scans

Returns scans for your organization, optionally filtered by domain.

curl -H "X-API-Key: sb_live_abc123def456" \
  "https://api.surfbot.io/api/v1/scans?domain_id=550e8400-e29b-41d4-a716-446655440000&limit=10"

Query Parameters:

ParameterTypeDescription
domain_idstringFilter scans by domain UUID
limitintegerMax results (default: 100, max: 1000)

Response (200):

{
  "scans": [
    {
      "id": "770e8400-e29b-41d4-a716-446655440000",
      "domain_id": "550e8400-e29b-41d4-a716-446655440000",
      "domain_name": "example.com",
      "type": "discovery",
      "status": "completed",
      "phase": "done",
      "progress": 100,
      "stats": {
        "subdomains_found": 32,
        "ips_resolved": 28,
        "ports_scanned": 2800,
        "open_ports": 64,
        "http_probed": 48,
        "tech_detected": 12,
        "cdn_detected": 3,
        "takeover_risks": 0,
        "findings_total": 5,
        "findings_critical": 0,
        "findings_high": 1,
        "findings_medium": 2,
        "findings_low": 1,
        "findings_info": 1
      },
      "tier": "free",
      "started_at": "2026-03-15T10:05:01Z",
      "finished_at": "2026-03-15T10:17:30Z",
      "created_at": "2026-03-15T10:05:00Z"
    }
  ],
  "count": 1
}

Get Scan Detail

GET /api/v1/scans/:id

Returns detailed status for a specific scan, including phase, progress, and stats.

curl -H "X-API-Key: sb_live_abc123def456" \
  https://api.surfbot.io/api/v1/scans/770e8400-e29b-41d4-a716-446655440000

Response (200):

{
  "id": "770e8400-e29b-41d4-a716-446655440000",
  "domain_id": "550e8400-e29b-41d4-a716-446655440000",
  "domain_name": "example.com",
  "type": "discovery",
  "status": "running",
  "phase": "scanning_ports",
  "progress": 45.5,
  "stats": {
    "subdomains_found": 32,
    "ips_resolved": 28,
    "ports_scanned": 1400,
    "open_ports": 32,
    "http_probed": 0,
    "tech_detected": 0,
    "cdn_detected": 0,
    "takeover_risks": 0,
    "findings_total": 0,
    "findings_critical": 0,
    "findings_high": 0,
    "findings_medium": 0,
    "findings_low": 0,
    "findings_info": 0
  },
  "tier": "free",
  "started_at": "2026-03-15T10:05:01Z",
  "created_at": "2026-03-15T10:05:00Z"
}

Scan phases: discovering, resolving, scanning_ports, probing_http, done

Scan statuses: queued, running, completed, failed, cancelling, cancelled

Cancel Scan

DELETE /api/v1/scans/:id

Cancels a running or queued scan.

curl -X DELETE \
  -H "X-API-Key: sb_live_abc123def456" \
  https://api.surfbot.io/api/v1/scans/770e8400-e29b-41d4-a716-446655440000

Response (200):

{
  "message": "scan cancellation requested",
  "scan_id": "770e8400-e29b-41d4-a716-446655440000"
}

Only scans with status queued or running can be cancelled. Attempting to cancel a completed scan returns 400.

Tool Runs

Each scan executes multiple tools. You can inspect individual tool executions.

List Tool Runs for a Scan

GET /api/v1/scans/:id/tool-runs
curl -H "X-API-Key: sb_live_abc123def456" \
  "https://api.surfbot.io/api/v1/scans/770e8400-e29b-41d4-a716-446655440000/tool-runs?phase=discovery"

Query Parameters:

ParameterTypeDescription
tool_namestringFilter by tool name (comma-separated)
phasestringFilter by phase (comma-separated)
statusstringFilter by status (comma-separated)

Response (200):

{
  "tool_runs": [
    {
      "id": "880e8400-e29b-41d4-a716-446655440000",
      "scan_id": "770e8400-e29b-41d4-a716-446655440000",
      "tool_name": "subfinder",
      "phase": "discovery",
      "status": "completed",
      "started_at": "2026-03-15T10:05:01Z",
      "finished_at": "2026-03-15T10:07:30Z",
      "duration_ms": 149000,
      "targets_count": 1,
      "findings_count": 32,
      "output_summary": "Found 32 subdomains",
      "created_at": "2026-03-15T10:05:01Z"
    }
  ],
  "total": 1
}

Get Tool Run

GET /api/v1/tool-runs/:id
curl -H "X-API-Key: sb_live_abc123def456" \
  https://api.surfbot.io/api/v1/tool-runs/880e8400-e29b-41d4-a716-446655440000

Changes

Surfbot tracks what changed between scans. Changes are available at org, domain, and asset level.

Organization Changes

GET /api/v1/asset-changes
GET /api/v1/changes

Both endpoints return the same data — asset changes across all domains in your organization.

curl -H "X-API-Key: sb_live_abc123def456" \
  "https://api.surfbot.io/api/v1/asset-changes?significance=high&limit=20"

Query Parameters:

ParameterTypeDescription
change_typestringappeared, disappeared, or modified
significancestringcritical, high, medium, low, or info
asset_typestringFilter by asset type (e.g. subdomain, ip)
sincestringISO 8601 datetime — only changes after this time
domain_idstringFilter by domain UUID
cursorstringCursor for pagination
limitintegerMax results (default: 100, max: 1000)

Response (200):

{
  "changes": [
    {
      "id": "990e8400-e29b-41d4-a716-446655440000",
      "org_id": "110e8400-e29b-41d4-a716-446655440000",
      "domain_id": "550e8400-e29b-41d4-a716-446655440000",
      "scan_id": "770e8400-e29b-41d4-a716-446655440000",
      "asset_id": "220e8400-e29b-41d4-a716-446655440000",
      "change_type": "appeared",
      "significance": "high",
      "asset_type": "subdomain",
      "asset_value": "staging.example.com",
      "previous_meta": null,
      "current_meta": {"ips": ["93.184.216.35"]},
      "summary": "New subdomain discovered",
      "created_at": "2026-03-15T10:17:30Z"
    }
  ],
  "count": 1,
  "next_cursor": "eyJpZCI6Ijk5MGU4..."
}

Organization Change Summary

GET /api/v1/asset-changes/summary

Returns aggregated change counts for your organization.

curl -H "X-API-Key: sb_live_abc123def456" \
  "https://api.surfbot.io/api/v1/asset-changes/summary?since=2026-03-01T00:00:00Z"

Query Parameters:

ParameterTypeDescription
sincestringISO 8601 datetime — only count changes after this time

Response (200):

{
  "total": 15,
  "appeared": 8,
  "disappeared": 2,
  "modified": 5,
  "critical": 1,
  "high": 3,
  "medium": 5,
  "low": 4,
  "info": 2
}

Domain Changes

GET /api/v1/domains/:id/asset-changes
GET /api/v1/domains/:id/changes

Same query parameters and response format as organization changes, scoped to a single domain.

Domain Change Summary

GET /api/v1/domains/:id/asset-changes/summary

Same response format as organization change summary, scoped to a single domain.

Asset Change History

GET /api/v1/assets/:id/changes

Returns change history for a specific asset.

curl -H "X-API-Key: sb_live_abc123def456" \
  "https://api.surfbot.io/api/v1/assets/220e8400-e29b-41d4-a716-446655440000/changes?limit=50"

Query Parameters:

ParameterTypeDescription
cursorstringCursor for pagination
limitintegerMax results (default: 100, max: 1000)

Asset History

GET /api/v1/assets/:id/history

Returns the asset with its metadata history.

curl -H "X-API-Key: sb_live_abc123def456" \
  https://api.surfbot.io/api/v1/assets/220e8400-e29b-41d4-a716-446655440000/history

Response (200):

{
  "asset": {
    "id": "220e8400-e29b-41d4-a716-446655440000",
    "domain_id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "subdomain",
    "value": "api.example.com",
    "status": "active",
    "first_seen": "2026-01-01T00:00:00Z",
    "last_seen": "2026-03-15T10:17:30Z",
    "metadata": {"ips": ["93.184.216.34"]}
  }
}

On this page