← Back to home
LiveAPISec

liveapisec — CLI & SDK docs

Push your API endpoints, run security tests and gate your CI/CD — straight from the terminal.

When to use the CLI? Instead of walking through the wizard in the dashboard, a developer pushes endpoints + an optional token from their own environment (CI/CD, agent, script). The token is generated on your side and encrypted server-side (AES-256). Tip: no token = we only test what's public.

Not Python-only — works with any HTTP API, in any language

The liveapisec CLI is written in Python — but that is only the tool you run. You use it to push, test and monitor APIs built in any language and framework: Python, Node.js, Go, Rust, Java/Kotlin, PHP, Ruby, .NET/C#… It does not matter how your backend is implemented, as long as it exposes HTTP(S) endpoints.

3 ways to get your endpoints in:

  • push — list endpoints yourself (works for any HTTP API).
  • push --openapi-url … — pull an OpenAPI spec (FastAPI/DRF, Springdoc, NestJS Swagger, express swagger-ui, ASP.NET Swashbuckle…).
  • scan-code — scan the source code; it auto-detects these 11 frameworks:
Python
FastAPI · Flask · Django
JavaScript / TypeScript
Next.js (App + Pages Router) · NestJS · Express
PHP
Laravel · PHP/Slim · Lumen
Java
Spring MVC / Spring Boot (@GetMapping)
Go
Gin · Echo · Fiber · Chi · gorilla/mux · net/http
Rust
axum · actix-web · rocket · warp

What kind of applications work? REST/JSON APIs — microservices, monoliths, BFFs, API gateways, third-party APIs… public or protected (jwt / bearer / cookie / api_key / OAuth2). scan-code reads the HTTP routes; the app behind them can be anything.

API types we can test: REST (OpenAPI / Swagger), RAML, GraphQL (introspection or SDL) and SOAP (WSDL) — the scanner converts each into real HTTP targets. WebSocket and gRPC are not covered by the HTTP scanner (non-HTTP protocols).

Integration & SDK: the package also ships a Python SDK ( from liveapisec import LiveAPISec ), and the same Developer API is a plain REST API you can call from any language (curl, Node fetch, Go…). See section 8 — SDK below.

1. Installation

One command (Linux / macOS) — recommended

curl -fsSL https://raw.githubusercontent.com/LiveApiSec/liveapisec/main/install.sh | bash

The installer uses pipx when available, otherwise it creates an isolated virtualenv and symlinks the command into ~/.local/bin — no sudo, and it works on PEP 668 systems (Ubuntu 24.04+) where a plain pip install is blocked.

From PyPI (developers with pipx/venv)

pipx install liveapisec     # or: pip install liveapisec (inside a venv)

From GitHub (build from source)

pip install "liveapisec @ git+https://github.com/LiveApiSec/liveapisec.git"

Verify

liveapisec --help

Install once (e.g. in a CI image, on a dev machine, in GitHub Actions) and the liveapisec command is available in every project on that machine.

2. Configuration

Generate an API key once in the dashboard: Settings → Developer API → Create API key (the las_dev_... key is shown only once — store it as a secret).

Log in like aws / gcloud (recommended locally)

Instead of pasting a key, run liveapisec login. The CLI starts a device flow: it prints a one-time code, opens https://liveapisec.com/cli/authorize?code=XXXX-XXXX, you sign in and click Approve, and a fresh key is saved locally. The login key expires after 30 days; the saved token has org-wide scope, so it covers all your projects — one login, not one per project. Permissions can be limited on the approval page.

$ liveapisec login
  First, copy your one-time code:  WDJB-MJHT
  Then open:  https://liveapisec.com/cli/authorize?code=WDJB-MJHT

✓ Logged in — acme
  key:     las_dev_ab12…
  expires: 2026-11-01
✓ Token saved to /home/you/.config/liveapisec/config.json

liveapisec whoami          # org, key prefix, scopes, expiry
liveapisec logout          # remove the saved token (key stays in the panel)

Headless / SSH? Add --no-browser (the URL is printed) or paste an existing key with liveapisec login --token las_dev_.... In CI the login is not needed: keep the LIVEAPISEC_API_KEY secret — the environment variable wins over the saved login, so pipelines are unaffected.

First run (interactive)

The first time you run a command that needs the API, the CLI asks for your key, shows you exactly where to find it, and saves it to ~/.config/liveapisec/config.json (mode 0600). Next runs pick it up automatically:

$ liveapisec push --name my-api --base-url https://api.example.com ...
No LiveAPISec API key found.
Generate one in the dashboard:  Settings → Developer API → Create API key
  https://liveapisec.com/settings
The key looks like:  las_dev_...
Tip: no key = only public endpoints can be tested.
Paste your API key: las_dev_...
✓ API key saved to /home/you/.config/liveapisec/config.json

