Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.vigolium.com/llms.txt

Use this file to discover all available pages before exploring further.

Starting the Server

# Start with an API key
export VIGOLIUM_API_KEY=my-secret-key
vigolium server

# Custom host and port
export VIGOLIUM_API_KEY=my-secret-key
vigolium server --host 127.0.0.1 --service-port 9002

# With transparent HTTP proxy for recording traffic
export VIGOLIUM_API_KEY=my-secret-key
vigolium server --ingest-proxy-port 9003

# Without authentication (development only)
vigolium server -A
The server listens on 0.0.0.0:9002 by default.

CORS Configuration

The server’s CORS behavior is controlled by cors_allowed_origins in ~/.vigolium/vigolium-configs.yaml:
server:
  cors_allowed_origins: reflect-origin
ValueBehavior
reflect-origin (default)Echoes the requesting Origin header back. Allows credentials.
*Allows all origins without credentials (standard wildcard).
(empty string)Disables CORS middleware entirely.
https://app.example.com, https://admin.example.comComma-separated allowlist. Allows credentials.

Project Scoping

All server operations are scoped to a project via the X-Project-UUID request header. If omitted, the default project is used.
# Ingest into a specific project
curl -X POST http://localhost:9002/api/ingest-http \
  -H "Authorization: Bearer my-secret-key" \
  -H "X-Project-UUID: a1b2c3d4-..." \
  -H "Content-Type: application/json" \
  -d '{"input_mode": "url", "content": "https://example.com"}'
All queries (findings, HTTP records, stats, scans) return data scoped to the project specified in the header. See Projects for the full multi-tenancy reference.

Authentication

All API requests (except /health) require a Bearer token:
Authorization: Bearer my-secret-key
API key resolution order: VIGOLIUM_API_KEY env var > server.auth_api_key in config file.

API Endpoints

