Skip to content

Vectasec · Reference

CLI and API reference

Reference for the vectasec and vectasec-collector commands and the Vectasec engine HTTP API: endpoints, auth headers, roles and error codes.

On this page

The Vectasec CLI#

vectasec is the operator's entry point to the engine. Run it from the engine directory of the release as uv run vectasec <command>. It loads the nearest .env at or above your working directory and talks to Postgres directly through DATABASE_URL, not through the API. It acts with that database credential rather than a user token, so run it only on hosts that should hold DATABASE_URL. Commands that read or write tenant data take --tenant <uuid> and default to the demo tenant that the first migration seeds. connections add and connections rm write an audit log row with the actor cli.

CommandWhat it doesKey flags
scanRuns one scan inside the CLI process, without the queue, stores the results and prints resources, edges, findings, observations and detector timing. An ad-hoc scan also saves its connection.--connection NAME for a saved connection, or --type T plus connector flags for an ad-hoc one; --name (defaults to the bootstrap servers, URL or type), --json
connectionsLists connections with mode, status, last scan, resource count and open findings. Same as connections list.none beyond --tenant
connections addChecks your flags against the fields the connector declares and saves the connection without scanning it. Secret fields go to Supabase Vault.--type and --name (required), --mode cloud or --mode collector (default cloud), connector flags
connections test NAMERuns the connector against the saved config and reports how many resources of each kind it collects. Runs no detectors. Sets the connection status to active or error.--type when the name exists for several types
connections rm NAMEDeletes the connection, what was collected through it and its Vault secret. Scan history is kept.--type; --yes to delete. Without it, the command is a dry run that prints the counts and exits non-zero.
scansScan history with status, connection, start time and duration.--limit (default 20)
identitiesThe non-human identity inventory with credentials and grants, and a count of wildcard grants.none beyond --tenant
posturePosture score and grade, open findings by severity, and coverage gaps.none beyond --tenant
rulesEvery loaded detector grouped by rule-id prefix, then the connector list. Needs no database.none
findingsEvery finding for the tenant, worst first, with an evidence count.none beyond --tenant
doctorChecks connector and detector counts, the database, the pgmq and pg_cron extensions and the scan queue. Exits non-zero on a problem.--verify-ledger recomputes the evidence hash chain
workerDrains the scan queue and runs each scan.--once drains and exits; --reap-only ages out stuck running scans and exits

Connector flags#

scan and connections add share these flags. Each one sets the config key of the same name.

FlagConfig keyUsed by, for example
--bootstrapbootstrapkafka
--urlurlkong, rabbitmq, mcp
--host, --porthost, portredis, pgbouncer
--tokentokenmcp, vault
--admin-tokenadmin_tokenkong
--username, --passwordusername, passwordrabbitmq, nats
--set KEY=VALUEany keyevery other field; repeatable

Values pass through as strings, for example --set timeout=30, and each connector converts what it reads. When connections add rejects a config, it prints the problems and the flags that type takes. Every connector's fields are listed in the Connector reference.

Collector CLI#

The collector ships its own command, vectasec-collector, with three subcommands:

  • run (the default) enrolls, then sends heartbeats, polls for jobs, scans and pushes results.
  • preview scans every configured target and prints exactly what would be pushed. It contacts no control plane.
  • check validates the configuration and prints each target's non-secret config, without contacting the targets or the control plane.

API basics#

The engine API is a FastAPI service. Start it with its bundled entry point from the engine directory of the release (it reads .env, ENGINE_HOST and ENGINE_PORT); don't start it with bare uvicorn. It listens on http://127.0.0.1:8000 by default and serves interactive docs at /docs. Read the Security model before you bind it to any other address.