Environment variables (recommended for CI)

export LIVEAPISEC_API_KEY=las_dev_...          # required
export LIVEAPISEC_API_URL=https://api.liveapisec.com   # optional (default)

Precedence: --api-key / --api-url flags → environment variables → saved config file.

Manage the saved key

liveapisec config        # show where the key is stored
liveapisec config --clear  # remove the saved config file
liveapisec whoami        # show org, key prefix, scopes and expiry

Authorize your domain (unlocks advanced tests)

Public tests work for any API. To unlock advanced & destructive tests (hacker-mode agent, release-path testing, private scans) prove you own the domain in the dashboard: Domains. We verify ownership with a DNS TXT record, a CNAME record, an HTTP file in /.well-known/, or a manual confirm — then record your consent (timestamp) for audit. Every authorized scan is gated on that consent.

# What you add at your DNS provider / web server
TXT    _penetration-auth.api.example.com  "the-token-we-give-you"
# or
CNAME  _penetration-auth.api.example.com  →  <token>.verify.liveapisec.com
# or a file
https://api.example.com/.well-known/liveapisec-<token>.txt  →  contains <token>

Local addresses are exempt. If your target is localhost, 127.0.0.1 or a private IP (e.g. 10.x, 192.168.x), no domain verification is required — it's your own local server. You can run the hacker-mode agent against it straight from the CLI:

liveapisec hacker --project PROJECT_ID --env development --wait   # dev/staging only
# --project accepts the project ObjectId or its slug (e.g. payments-api).
# ⚠ hacker mode is a DESTRUCTIVE authorized AI test — dev/staging only,
#   never production (it can break/destroy a system).

3. Interactive mode (project picker)

When you run push / scan-code in a terminal and omit --project, the CLI shows the projects available for your API key and lets you pick one — or create a new one:

$ liveapisec push --endpoint "GET /users"
No --project given. Pick a project (or create a new one):
  1) api-a (api-a)  https://a.example.com
  2) api-b (api-b)  https://b.example.com
  3) create new project
Enter number: 2
→ updating existing project api-b
✓ project 65f...: api-b — 2 endpoints, auth=none
  export PROJECT_ID=65f...

In CI (no TTY) the flags are required as before — nothing changes in pipelines.

4. Commands

Every command that takes a project accepts either the project ObjectId or its slug (e.g. payments-api) interchangeably — both come from liveapisec projects (which prints name (slug)). The slug is the public id used on liveapisec.com/trust/<slug> and never changes when you rename the project.

4.1 push — push your API (idempotent, safe in CI)

liveapisec push \
  --name my-api \
  --base-url https://api.example.com \
  --endpoint "GET /users" \
  --endpoint "POST /payments"
  • The same name + base_url = the same project (update, not a duplicate) — you can call push in every build.
  • Instead of a list of endpoints you can provide an OpenAPI spec: --openapi-url https://api.example.com/openapi.json.
  • Optional token: --auth-type jwt --auth-token <TOKEN> (or bearer, cookie --auth-cookie "session=...", api_key --auth-header X-API-Key).
  • Per-URL automation: --schedule 6h|12h|24h|weekly (capped by your plan) and --access external|internal. internal (dev/localhost/private) is never auto-tested — run it on demand via CLI; setting a schedule on an internal URL is rejected.

4.2 scan-code — scan your source code and push the endpoints

Point the CLI at a repo/folder and it detects the framework, extracts the API endpoints from the code and pushes them — no running project or OpenAPI spec needed.

cd my-project
liveapisec scan-code --dir . --name my-api --base-url https://api.example.com

# Or clone straight from git (https / ssh), no checkout needed
liveapisec scan-code --repo [email protected]:acme/my-api.git \
  --name my-api --base-url https://api.example.com

# Preview the endpoints first (no API key needed)
liveapisec scan-code --dir . --name my-api \
  --base-url https://api.example.com --dry-run

# Force a framework if auto-detection misses it
liveapisec scan-code --dir . --framework nextjs \
  --name my-api --base-url https://api.example.com

Auto-detected frameworks: FastAPI, Flask, Django, Next.js (app/api + pages/api), NestJS (@Controller/@Get), Express (app.get), Laravel, generic PHP ($app->get, Slim, Lumen), Spring (@GetMapping, Java), Go (Gin, Echo, Fiber, Chi, gorilla/mux, net/http) and Rust (axum, actix-web, rocket, warp).

framework: fastapi (42 files scanned)
found 58 endpoints:
  GET     /users
  POST    /payments
project 65f...abc: my-api — 58 endpoints, auth=none
export PROJECT_ID=65f...abc

