kaveo · Reference
CLI and API reference
Reference for the kaveo CLI (commands, flags, exit codes, CI gating), authentication, the /v1 REST API, streaming, error envelope and health endpoints.
On this page
- The kaveo CLI
- Point it at kaveo
- Global flags
- Commands
- Gate a pipeline
- Exit codes
- API authentication
- Endpoints
- Auth and your account
- Accounts and onboarding
- Scans
- Findings and evidence
- Grounded AI
- Remediation
- Issues
- Compliance
- Sharing and email
- Integrations and MCP
- Organizations
- Administration
- SCIM 2.0
- Health and metrics
- Streaming responses
- Errors
- Related pages
The kaveo CLI#
kaveo is a command-line client built for CI first. It is already installed in the api and worker images. The CLI talks HTTP to /v1/* only and never opens the database. RBAC and row-level security are enforced on the server, so the CLI never sees more than the console would show the same user.
Point it at kaveo#
Each setting is resolved in this order: flag, then environment variable, then config file.
The default URL is the api container's own address, so it works when you run the CLI inside that container. Compose publishes only Caddy's ports, and Caddy forwards /v1/* to the api. From anywhere else, set the URL to your kaveo origin, for example https://kaveo.example.com, or http://localhost for a local stack.
kaveo auth login stores the origin and a session token in the config file and writes it with mode 0600.
Global flags#
Every command accepts these flags. Put them after the full command, for example kaveo findings list --output table. A flag placed before the subcommand, as in kaveo --url ... scan list, is ignored.
--urland--tokenoverride the environment and the config file.--outputpicksjson(the default),tableorcsv. Results go to stdout. Progress, notes and warnings go to stderr, sokaveo findings list | jqstays clean.--yesturns off prompts. Withauth login, a missing password then fails as a usage error instead of prompting.
Commands#
--account takes kaveo's account id, the id column of kaveo accounts list, not the 12-digit AWS account number.
A session from auth login expires after KAVEO_SESSION_TTL_HOURS (168 hours by default) and cannot be refreshed. For CI, mint an API token.
Gate a pipeline#
- name: kaveo scan gate
env:
KAVEO_API_URL: https://kaveo.example.com
KAVEO_API_TOKEN: ${{ secrets.KAVEO_API_TOKEN }}
KAVEO_ACCOUNT_ID: ${{ vars.KAVEO_ACCOUNT_ID }}
run: kaveo scan start --account "$KAVEO_ACCOUNT_ID" --wait --fail-on high
The runner needs the kaveo package installed. If your runner can pull the kaveo-api image you built, you can run the CLI from that image instead:
docker run --rm -e KAVEO_API_URL -e KAVEO_API_TOKEN kaveo-api:latest \
kaveo scan start --account "$KAVEO_ACCOUNT_ID" --wait --fail-on high
How the gate behaves:
--fail-onrequires--wait. Without it the command exits 2, so a gate never passes without a result.- The CLI polls
GET /v1/scans/{scan_id}every 2 seconds until the status issucceeded,failedorpartial.--timeoutbounds the wait, in seconds. - Progress goes to stderr, and only on a TTY, so CI logs stay quiet.
- Severities run
critical,high,medium,low,info.--fail-on highalso fires on critical. - The gate counts non-suppressed findings of every source, including native AWS findings.
- A scan that ends
failedexits 4. So does a scan that is still running when the timeout hits. Check it later withkaveo scan status.
Exit codes#
Codes 1 and 4 are kept apart deliberately. "The scan found something" and "kaveo did not answer" never share a code, so an outage never reads as a pass. Branch on the exact code in your pipeline, not on any non-zero value.
API authentication#
- Sessions.
POST /v1/auth/logintakesemail,passwordand, when the user has TOTP MFA,mfa_code. It returnstokenandexpires_at, and also sets the httpOnlykaveo_sessioncookie that the console uses. Send the token asAuthorization: Bearer <token>. After repeated failed logins, the email is locked out for a cool-down period. - API tokens. Tokens start with
kv_api_and are meant for scripts and CI. Create one withPOST /v1/api-tokensand a body ofname, optionalscopesand optionalttl_days(1 to 3650). The plaintext appears once in the response, and kaveo stores only a SHA-256 hash. - Scopes. A token can do only what both its owner's role and its scopes allow. Scopes are the permission names:
view_findings,run_scan,investigate,share_report,triage_findings,approve_remediation,manage_accountsandmanage_users. The default,view_findingsplusrun_scan, is enough for a CI gate and cannot change your cloud. - MCP tokens. Tokens that start with
kv_mcp_work only onPOST /mcp. See MCP server and integrations. - Org selection. Send
X-Kaveo-Org: <org-id>to act in another org you belong to. Without the header, requests use your home org. Platform superadmins can name any org. - Pending accounts. While
KAVEO_APPROVAL_REQUIREDis on (the default), a user a superadmin has not approved yet gets a 403 on every authenticated route exceptGET /v1/auth/meandPOST /v1/auth/logout. - Request ids. Responses carry
X-Request-ID. If you send your own value in that header, kaveo uses it, so you can match a client error to a server log line. The one exception is a rate-limit 429, which is answered before a request id is assigned.
Endpoints#
The Needs column shows the permission a route checks. A session needs a role that grants it, and an API token needs it as a scope too. Viewers hold view_findings. Analysts add run_scan, investigate, share_report and triage_findings. Admins hold every permission. Your role in an org comes from your membership there: owners and admins act as admins, analysts as analysts, and viewers and plain members as viewers.
Auth and your account#
Accounts and onboarding#
Scans#
Findings and evidence#
Grounded AI#
Remediation#
Issues#
Compliance#
Sharing and email#
Integrations and MCP#
Organizations#
These routes need a signed-in caller. The handler then checks your role in that org. A platform superadmin passes the owner-or-admin checks, except when adding members.
Administration#
SCIM 2.0#
SCIM accepts two bearer credentials:
- The static token in
KAVEO_SCIM_TOKEN. Users it creates are not placed in any org, and a user without an org gets a 403 on tenant routes. Treat this path as limited today. - A console session token of a signed-in user who holds
manage_users. Users it creates join that user's org as members, with viewer access. A session expires afterKAVEO_SESSION_TTL_HOURS, so the IdP's credential needs renewing. API tokens (kv_api_) are not accepted on SCIM.
handle /scim/* {
reverse_proxy api:8000
}
Health and metrics#
Caddy does not forward either path to the api, so you can reach them only from inside the compose network. Keep it that way, or put them behind your own access control if you route them. See Deployment.
Streaming responses#
The /stream variants and POST /v1/investigate return text/event-stream. Each event is a single data: line holding a JSON object, and its type field says which event it is.
kaveo runs the stage, and stores the output when it cites evidence, before it sends the first byte. So a missing finding comes back as an ordinary 404, and a provider failure as a 503, never as a half-written stream.
Errors#
kaveo's errors use one envelope:
{"error": "forbidden", "detail": "account pending approval"}
A few 400 responses, such as an unknown provider sent to PUT /v1/ai/config, and requests to paths that do not exist use FastAPI's plain {"detail": "..."} shape instead. Read detail first and treat error as optional.
The rate limiter counts requests per client address over a rolling 60 seconds, using the address the api sees. In the stock stack every request arrives through Caddy, so all clients share one budget. Size the limit with that in mind.
Related pages#
- Quick start: bring the stack up and sign in.
- Configuration: every setting, and how to pass the ones compose leaves out.
- Connect cloud accounts: register accounts and run your first scan.
- Evidence and grounded AI: what the AI stages return and how citations are checked.
- MCP server and integrations: the 7 MCP tools, alert channels and SIEM export.