Every route except /health, /collector/enroll and the interactive docs needs Authorization: Bearer <token>. Requests that carry only X-VectaSec-* headers are refused unless VECTASEC_DEV_TRUST_HEADERS is set. That switch is off by default; keep it unset on any engine another host can reach. The /collector/* routes take the collector token described below. Everywhere else, the token is one of two kinds:

  • The engine service token (VECTASEC_ENGINE_TOKEN), for a trusted server such as the console. Name the tenant in X-VectaSec-Tenant unless VECTASEC_ENGINE_TOKEN_TENANT pins it. Every mutation also needs X-VectaSec-Actor, the acting user's UUID, and the engine checks that user's role in the tenant.
  • A Supabase user access token. The engine verifies it against your project's public keys, so set SUPABASE_URL on the engine. The actor is the token's subject and the tenant comes from membership. Send X-VectaSec-Tenant only if you belong to more than one tenant.

Roles come from each member's role in the organization. A viewer can call every GET. An analyst or editor can also scan, triage, change finding status, suppress, attest and manage connections. An admin or owner can also manage integrations, routing rules and members. Every action is recorded in the audit log with its actor.

There are no list endpoints for findings or assets. The console reads those from Postgres under row-level security, and the API carries actions, reports and the few reads RLS can't serve.

bash
curl -s -X POST http://127.0.0.1:8000/connections -H "Authorization: Bearer $VECTASEC_ENGINE_TOKEN" -H "X-VectaSec-Tenant: <tenant-uuid>" -H "X-VectaSec-Actor: <user-uuid>" -H 'Content-Type: application/json' -d '{"type":"kafka","name":"prod-kafka","config":{"bootstrap":"broker-1:9092"}}'

The 201 response carries connection_id and created. Queue a scan with POST /connections/{id}/scan.

Endpoints#

Scans and connections#

RouteRoleNotes
GET /healthnoneAlways 200. status is ok or degraded, db is true when the database answered, and the body lists the loaded connectors and the detector count.
POST /scanseditorBody: type, config, name, inline, and an optional tenant_id that must match yours. Saves the connection and queues a scan for vectasec worker. inline: true runs it in the request instead. Returns 202.
GET /scans/{id}viewerStatus, timestamps, stats and connection.
GET /connectorsviewerEach connector type with its declared fields and rule count.
GET /collectorsviewerEnrolled collectors. online is true when the last heartbeat is under two minutes old.
POST /connectionseditorBody: type, name, config, mode, collector_id. Validates the config, stores secret fields in Vault and returns 201. In collector mode it binds the named collector, or the only one enrolled.
POST /connections/{id}/testeditorRuns the connector against the stored config. Returns 200 either way, with ok.
POST /connections/{id}/scaneditorQueues a scan from the stored config. A collector connection waits for its collector. Returns 202.
DELETE /connections/{id}editorRemoves the connection, its collected data and its Vault secret. Scan history is kept.
PATCH /connections/{id}editorBody: scan_interval_minutes, either null to unschedule or 5 to 10080 minutes.

Findings and compliance#

RouteRoleNotes
POST /findings/{id}/statuseditorBody: status (open, triaged, in_progress, resolved or accepted) and an optional note.
POST /findings/{id}/assigneditorBody: assignee, a user UUID or null.
POST /findings/{id}/triageeditorGrounded triage with its citations. Without an AI provider key it returns a rule-based triage. ?force=true skips the cache.
POST /suppressionseditorBody: rule_id, scope ({} for tenant-wide, or an ext_id or kind key), reason (required), expires_at. Returns 201 and applies from the next scan.
GET /compliance/{framework}viewerControls with status and finding ids. Framework ids are PCI_DSS_4_0_1, NIS2, DORA, HIPAA and MCP_SPEC_2025_11_25. An unknown id returns an empty list.
POST /compliance/{framework}/{control_id}/attesteditorBody: scope (required), note, expires_at. The actor must be a user UUID. Returns 201.

Reports and graph#

RouteRoleNotes
GET /reports/oscalviewerOSCAL 1.1.3 assessment results.
GET /reports/csvviewerFindings as CSV.
GET /reports/summaryviewerExecutive summary in Markdown.
GET /reports/sbomviewerCycloneDX 1.6 SBOM of the running estate.
GET /reports/vexviewerCycloneDX 1.6 VEX from finding status and suppressions.
GET /licensingviewerLicense terms per running component version.
GET /graph/blast-radius/{resource_id}viewerWhat a resource reaches. depth 1 to 10 (default 4), directed (default false).

Tenant administration#

RouteRoleNotes
GET /integrations, GET /routing-rules, GET /membersviewerPublic config only for integrations.
POST /integrationsadminBody: type (slack, teams, webhook, email, jira or siem), name, config, enabled. Secret fields go to Vault.
DELETE /integrations/{id}, POST /integrations/{id}/testadminDelete removes its routing rules and Vault secret too. Test sends a real message and returns 200 either way, with ok.
POST /routing-rules, DELETE /routing-rules/{id}adminBody: integration_id, match, name, enabled. match keys: min_severity, connector_types, rule_prefixes, notify_on (new_findings, scan_failed). An empty match routes everything.
POST /members, PATCH /members/{user_id}, DELETE /members/{user_id}adminInviting a new address needs SUPABASE_SERVICE_ROLE_KEY and SUPABASE_URL on the engine. The last admin can't be demoted or removed.
/admin/* (three routes)operatorPlatform operators only: delete an account, grant or revoke operator rank.

Collector#

RouteAuthNotes
POST /collector/enrollenrollment_token in the bodyReturns a collector token valid for 3600 seconds. Send it as Authorization: Bearer on the other collector routes.
POST /collector/heartbeatcollector tokenRecords liveness and version.
GET /collector/jobscollector tokenUp to max_jobs (1 to 50, default 5) queued scans. A job names a target, never a host or credential.
POST /collector/resultscollector tokenFindings and resource metadata for a claimed job.

Error codes#

CodeMeaning
400Connector or integration config failed validation, unknown connector or integration type, a collector-mode connection whose collector is missing, ambiguous or not in your tenant, an X-VectaSec-Tenant that is not a UUID, no tenant named on an engine-token call, an attestation actor that is not a user UUID, or a change that would leave the tenant with no admin.
401Missing or invalid token, missing X-VectaSec-Actor on a mutation, invalid or expired collector token, or enrollment rejected.
403Role too low, not a member of the tenant, engine token scoped to another tenant, body tenant_id mismatch, or a caller without platform operator rank on /admin/*.
404No such scan, connection, finding, resource, integration, routing rule, member, user, tenant or collector job.
409The user is already a member.
413OSCAL, CSV or summary report for a tenant with more than 20000 findings.
422Request body or query failed schema validation, or triage requested on a finding with no observations.
429Invite to a new address after the tenant has added 20 members in the past hour.
500Triage rejected by the database's citation gate.
501Account deletion on an engine without SUPABASE_SERVICE_ROLE_KEY and SUPABASE_URL.
502Supabase Auth refused an invite or account deletion.
503Database unavailable or DATABASE_URL unset.

Next steps#