Note on methods: FastAPI/Flask/Express/NestJS/Spring/Laravel/Go/Rust carry the HTTP method in the code. Django urlpatterns and Go net/http handlers do not — those routes are assumed to be GET.

4.3 scan — run a security test

# fire and forget (202, does not wait)
liveapisec scan --project PROJECT_ID --branch main --commit "$GITHUB_SHA"

# wait for the result and fail the build on high (CI gate)
liveapisec scan --project PROJECT_ID --branch main --commit "$SHA" \
  --wait --fail-on high
  • --wait — polls until the scan finishes (default timeout 600 s, interval 3 s; change with --timeout / --poll-interval).
  • --fail-on high — exit code 1 when a finding of severity high/critical is found; --fail-on critical only for criticals; omit it → always exit 0 (except errors).
  • --tunnel — route the scan through a connected CLI (liveapisec connect) to test a target reachable only from your machine (localhost/internal). See 4.10.

4.4 status — project status + recent scans

liveapisec status --project PROJECT_ID

4.5 findings — scan results

liveapisec findings --project PROJECT_ID --scan SCAN_ID
liveapisec findings --project PROJECT_ID --scan SCAN_ID --json   # raw data (for agents/AI)

4.5b verdict — CI regression gate (new/fixed vs baseline)

Compares the scan against a baseline: new findings are regressions. Exits 1 when new findings reach --fail-on (default: high) — the fix-and-re-scan gate for CI:

liveapisec verdict --project PROJECT_ID --scan NEW_SCAN --baseline BASE_SCAN --fail-on high

4.5c compliance · report · certificate --pdf

liveapisec compliance --project PROJECT_ID --scan SCAN_ID   # PCI DSS / SOC 2 / ISO 27001 / GDPR / NIS2 (SaaS+)
liveapisec report --project PROJECT_ID --scan SCAN_ID -o report.json   # full saved report
liveapisec certificate --project PROJECT_ID --scan SCAN_ID --pdf --variant full -o cert.pdf  # passed scans only

4.5d all — full pipeline in one command

Scan (waits) → verdict vs baseline (explicit or auto = previous completed scan) → compliance → report + certificate PDF saved. Exits 1 on regressions — so in CI (GitHub Actions, GitLab, Jenkins) the step turns red exactly like a failing test suite. Use --format md --report-out security-report.md and upload it as an artifact (if: always()) so reviewers see which findings are new even when the gate fails:

liveapisec all --project PROJECT_ID
liveapisec all --project PROJECT_ID --format md --report-out security-report.md  # human-readable report
liveapisec report --project PROJECT_ID --scan SCAN_ID --format md -o report.md   # report alone, in Markdown
liveapisec all --project PROJECT_ID --hacker --env development   # hacker-mode instead (dev/staging only)

4.5e auth-matrix — RBAC test with two identities (no source code)

Role checks (user vs organization, tenant isolation) need two accounts. Pass a second identity and every endpoint is requested as anonymous / A / B and diffed: anonymously reachable secured endpoints, inconsistent tiers, confirmed BOLA, exposed admin paths. Identity A is the scan's normal auth; B is transient (encrypted, scan-only) or a saved credential with slot B (Settings → Credentials):

liveapisec scan --project PROJECT_ID --wait --auth-token-b "$USER_B_JWT" --auth-type-b bearer
liveapisec all --project PROJECT_ID --auth-token-b "$USER_B_JWT"

4.6 project — project details

liveapisec project --project PROJECT_ID

4.7 projects — last test status per project (no dashboard needed)

See every project and the last security test result straight in the terminal — no need to open the project:

$ liveapisec projects
svc
  api-a  https://a.example.com  last test: completed · 42 tests · 3 findings (high=1 medium=2)
  api-b  https://b.example.com  last test: failed
mobile
  api-c  https://c.example.com  last test: no test yet

# JSON (for scripts / agents)
liveapisec projects --json

4.8 scans — full test (scan) history for a project

See every security test ever run on a project (status, branch/commit, tests run, findings by severity) — useful for an agent that wants to know what was tested, when, and with what result:

liveapisec scans --project PROJECT_ID
# scan 65f...001  status=completed  branch=main  commit=abc  tests=42  findings=3 (high=1 medium=2)
# scan 65f...002  status=failed     branch=main

liveapisec scans --project PROJECT_ID --json        # raw list (for scripts / agents)
liveapisec scans --project PROJECT_ID --limit 5     # only the 5 most recent

4.9 certificate — live certificate URL + embed snippet

After a scan is green, publish the live certificate for a project. The project slug is created automatically with the project (from its name); paste the returned snippet into your project, docs or trust page. It updates with every scan.

liveapisec certificate --project PROJECT_ID
liveapisec certificate --project PROJECT_ID --type badge   # badge | banner | card | iframe