MethodPathDescription
GET/App info (no auth required)
GET/healthHealth check (no auth required)
GET/metricsPrometheus metrics (no auth required)
GET/swagger/*Swagger UI and OpenAPI spec (no auth required)
GET/server-infoServer status, queue depth, record/finding counts
GET/api/modulesList available scanner modules
GET/api/http-recordsQuery stored HTTP records
GET/api/findingsQuery scan findings
POST/api/ingest-httpIngest HTTP traffic into the database
GET/api/statsAggregated scan statistics
GET/api/scopeView scope configuration
POST/api/scopeUpdate scope configuration
GET/api/configView server configuration
POST/api/configUpdate server configuration
POST/api/scanTrigger a background scan
GET/api/scan/statusCheck scan status
DELETE/api/scanCancel a running scan
GET/api/source-reposList source repos
POST/api/source-reposCreate a source repo
GET/api/source-repos/:idGet a source repo
PUT/api/source-repos/:idUpdate a source repo
DELETE/api/source-repos/:idDelete a source repo
POST/api/agent/run/querySingle-shot agent prompt execution
POST/api/agent/run/autopilotAutonomous AI-driven scanning session
POST/api/agent/run/swarmAI-guided multi-phase vulnerability scan
POST/api/agent/chat/completionsOpenAI-compatible chat completions (synchronous)
GET/api/agent/status/listList agent runs
GET/api/agent/status/:idGet agent run status (includes full result when completed)
GET/api/agent/sessionsPaginated session history
GET/api/agent/sessions/:idFull session detail with debug fields
GET/api/agent/sessions/:id/logsRead or tail runtime.log (SSE supported)
GET/api/agent/sessions/:id/artifactsList session artifact files
GET/api/agent/sessions/:id/artifacts/{name}Read a specific artifact

Ingesting Data via API

The /api/ingest-http endpoint accepts multiple input modes. All requests use POST with a JSON body.

Ingest a Single URL

curl -X POST http://localhost:9002/api/ingest-http \
  -H "Authorization: Bearer my-secret-key" \
  -H "Content-Type: application/json" \
  -d '{
    "input_mode": "url",
    "content": "https://example.com/api/users?id=1"
  }'

Ingest Multiple URLs (url_file mode)

Pass a newline-separated list of URLs. Lines starting with # are treated as comments.
curl -X POST http://localhost:9002/api/ingest-http \
  -H "Authorization: Bearer my-secret-key" \
  -H "Content-Type: application/json" \
  -d '{
    "input_mode": "url_file",
    "content": "https://example.com/api/users?id=1\nhttps://example.com/api/posts?page=2\nhttps://example.com/login"
  }'

Ingest a curl Command

curl -X POST http://localhost:9002/api/ingest-http \
  -H "Authorization: Bearer my-secret-key" \
  -H "Content-Type: application/json" \
  -d '{
    "input_mode": "curl",
    "content": "curl -X POST https://example.com/api/login -H \"Content-Type: application/json\" -d \"{\\\"username\\\":\\\"admin\\\",\\\"password\\\":\\\"test\\\"}\""
  }'
Using content_base64 to avoid JSON escaping issues:
# Encode the curl command
ENCODED=$(echo -n 'curl -X POST https://example.com/api/login -H "Content-Type: application/json" -d "{\"username\":\"admin\",\"password\":\"test\"}"' | base64)

curl -X POST http://localhost:9002/api/ingest-http \
  -H "Authorization: Bearer my-secret-key" \
  -H "Content-Type: application/json" \
  -d "{
    \"input_mode\": \"curl\",
    \"content_base64\": \"$ENCODED\"
  }"

Ingest a Raw HTTP Request (Burp-style)

Send a base64-encoded raw HTTP request, optionally with its response:
# Encode raw request
RAW_REQ=$(printf 'GET /api/users?id=1 HTTP/1.1\r\nHost: example.com\r\nCookie: session=abc123\r\n\r\n' | base64)

curl -X POST http://localhost:9002/api/ingest-http \
  -H "Authorization: Bearer my-secret-key" \
  -H "Content-Type: application/json" \
  -d "{
    \"input_mode\": \"burp_base64\",
    \"http_request_base64\": \"$RAW_REQ\"
  }"
With both request and response:
RAW_REQ=$(printf 'POST /api/login HTTP/1.1\r\nHost: example.com\r\nContent-Type: application/json\r\n\r\n{"username":"admin","password":"test"}' | base64)
RAW_RESP=$(printf 'HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n{"token":"eyJhbGciOiJIUzI1NiJ9..."}' | base64)

curl -X POST http://localhost:9002/api/ingest-http \
  -H "Authorization: Bearer my-secret-key" \
  -H "Content-Type: application/json" \
  -d "{
    \"input_mode\": \"burp_base64\",
    \"http_request_base64\": \"$RAW_REQ\",
    \"http_response_base64\": \"$RAW_RESP\"
  }"

Ingest a Raw HTTP Request with a URL Hint

Raw HTTP requests don’t contain the scheme (https vs http), and the Host header may not match the public hostname (e.g. behind a load balancer). Use the url field to provide the correct scheme and host:
RAW_REQ=$(printf 'POST /api/login HTTP/1.1\r\nHost: internal-lb\r\nContent-Type: application/json\r\n\r\n{"user":"admin"}' | base64)

curl -X POST http://localhost:9002/api/ingest-http \
  -H "Authorization: Bearer my-secret-key" \
  -H "Content-Type: application/json" \
  -d "{
    \"input_mode\": \"burp_base64\",
    \"url\": \"https://app.example.com\",
    \"http_request_base64\": \"$RAW_REQ\"
  }"

Ingest an OpenAPI / Swagger Spec

curl -X POST http://localhost:9002/api/ingest-http \
  -H "Authorization: Bearer my-secret-key" \
  -H "Content-Type: application/json" \
  -d '{
    "input_mode": "openapi",
    "content": "{\"openapi\":\"3.0.0\",\"info\":{\"title\":\"Example\",\"version\":\"1.0\"},\"servers\":[{\"url\":\"https://api.example.com\"}],\"paths\":{\"/users\":{\"get\":{\"summary\":\"List users\"}},\"/users/{id}\":{\"get\":{\"summary\":\"Get user\",\"parameters\":[{\"name\":\"id\",\"in\":\"path\",\"required\":true,\"schema\":{\"type\":\"integer\"}}]}}}}"
  }'
Using base64 for larger specs:
SPEC=$(base64 < openapi.yaml)

curl -X POST http://localhost:9002/api/ingest-http \
  -H "Authorization: Bearer my-secret-key" \
  -H "Content-Type: application/json" \
  -d "{
    \"input_mode\": \"openapi\",
    \"content_base64\": \"$SPEC\"
  }"

Ingest a Postman Collection

COLLECTION=$(base64 < collection.json)

curl -X POST http://localhost:9002/api/ingest-http \
  -H "Authorization: Bearer my-secret-key" \
  -H "Content-Type: application/json" \
  -d "{
    \"input_mode\": \"postman_collection\",
    \"content_base64\": \"$COLLECTION\"
  }"

Ingesting Data via CLI

The vigolium ingest command supports both remote (server) and local (direct-to-database) modes.

Remote Ingestion (to a running server)

export VIGOLIUM_API_KEY=my-secret-key

# Pipe URLs from stdin
cat urls.txt | vigolium ingest -s http://localhost:9002

# From a file
vigolium ingest -s http://localhost:9002 --input targets.txt

# OpenAPI spec with a base URL
vigolium ingest -s http://localhost:9002 \
  --input api.yaml -I openapi -t https://api.example.com

# Control submission rate
vigolium ingest -s http://localhost:9002 \
  --input urls.txt --concurrency 20 -r 200

Local Ingestion (direct to database)

When --server is omitted, requests are fetched and stored directly in the local database:
# Ingest URLs (fetches each and stores request + response)
cat urls.txt | vigolium ingest

# From an OpenAPI spec
vigolium ingest --input api.yaml -I openapi -t https://api.example.com

# With a custom scan ID for tagging
vigolium ingest --input urls.txt --scan-id recon-2026-02

# Use a specific database file
vigolium ingest --input urls.txt --db ./project.db

# Ingest into a specific project
vigolium ingest --input urls.txt --project-id a1b2c3d4-...

Ingesting via Transparent Proxy

Start the server with a proxy port to passively record HTTP traffic:
export VIGOLIUM_API_KEY=my-secret-key
vigolium server --ingest-proxy-port 9003
Then route your tools through the proxy:
# curl through the proxy
curl -x http://localhost:9003 https://example.com/api/users

# httpx through the proxy
echo "https://example.com" | httpx -proxy http://localhost:9003

# nuclei through the proxy
nuclei -u https://example.com -proxy http://localhost:9003
All proxied HTTP traffic is automatically recorded in the database. HTTPS CONNECT tunneling is passed through without recording.

Querying Ingested Data

List HTTP Records

# All records (paginated, default limit=50)
curl -s http://localhost:9002/api/http-records \
  -H "Authorization: Bearer my-secret-key" | jq .

# Filter by domain
curl -s "http://localhost:9002/api/http-records?domain=example.com" \
  -H "Authorization: Bearer my-secret-key" | jq .

# Filter by status code and method
curl -s "http://localhost:9002/api/http-records?status_code=200,302&method=GET,POST" \
  -H "Authorization: Bearer my-secret-key" | jq .

# Search across URLs and headers
curl -s "http://localhost:9002/api/http-records?search=admin&limit=10" \
  -H "Authorization: Bearer my-secret-key" | jq .

# Pagination
curl -s "http://localhost:9002/api/http-records?limit=20&offset=40" \
  -H "Authorization: Bearer my-secret-key" | jq .

List Findings

# All findings
curl -s http://localhost:9002/api/findings \
  -H "Authorization: Bearer my-secret-key" | jq .

# Filter by severity
curl -s "http://localhost:9002/api/findings?severity=high,critical" \
  -H "Authorization: Bearer my-secret-key" | jq .

# Filter by module
curl -s "http://localhost:9002/api/findings?module_name=xss-reflected" \
  -H "Authorization: Bearer my-secret-key" | jq .

# Filter by domain
curl -s "http://localhost:9002/api/findings?domain=example.com" \
  -H "Authorization: Bearer my-secret-key" | jq .

Server Info

curl -s http://localhost:9002/server-info \
  -H "Authorization: Bearer my-secret-key" | jq .
Response:
{
  "version": "0.1.0",
  "uptime": "2h15m30s",
  "service_addr": "0.0.0.0:9002",
  "proxy_addr": "0.0.0.0:9003",
  "db_driver": "sqlite",
  "queue_depth": 0,
  "total_records": 1542,
  "total_findings": 23
}

Scan Management via API

After ingesting HTTP records, trigger a vulnerability scan via the API.

Trigger a Scan

curl -s -X POST http://localhost:9002/api/scan \
  -H "Authorization: Bearer my-secret-key" \
  -H "Content-Type: application/json" \
  -d '{}' | jq .
Force re-scan with specific modules:
curl -s -X POST http://localhost:9002/api/scan \
  -H "Authorization: Bearer my-secret-key" \
  -H "Content-Type: application/json" \
  -d '{
    "force": true,
    "enable_modules": ["xss-scanner", "sqli-error-based"]
  }' | jq .
Returns 202 Accepted on success, 409 Conflict if a scan is already running.

Check Scan Status

curl -s http://localhost:9002/api/scan/status \
  -H "Authorization: Bearer my-secret-key" | jq .

Cancel a Running Scan

curl -s -X DELETE http://localhost:9002/api/scan \
  -H "Authorization: Bearer my-secret-key" | jq .
See the API Reference for full request/response details.

Running AI Agents via API

The agent API provides three run modes that mirror the vigolium agent CLI subcommands. Only one agent run can be active at a time (returns 409 Conflict if busy).

Query, Single-Shot Agent Run

curl -s -X POST http://localhost:9002/api/agent/run/query \
  -H "Authorization: Bearer my-secret-key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt_template": "security-code-review",
    "source": "/home/user/src/my-app"
  }' | jq .
At least one of prompt_template, prompt_file, or prompt is required. Returns 202 Accepted on success. Set "stream": true for real-time SSE output. The legacy repo_path JSON field is still accepted as an alias for source.

Autopilot, Autonomous Scanning

curl -s -X POST http://localhost:9002/api/agent/run/autopilot \
  -H "Authorization: Bearer my-secret-key" \
  -H "Content-Type: application/json" \
  -d '{
    "target": "https://example.com",
    "focus": "API injection",
    "intensity": "balanced",
    "stream": true
  }'

Swarm, AI-Guided Multi-Phase Scan

curl -s -X POST http://localhost:9002/api/agent/run/swarm \
  -H "Authorization: Bearer my-secret-key" \
  -H "Content-Type: application/json" \
  -d '{
    "input": "https://example.com",
    "discover": true,
    "triage": true,
    "stream": true
  }'
SSE events are data: lines with JSON payloads: {"type":"chunk","text":"..."} for real-time output, {"type":"phase","phase":"..."} for swarm phase transitions, {"type":"done","result":{...}} on completion, or {"type":"error","error":"..."} on failure.
Provider overrides are CLI-only. The server resolves the olium provider once from agent.olium.* in vigolium-configs.yaml. To switch providers on a server-side workload, edit the YAML and reload, there is no per-request provider field.

List All Agent Runs

curl -s http://localhost:9002/api/agent/status/list \
  -H "Authorization: Bearer my-secret-key" | jq .

Check Agent Run Status

curl -s http://localhost:9002/api/agent/status/agt-550e8400... \
  -H "Authorization: Bearer my-secret-key" | jq .
Once the run completes, the response includes a result field with the full agent output (raw text, findings, HTTP records). See Agent Mode for the full agent documentation (autopilot, swarm, vigolium-audit, query, olium) and the API Reference for request/response details.

Input Modes Reference

ModeContent FieldDescription
urlcontentA single URL
url_filecontentNewline-separated list of URLs
curlcontent or content_base64A curl command string
burp_base64http_request_base64Base64-encoded raw HTTP request
openapi / swaggercontent or content_base64OpenAPI/Swagger spec (JSON or YAML)
postman_collectioncontent or content_base64Postman Collection (JSON)
For burp_base64 mode, you can also include http_response_base64 to store the response alongside the request. For modes that accept large payloads, prefer content_base64 to avoid JSON escaping issues.