The snippet (same in the dashboard under a project → Certificate) looks like this — the widget is wrapped in a static link, so it is clickable AND crawlable (href sits in your HTML):

<a href="https://liveapisec.com/trust/payments-api" title="Verified by LiveApiSec" style="text-decoration:none;display:inline-block;color:inherit"><div data-liveapisec-widget data-slug="payments-api" data-type="badge"></div></a>
<script src="https://liveapisec.com/widget.js" async></script>

Options: data-type (badge, banner, card), data-name (custom label instead of the default brand-only badge). The badge appears only once the project passes its tests.

4.10 connect — reverse tunnel (test localhost / internal)

The scan runs on LiveAPISec's scanner, so it normally cannot reach a target that exists only on your machine. Start a tunnel: the CLI then acts as a proxy — it executes the scan's HTTP requests locally and posts the results back. Only the project's base_url host is forwarded (not an open proxy).

The tunnel auto-recovers: reconnecting the CLI resumes the same tunnel, so an in-flight scan is not orphaned; transient errors (429/5xx/network) are retried with backoff; and if the CLI stops responding the scan fails fast with tunnel disconnected instead of hanging until the stale timeout.

# terminal 1 — keep running
liveapisec connect --project PROJECT_ID

# terminal 2 — same target, now reachable through the CLI
liveapisec scan --project PROJECT_ID --wait --tunnel

# hacker-mode works through the tunnel too (dev/staging only)
liveapisec hacker --project PROJECT_ID --env development --wait --tunnel

5. Authentication (auth on the target API)

5.1 Reuse the token your app already has

liveapisec push --name my-api --base-url https://api.example.com \
  --auth-type jwt --auth-token "$MY_APP_TOKEN" \
  --endpoint "GET /users" --endpoint "POST /payments"

5.2 OAuth2 Client Credentials (M2M) — recommended for CI/CD

Short-lived JWTs expire before the scan runs. Instead, register a Machine-to-Machine application in your identity provider (Auth0, Okta, Azure AD, Keycloak…) once and push the long-lived client credentials — our scanner fetches a fresh token at every scan:

liveapisec push --name my-api --base-url https://api.example.com \
  --auth-type oauth2 \
  --auth-token-url https://<your-idp>/oauth/token \
  --auth-client-id "$CLIENT_ID" --auth-client-secret "$CLIENT_SECRET" \
  --endpoint "GET /users"

5.3 Verify the token before you commit to it

--verify probes the first endpoint with the pushed auth and reports whether the token actually works (exit 2 on a bad/expired token):

liveapisec push --name my-api --base-url https://api.example.com \
  --auth-type bearer --auth-token "$TOKEN" \
  --endpoint "GET /users" --verify
# → verify: GET https://api.example.com/users → 200 ✓
#   or: verify: GET https://api.example.com/users → 401 ✗ auth failed — ...

Network errors from --verify are informational — your machine may not reach the API while our scanner can; what matters is the auth result (2xx vs 401/403).

6. Exit codes

CodeMeaning
0OK (no findings at/above the threshold, or no --fail-on)
1Gate failed — findings found at/above --fail-on
2Usage error / API error / missing key

7. GitHub Actions — full example (gate on push)

name: liveapisec
on: push
jobs:
  security-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: "3.12" }
      - name: Install CLI
        run: pip install "liveapisec @ git+https://github.com/LiveApiSec/liveapisec.git"
      - name: Push API + run security test (gate on high)
        env:
          LIVEAPISEC_API_KEY: ${{ secrets.LIVEAPISEC_KEY }}
        run: |
          liveapisec push --name my-api --base-url "$BASE_URL" \
            --endpoint "GET /users" --endpoint "POST /payments"
          liveapisec scan --project "$PROJECT_ID" \
            --branch "${GITHUB_REF#refs/heads/}" --commit "$GITHUB_SHA" \
            --wait --fail-on high

Why is push safe? Push is idempotent (name+base_url → the same project), so the next build does not create junk — it updates endpoints and the token, and the next scan tests the latest state.

Gate on NEW findings only (CI verdict vs baseline)

--fail-on high fails on any high — including findings you already know and accepted. The verdict endpoint compares against a baseline (e.g. the last scan from main) and fails only on regressions:

# after the scan completes (SCAN_ID from --wait / API response)
VERDICT=$(curl -s "$API/scans/$SCAN_ID/verdict?baseline_scan_id=$BASELINE_ID&fail_on=high" \
  -H "Authorization: Bearer $LIVEAPISEC_API_KEY")
[ "$(echo "$VERDICT" | python3 -c "import sys,json; print(json.load(sys.stdin)['verdict'])")" = "pass" ]

Response shape is stable for scripts: verdict, counts (new / fixed / persisting / blocking), plus full new, fixed, persisting lists (category, severity, title, target, status). Matching is by category + target + title. Both scans must belong to your organisation.

Scan depth: Baseline vs Deep

Every scan runs at a depth: baseline (8 fast deterministic tests — BOLA, auth, mass assignment, injection, rate limit, CORS, headers, sensitive params; seconds per endpoint, made for every commit) or deep (the full suite — JWT, method tampering, tech fingerprint, disclosure, rate-limit v2, API versions, GraphQL, OAuth, CORS chain, SSRF canary; for nightly runs and releases). Pass depth when triggering (POST /scans); default is deep (Live plan and up — Dev runs baseline; requesting deep on Dev returns 402). Typical setup: baseline on every push + verdict vs main, deep on schedule.

Compliance mapping

GET /scans/:id/compliance groups open findings per framework requirement — PCI DSS 4.0, SOC 2, ISO 27001, GDPR, NIS2 — so your auditor can locate technical evidence fast. The same view lives in the dashboard under scan details (SaaS plan and up). It is an indicative mapping, not a certification: silence on a requirement means no open findings in scanner scope, not proof of full compliance.

8. SDK (API)

Besides the CLI, the package also exports a Python client for scripts:

from liveapisec import LiveAPISec

api = LiveAPISec()  # LIVEAPISEC_API_KEY from env
project = api.create_project("my-api", "https://api.example.com",
                       endpoints=[{"method": "GET", "path": "/users"}])
scan = api.trigger_scan(project["project_id"], branch="main", commit="abc")
done = api.wait_for_scan(project["project_id"], scan["scan_id"])
blocked = LiveAPISec.findings_above(done["findings"], "high")

The same Developer API is plain REST — call it from any language

Not on Python? The endpoints behind the CLI are a standard REST API. Call them with curl, Node fetch, Go, Java, Ruby… anything that speaks HTTP:

# Node.js — push a project + endpoints from your app
const res = await fetch(API + '/developers/projects', {
  method: 'POST',
  headers: { Authorization: 'Bearer ' + DEV_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    name: 'my-api',
    base_url: 'https://api.example.com',
    endpoints: [{ method: 'GET', path: '/users' }],
  }),
});
const { project_id } = await res.json();   // → push the same project_id into your pipeline

# Go (net/http) — trigger a scan
req, _ := http.NewRequest("POST", API+"/developers/projects/"+projectID+"/scans", body)
req.Header.Set("Authorization", "Bearer "+DEV_KEY)
resp, _ := http.DefaultClient.Do(req)

The CLI simply wraps these same endpoints (see the GitHub repo for the full REST reference). So regardless of your stack you get the same result: endpoints pushed, scans run, findings readable by your agent or CI.

9. Copilot / AI coding assistants

The CLI is designed to be driven by an AI assistant. Paste the block below into your assistant (GitHub Copilot, Cursor, Windsurf…) so it can push your API, run the security test, read the findings and fix the issue itself, then re-test until the gate is green.

Copy-paste for your AI assistant

TASK: add LiveAPISec security testing to THIS repository, run it, and fix what it finds.

Full CLI/SDK documentation (read it if you need exact flags or the REST API):
https://liveapisec.com/docs

You are a coding agent. Execute the steps below now using the terminal — this message IS the task, not just a tool description. If a required value is missing (API key, base URL), ask the user for exactly that value and continue. Do not reply with only a status report.

## Goal — what you are setting up and why
There are two sides to this:
1. **Check the dev solution** — run the security tests against the reachable dev/staging
   URL while fixes are still cheap.
2. **Turn on the LIVE security side** — register the API on LiveAPISec so it can
   produce the live security status/certificate (Trust Page) that customers can see
   and that keeps updating with every scan. For that the URL MUST be correct: use
   the real, publicly reachable base URL of the environment you want covered
   (dev vs staging vs production), no path suffix, correct http/https. A wrong URL
   means the certificate/monitoring points at the wrong target.

You are ALLOWED to create the project yourself and to read everything
back — do it, don't just report. Use `liveapisec projects` /
`liveapisec project` /
`liveapisec status` to confirm what exists. The only thing you cannot create is the
API key (dashboard).

## Step 0 — Setup (do this first)
1. If `liveapisec` is not installed (`command -v liveapisec` fails), install it:
   curl -fsSL https://raw.githubusercontent.com/LiveApiSec/liveapisec/main/install.sh | bash
   (or: pipx install liveapisec — or pip install liveapisec inside a venv.)
   Verify with `liveapisec --help`.
2. Developer API key (env var LIVEAPISEC_API_KEY, looks like las_dev_...):
   - If it is already set in the environment, use it (CI always uses this secret).
   - If a token is already saved locally, `liveapisec whoami` confirms it — use that.
   - If not: ask the USER to authenticate once. Two options:
     a) interactive (recommended locally): the user runs  liveapisec login
        (browser device flow: prints a one-time code + opens
        https://liveapisec.com/cli/authorize) — you cannot click the browser for them;
     b) headless/CI: create a key at
        https://liveapisec.com/settings -> Developer API -> Create API key,
        then run  export LIVEAPISEC_API_KEY=las_dev_...   (or
        `liveapisec login --token las_dev_...`  to save it).
   - NEVER print, log, commit or hardcode the key — always read it from the environment.
   (The API key/login is the ONLY thing the CLI cannot obtain by itself — everything
   else, including the project, is created by the CLI commands below.)
3. URLs — do NOT confuse these three:
   - LiveAPISec platform API (what the CLI calls): https://api.liveapisec.com
     This is LIVEAPISEC_API_URL (default; only change it for self-hosted). The CLI
     already knows it — never probe or rewrite it yourself.
   - LiveAPISec dashboard / docs (browser only): https://liveapisec.com
     This is a static site. POSTing to it returns 405 by design — it is NOT the API.
     Never send API calls there.
   - YOUR API under test = the `--base-url` value. It is a different host; ask the
     user if unknown. Never guess it.
   If the CLI returns 502 / timeouts, the LiveAPISec platform may be briefly down —
   retry and report, do not change the URL.

## Step 1 — Find this project's endpoints
- Prefer source discovery:
  `liveapisec scan-code --dir . --name <api-name> --base-url <api-url> [--project <project>]`
  Supported frameworks: FastAPI, Flask, Django, Next.js (App+Pages), NestJS, Express,
  Laravel, PHP/Slim/Lumen, Spring, Go, Rust.
- If the project serves an OpenAPI spec, use `--openapi-url <url>` instead.
- If the base URL is unknown, ask the user — never guess production.

## Step 2 — Push (idempotent: same name + base_url = same project, safe to repeat)
You do NOT need a separate create-project command: a plain push without `--project`
creates a new project; pass `--project <id-or-slug>` (from `liveapisec projects`) to
update an existing one. Every `--project` accepts the project ObjectId **or** its
slug (e.g. `payments-api`) interchangeably. If the user didn't give a name, derive
one from the repo/directory name or ask; reuse an existing one with `liveapisec projects` when in doubt.
`liveapisec push --name <api-name> --base-url <api-url> --endpoint "GET /x" --endpoint "POST /y"`
Then export the returned id:  export PROJECT_ID=<project_id>   # or use the slug directly

ENVIRONMENTS = URLs IN ONE PROJECT. One project = one API (one endpoint set)
tested against many addresses. Do NOT create a separate project per environment —
add each environment as a URL (with its own schedule/version):
  `liveapisec urls add --project "$PROJECT_ID" --name dev     --url https://dev.acme.com`
  `liveapisec urls add --project "$PROJECT_ID" --name staging --url https://stg.acme.com --schedule 24h`
  `liveapisec urls add --project "$PROJECT_ID" --name prod    --url https://api.acme.com --schedule 24h`
Drift-aware scanning skips endpoints not deployed on a given URL, so dev can be
several versions ahead of prod without false coverage.
ACCESS: `--access internal` (dev/localhost/private) = NEVER auto-tested by the
scheduler — run it on demand only (`liveapisec scan --project <id>`, optionally
`--tunnel`). `--access external` (default) may be auto-tested; per-URL `--schedule`
is capped by the plan (e.g. Dev = CLI only, no schedule; Live/SaaS = daily). Setting a schedule on an internal
project is rejected. Localhost / private IPs need no domain verification. The scan
runs on LiveAPISec's scanner, so if the target is reachable only from your
machine, start a tunnel (keep it running in a separate terminal) — the CLI acts
as a proxy:
  `liveapisec connect --project "$PROJECT_ID"`                     # keep running
  `liveapisec scan --project "$PROJECT_ID" --wait --tunnel`        # other terminal
  `liveapisec hacker --project "$PROJECT_ID" --env development --wait --tunnel`  # AI agent, dev/staging only
If the target is on an internal network the scanner can reach (VPN/private IP),
no tunnel is needed.
If the API needs credentials, add:
  --auth-type jwt|bearer|api_key --auth-token "$TOKEN"   (or cookie, or oauth2 client credentials)
Use `--verify` to pre-flight the token before relying on it.

## Step 3 — Run a scan and read the findings
Shortcut for everything at once: `liveapisec all --project "$PROJECT_ID"` (scan → verdict → compliance → report + certificate PDF; exits 1 on regressions). With a second account available, add `--auth-token-b <jwt>` to enable the auth-matrix RBAC test (anon/A/B differential: broken tiers, BOLA, exposed admin paths — no source code needed). Or step by step:
`liveapisec scan --project "$PROJECT_ID" --branch <branch> --commit <sha> --wait`
`liveapisec findings --project "$PROJECT_ID" --scan <scan_id>`    (add --json for raw JSON)

## Step 4 — Fix and re-scan (the real deliverable)
1. Group findings by severity; start with critical/high.
2. Fix the actual code (BOLA/authZ, injection, mass assignment, rate limiting, headers/CORS…).
3. Re-push (idempotent) and re-scan until no critical/high remain.
4. Regression gate vs the baseline (e.g. last green scan): `liveapisec verdict --project "$PROJECT_ID" --scan <new> --baseline <base> --fail-on high` — exit 1 means NEW high/critical findings; fix those, never just re-baseline.
5. Optional evidence: `liveapisec compliance --project "$PROJECT_ID" --scan <scan_id>` (PCI DSS / SOC 2 / ISO 27001 / GDPR / NIS2, SaaS+), `liveapisec report --project "$PROJECT_ID" --scan <scan_id> -o report.json`, `liveapisec certificate --project "$PROJECT_ID" --scan <scan_id> --pdf -o cert.pdf` (passed scans only).
6. Report: files changed, findings fixed, and any false positives with evidence — do not silently "fix" those.

## Step 4b — Answer what the scanner cannot see (ask-mode, SaaS+)
Black-box tests stop at HTTP. Open a question session (AI extras about THIS api + 270 bank checks). The AI may first ask **clarifications** (SEC-ASK-CL-N, no priority) about the system — answer them with `--verdict info --note "..."`, then run `liveapisec ask followup` so the next round turns those facts into precise questions. Then answer each audit question by READING THE CODE and fix every fail:
`liveapisec ask new --project "$PROJECT_ID"` → `liveapisec ask run --session <id>` (verdicts pass|fail|na + evidence note, e.g. --note "argon2id in auth.py:42"). Each question has a priority (critical/high/medium/low); review with `liveapisec ask show --session <id> --only failed` (sorted critical-first). When your answers reveal weak spots, run `liveapisec ask followup --session <id> --until-dry` — the AI reads your answers (fails, notes, n/a) and adds deeper follow-up questions to the same session; answer those too. Failures appear in the Markdown report.

## Step 5 — Confirm the live security setup and report
- Re-read the registered objects and report them back:
  `liveapisec projects` (project + last test status), `liveapisec project --project "$PROJECT_ID"`,
  `liveapisec scans --project "$PROJECT_ID"`, `liveapisec status --project "$PROJECT_ID"`.
- If the live/production API is firewalled, note that the scanner must be able to
  reach the base URL (the dashboard shows the scanner IPs to allowlist) — otherwise
  the live certificate will have no data.
- State clearly which URL/environment is now covered and which one still needs to be added.

## Step 6 — Publish the live certificate
After a scan is green (no open critical/high), install the live certificate for a project.
The project slug is created automatically with the project (from its name):
  `liveapisec certificate --project "$PROJECT_ID"`                     — one project
  `liveapisec certificate --project "$PROJECT_ID" --url prod`          — one URL of that project
  `liveapisec certificate --project "$PROJECT_ID" --type badge`        — badge | banner | card | iframe
Paste the returned snippet (an `<a href=...>` wrapping `<div data-liveapisec-widget ...></div>`,
plus `widget.js`) into the site's footer / docs / trust page. The link is static in the
HTML (crawlable) and the whole widget is clickable. Certificates are per project
(the slug comes from the project name); the dashboard shows the embed under project →
Certificate. The certificate updates automatically with every scan — a live trust
signal, not a one-off PDF.

## Reference — inspect the portal from the terminal
- `liveapisec projects`              — every project + last test status
- `liveapisec scans --project <id>`    — full scan history (--json for raw)
- `liveapisec status --project <id>`   — project status + recent scans
- `liveapisec project --project <id>`    — project details
- `liveapisec findings --project <id> --scan <scan_id>`  — findings (--json for raw)
- `liveapisec whoami`                 — org, key prefix, scopes and expiry

## Rules
- Never print or commit the API key; use the environment variable.
- Push is idempotent — it is safe to run on every commit / CI run.
- Exit code 1 from `scan --wait --fail-on <sev>` = gate failed (findings at/above that severity); exit 2 = usage/API error.
- It works with APIs in ANY language/framework — not Python-only.

Or let the agent fetch it itself — the CLI serves the same prompt and the full documentation as plain text (no dashboard, no copy-paste):

$ liveapisec llm                          # short task prompt (same text as above)
$ liveapisec llm --project payments-api   # + PROJECT_ID / slug / base URL context
$ liveapisec llm --full                   # the whole /docs page as markdown
$ liveapisec llm --full --save AGENTS.md  # drop it into your repo for the agent

# public URLs — same content, no API key, any HTTP client (CI, agent, curl):
$ curl -s https://liveapisec.com/llms.txt
$ curl -s https://liveapisec.com/llms-full.txt

Answer what the scanner cannot see (ask-mode, SEC-ASK-N) (SaaS+)

Black-box tests stop at the HTTP boundary — the questionnaire covers the rest: 270 checkable questions (auth, RBAC, tenant isolation, crypto, business logic, SDLC) plus AI-tailored extras about your endpoints. Each question has a priority (critical/high/medium/low), so failures triage themselves. Paste the failures into the same Copilot prompt — it answers them by reading the code:

$ liveapisec ask new --project 65f...001
ask session created: 70a...009 (200 questions)
$ liveapisec ask run --session 70a...009   # interactive: pass | fail | na + evidence note
$ liveapisec ask followup --session 70a...009   # AI digs deeper based on your answers
$ liveapisec ask show --session 70a...009 --only failed   # review, fix code, re-answer
# failures appear in the Markdown report next to the findings

Example — Copilot self-repairs an issue from our test

Your CI just failed with exit 1 (gate failed). You ask your Copilot: "fix the failing security test". Here is the whole loop — the Copilot fetches everything from the terminal, no dashboard:

1) Sees what failed
   $ liveapisec projects
   svc
     api-a  https://api.example.com  last test: failed

2) Looks at the test history for the project
   $ liveapisec scans --project 65f...001
   scan 65f...002  status=failed  branch=main  commit=abc  findings=2

3) Reads the findings for the failed scan (raw JSON for the agent)
   $ liveapisec findings --project 65f...001 --scan 65f...002 --json
   [
     { "severity": "high", "category": "headers", "title": "Missing security headers",
       "target": "GET /users", "description": "no Content-Security-Policy header" },
     { "severity": "high", "category": "headers", "title": "HSTS not enabled",
       "target": "GET /users", "description": "Strict-Transport-Security missing" }
   ]

4) Fixes the code (adds a security-headers middleware), commits the fix

5) Re-pushes the endpoints (idempotent) and re-runs the gate
   $ liveapisec push --name api-a --base-url https://api.example.com --endpoint "GET /users"
   $ liveapisec scan --project 65f...001 --branch main --commit "$SHA" --wait --fail-on high
   ✓ scan completed — no findings at or above high

6) Confirms the gate is green
   $ liveapisec projects
   svc
     api-a  https://api.example.com  last test: completed · 42 tests · 0 findings

That is the whole idea: the CLI gives your Copilot read + write access to the security loop (fetch state → read findings → fix code → re-test → confirm green), so it can resolve issues end-to-end without a human opening the dashboard.

10. What each scan tests

Every scan runs a deterministic engine (no AI needed for detection) plus AI triage of the findings. Baseline suite (OWASP API Top 10): BOLA/IDOR, broken authentication, mass assignment, injection (SQL/NoSQL/JSON), rate limiting, CORS misconfiguration, security headers, sensitive parameters in URLs, shadow APIs. Deep-scan suite: JWT weaknesses (alg=none, tampered payload, weak HMAC secret, missing exp, kid injection), HTTP method tampering, privilege escalation via mass assignment (undeclared role fields echoed back exactly), server tech fingerprint with end-of-life version detection, information disclosure checklist (.git, .env, debug, actuator, metrics, public specs, stack traces), differential rate limits with X-Forwarded-For bypass check, old API version comparison (v1 vs v2 auth), GraphQL introspection and query-complexity check, OAuth redirect_uri open-redirect check, CORS null-origin / allowlist-bypass / CSRF-preflight chain, SSRF canary callback. Authenticated extras: auth-matrix RBAC (anon/A/B differential) and AI cross-layer probes — the LLM reads your endpoint shapes (roles, orgs, projects, invites) and invents up to 8 concrete probes outside the fixed suite, executed with a differential oracle (both identities 2xx but different bodies = possible cross-layer leak). Hacker mode (AI agent, dev/staging only) covers business-logic abuse on top. Findings carry category, severity, target and evidence (payloads, request/response) — visible in the dashboard under scan details. Two extras run when the scan is authenticated: the auth-matrix RBAC test (same endpoint requested as anonymous / identity A / identity B and diffed — broken tiers, confirmed BOLA, exposed admin paths; needs a second identity via --auth-token-b or a saved credential with slot B) and the AI test plan: one LLM call reads your OpenAPI (endpoints, methods, fields, auth) and tells the engine which tests matter per endpoint, in which order, and which identifiers to swap for BOLA — high-risk targets first, graceful fallback to the fixed order without AI.