liveapisec — CLI/SDK for the LiveAPISec Developer API
Official, thin client for the LiveAPISec Developer API. Install it once, use it in any project, script and CI/CD pipeline — no dashboard, no curl.
When to use this? 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.
Which APIs does it work with? (not Python-only)
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:
| Language | Frameworks recognized by scan-code |
|---|---|
| Python | FastAPI · Flask · Django |
| JS/TS | 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…) — the
CLI just wraps those endpoints. See the SDK section below and the
in-browser docs at https://liveapisec.com/docs.
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. After installing, open a new terminal and run liveapisec --help.
From PyPI (recommended for developers with pipx/venv)
pipx install liveapisec # or: pip install liveapisec (inside a venv)
From GitHub (if you prefer building from the repository)
pip install "liveapisec @ git+https://github.com/LiveApiSec/liveapisec.git"
Verify:
liveapisec --version # e.g. liveapisec 0.1.39
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.
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).
First run (interactive)
The first time you run a command that needs the API (e.g. push, scan), 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; dashboard is liveapisec.com)
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
Commands
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 https://a.example.com
2) 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.
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. - Local spec file (no server-side fetch, works with localhost/private URLs that
--openapi-urlblocks):--spec-file ./openapi.json(JSON/YAML, parsed locally). The full spec is uploaded — parameters, request bodies, schemas andsecurityare preserved (so the scanner tests them), not just method+path. - Optional token:
--auth-type jwt --auth-token <TOKEN>(orbearer,cookie --auth-cookie "session=...",api_key --auth-header X-API-Key). For short-lived JWT login flows, use--auth-type login(see below). - Per-URL automation:
--schedule 6h|12h|24h|weekly(capped by your plan) and--access external|internal.internal(dev/localhost/private) is never auto-tested by the scheduler — run it on demand via CLI; setting a schedule on an internal URL is rejected.
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"
Login (username/password) — short-lived JWTs
Many APIs issue a short-lived JWT at a login endpoint. Instead of pasting a token that expires, give the login URL + credentials — the scanner logs in at every scan and uses the returned token:
liveapisec push --name my-api --base-url https://api.example.com \
--auth-type login \
--auth-login-url https://api.example.com/auth/login \
--auth-username qa@example.com --auth-password "$PASSWORD" \
--endpoint "GET /me"
# optional: --auth-token-field data.access_token (dot path, default access_token)
# --auth-username-field email --auth-password-field password
# --auth-body json|form
Clerk (or any JWT-login) — mint a fresh token per scan
If your API is protected by Clerk (or another short-lived-JWT provider with a backend/machine API), give the scanner a backend secret + a test user — it mints a fresh session JWT at every scan (no expired-token problem):
liveapisec push --name my-api --base-url https://api.example.com \
--auth-type clerk \
--auth-clerk-secret "$CLERK_TEST_SECRET" \
--auth-clerk-user user_xxx \
--auth-clerk-org org_xxx \
--endpoint "GET /me"
For cross-tenant / IDOR testing add a second test user (another org):
liveapisec hacker --project PROJECT_ID --env dev --thorough \
--auth-type-b clerk --auth-clerk-secret "$CLERK_TEST_SECRET" \
--auth-clerk-user user_BBBB --auth-clerk-org org_BBBB
Use a test Clerk instance (never production). The secret is stored AES-encrypted and never reaches the AI. Tokens are minted via
POST /v1/sessions→POST /v1/sessions/{id}/tokens.
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
--verifyare informational — your machine may not reach the API while our scanner can; what matters is the auth result (2xx vs 401/403).
Output:
project 65f...abc: my-api — 2 endpoints, auth=none
export PROJECT_ID=65f...abc
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.
The scan runs 100% locally: your code never leaves the machine. Only the
extracted endpoint list (METHOD + path) is sent to the API. (The old name
push-code still works as an alias.)
cd my-project
liveapisec scan-code --dir . --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). - Scan a git repository straight from a URL (https / ssh / local path) — it is shallow-cloned to a temp dir and cleaned up afterwards:
liveapisec scan-code --repo git@github.com:acme/my-api.git \
--name my-api --base-url https://api.example.com
- Preview before pushing (no API key needed):
liveapisec scan-code --dir . --name my-api --base-url https://api.example.com --dry-run
liveapisec scan-code --dir . --name my-api --base-url https://api.example.com --dry-run --json
- Force a framework if auto-detection misses it:
--framework nextjs.
Output:
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
urlpatternsand Gonet/httphandlers do not — those routes are assumed to beGET.
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). When it finishes, the CLI prints a short summary — risk level, coverage (tested/not deployed) and points to improve (each finding with a one-line fix). Full descriptive report:liveapisec report --format md.--url <name>— test the project's endpoints against a specific URL (a project can have several URLs — dev/staging/prod — all sharing the same endpoints; seeliveapisec project --project PROJECT_IDorliveapisec urls --project PROJECT_ID). Each URL can pin a spec version (liveapisec urls set --name prod --version X). Without--url, the project's defaultbase_urlis used.--fail-on high— exit code 1 when a finding of severityhigh/criticalis found;--fail-on criticalonly for criticals; omit it → always exit 0 (except errors).
4. hacker — autonomous AI hacker-mode test (destructive — dev/staging only)
Runs the autonomous AI agent ("real human test") against a dev/staging environment: the LLM plans an attack, probes endpoints step by step (IDOR/BOLA, broken auth, injections, secrets, mass assignment), can write and run its own probe code in a sandbox, self-corrects, and writes a final evaluation. You watch the agent think live in the dashboard.
# dev/staging only — NEVER production (it can break/destroy a system)
liveapisec hacker --project PROJECT_ID --env development
liveapisec hacker --project PROJECT_ID --env staging --wait
# guided mode — give the agent a specific objective (TODO 3.6.2)
liveapisec hacker --project PROJECT_ID --env development \
--goal "check /users for IDOR — your record vs another user's"
# two identities — differential IDOR/RBAC (A vs B): the agent can send as a/b/anon
liveapisec hacker --project PROJECT_ID --env development --wait \
--goal "find IDOR" --auth-type-b bearer --auth-token-b "$USER_B_JWT"
# destructive mode (default is READ-ONLY) — allows POST/PUT/PATCH/DELETE
liveapisec hacker --project PROJECT_ID --env development --wait --destructive
# localhost / internal target — through a connected CLI tunnel (terminal 1:
# `liveapisec connect --project PROJECT_ID`, keep running)
liveapisec hacker --project PROJECT_ID --env development --wait --tunnel
--env— environment name defined on the project (e.g.development,staging). Production environments are rejected (403).--goal— optional guided attack objective (e.g. "check /users for IDOR", "try to escalate to admin", "enumerate secrets"). Without it the agent explores freely.--destructive— default is READ-ONLY (onlyGET/HEAD/OPTIONS); write methods are blocked by the server. Add--destructiveto allow state-changing methods (mass assignment, writes) on dev/staging.--thorough— "real hacker" mode: no step/request limits (ignores the AI cost budget), ALL endpoints in context (not just top-12), a deterministic recon pass (harvests object IDs from responses + an A/B/anon differential matrix → auto-IDOR) and maximal persistence (it does not stop at the first 401/403/404). Use with--auth-token-bfor cross-identity tests.--auth-token-b/--auth-type-b— a second identity; the agent can send the same request asa,bandanonand compare — a confirmed IDOR is whenb/anonreceivesa's data. Needs the project's main credential (slot A) too.--wait— polls until the AI agent finishes. When it finishes, the CLI prints a short summary: risk level, requests/steps, the attack plan (with revisions), the agent's recommendations, and the request/step budget.- Domain verification: public targets need a verified domain (the dashboard
Domains flow). Localhost / private IPs (e.g.
http://localhost:8000,10.x) are exempt — no domain verification needed for your own local server. - Your API URL and credentials are never sent to the AI — only relative paths reach the model; requests are executed server-side in a sandbox. If the project has credentials, the agent runs authenticated (it only learns a flag, not the token) and can test IDOR/BOLA and privilege escalation as a real user.
5. status — project status + recent scans
liveapisec status --project PROJECT_ID
6. 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)
7. verdict — CI regression gate (new/fixed vs baseline)
Compares the scan against a baseline (e.g. last green deploy): new findings
are regressions, fixed disappeared, persisting were already known. Exits 1
when NEW findings reach --fail-on (default: high) — the real fix-and-rescan gate:
liveapisec verdict --project PROJECT_ID --scan NEW_SCAN --baseline BASE_SCAN --fail-on high
8. compliance — PCI DSS / SOC 2 / ISO 27001 / GDPR / NIS2 (SaaS+)
Illustrative mapping of open findings onto framework requirements (with disclaimer — not a certification):
liveapisec compliance --project PROJECT_ID --scan SCAN_ID
9. report — full saved scan report (summary + points to improve)
liveapisec report --project PROJECT_ID --scan SCAN_ID -o report.json # save to file
liveapisec report --project PROJECT_ID --scan SCAN_ID --json # print to stdout
liveapisec report --project PROJECT_ID --scan SCAN_ID --format md -o report.md
The Markdown report (--format md / -o *.md) is the descriptive post-test
summary:
- scan summary + coverage (
tested/not deployed on this URL), - Summary — risk level + how many points to improve,
- Points to improve — prioritized, each with Why (from the scan) and Fix (how to remediate); failed questionnaire answers are included too with their fix,
- findings table + compliance mapping +
asksection.
10. ask — answer what the scanner cannot see (SEC-ASK-N, SaaS+)
Black-box tests stop at the HTTP boundary. ask opens a question session:
270 checkable questions (SEC-ASK-1 … SEC-ASK-270: auth, RBAC, tenant
isolation, crypto, business logic, SDLC…) plus AI-tailored extras about YOUR
endpoints. The first AI pass may also add clarifications (no priority) about
your system — role names, tenant model, internal endpoints; answer them, then run
ask followup and the next round turns those facts into precise questions — roles, org layers, edge cases. You (or your LLM) answer
pass / fail / na by reading the source code, each with the fix and
an evidence note. Every question carries a priority (critical/high/medium/low) — from the bank's category+pattern rules and, for AI questions, judged by the model; failures are sorted critical-first in the CLI, the panel and the Markdown report. Failures land in the Markdown report next to the findings:
liveapisec ask new --project PROJECT_ID # fresh session (270 + AI)
liveapisec ask sessions --project PROJECT_ID # pass/fail counts per session
liveapisec ask answer --session SES --question SEC-ASK-5 --verdict fail --note "no MFA in auth.py"
liveapisec ask run --session SES # interactive walkthrough
liveapisec ask answer --session SES --question SEC-ASK-CL-1 --verdict info --note "roles: owner/admin/developer/viewer" # answer a clarification
liveapisec ask followup --session SES # AI adds deeper questions from your answers
liveapisec ask followup --session SES --rounds 3 # several AI passes (deduped)
liveapisec ask followup --session SES --until-dry # repeat until a pass adds nothing (cap 5)
liveapisec ask show --session SES --only failed # review failures
10. certificate --pdf — download the certificate (passed scans only)
liveapisec certificate --project PROJECT_ID --scan SCAN_ID --pdf --variant full -o cert.pdf
liveapisec certificate --project PROJECT_ID --scan SCAN_ID --pdf --variant client -o cert-client.pdf
0. all — full pipeline in one command (scan → verdict → compliance → report → PDF)
Numbered 0 because it's the easiest path: queues a scan, waits, compares
against the baseline (explicit --baseline or auto = previous completed scan),
prints the verdict, saves the report + certificate PDF, and exits 1 on
regressions. Compliance below plan and a missing certificate (scan didn't pass)
are notes, not errors:
liveapisec all --project PROJECT_ID
liveapisec all --project PROJECT_ID --baseline BASE_SCAN --fail-on high --variant client
liveapisec all --project PROJECT_ID --hacker --env development # hacker-mode instead (destructive — dev/staging only)
Auth-matrix RBAC test — two identities, no source code needed
Role checks (user role vs organization role, cross-tenant isolation) can't be tested with one token. Pass a second identity and the scanner diffs every endpoint as anonymous / A / B: secured endpoints reachable anonymously, A allowed where B is blocked (inconsistent tiers), confirmed BOLA (A reads two different objects), and admin paths exposed to A:
# CI: two tokens from secrets (e.g. a low-priv user + an admin)
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"
- Identity A = the scan's normal auth (saved credential in
Settings → Credentials, or
--auth-type/--auth-tokenon push). - Identity B =
--auth-token-b(transient: encrypted server-side, lives only on this scan) or a saved credential with slot B (panel/CI reuse). - Findings land in category
rbac(high/medium) and flow into verdict → report (md) → compliance → PDF like everything else.
11. project — project details
Shows the project's endpoints count, default base_url, schedule — and the
list of URLs (all tested with the same endpoints). Each URL can test a pinned
spec version (latest or a snapshot). Run a scan against one with
scan --url <name>.
liveapisec project --project PROJECT_ID
# project 65f...: my-api — 12 endpoints
# base_url: https://api.example.com
# urls (same endpoints tested against each):
# - development: https://api.dev.example.com [schedule=6h]
# - staging: https://api.stage.example.com
# - production: https://api.example.com [version=1.0.3]
15. urls — manage URLs (environments) of a project
One endpoint set, many addresses (dev/staging/prod). Each URL has its own spec
version (latest or a snapshot), schedule and paused. See
URLs, versions & certificate.
# list
liveapisec urls --project PROJECT_ID
# add (same endpoints tested against each URL)
liveapisec urls add --project PROJECT_ID --name dev --url https://dev.example.com
liveapisec urls add --project PROJECT_ID --name prod --url https://api.example.com
# pin a spec version / set schedule / pause
liveapisec urls set --project PROJECT_ID --name prod --version 1.0.3
liveapisec urls set --project PROJECT_ID --name prod --schedule 24h
liveapisec urls set --project PROJECT_ID --name prod --paused
# remove
liveapisec urls rm --project PROJECT_ID --name dev
--version accepts latest (default) or a version from
liveapisec project/the Versions tab. Adding/updating with an unknown version is
rejected (400) — no silent testing of the wrong spec.
16. versions — list spec versions of a project
Shows every snapshot of the endpoint set (newest first): version, endpoints
count, date, change note, which URLs pin it (used by) and which is current.
Use a version with urls set --version.
liveapisec versions --project PROJECT_ID
# versions of project 65f... (newest first):
# 1.0.3 (current) 42 endpoints 2026-09-21 merge: +3 endpoints used by: dev
# 1.0.2 40 endpoints 2026-09-18 edited GET /users used by: prod
# 1.0.0 38 endpoints 2026-09-10 initial push (CI/CD)
liveapisec versions --project PROJECT_ID --json # raw list (for scripts / agents)
17. delete — delete a project
Removes the project and all its data (scans, findings, URLs, versions,
credentials, certificate). Asks for confirmation unless --yes.
liveapisec delete --project PROJECT_ID
liveapisec delete --project acme --yes
12. 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
13. 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 dashboard:
$ 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
# Only one project
liveapisec projects --project svc
9. certificate — live certificate URL + embed snippet
After a scan is green, publish the live certificate. Choose the scope: whole organisation (default), one project, or a single URL.
liveapisec certificate # whole organisation
liveapisec certificate --scope project --project acme
liveapisec certificate --scope project --project PROJECT_ID
liveapisec certificate --type badge # badge | banner | card | iframe
# which URL the PUBLIC project certificate concerns (not shown publicly):
liveapisec certificate --project PROJECT_ID --url production
liveapisec certificate --project PROJECT_ID --url "" # back to the default base_url
Paste the returned snippet (an <a href=...> wrapping <div data-liveapisec-widget ...>,
plus widget.js) into your project, docs or trust page. The link is static in the HTML
(crawlable) and the whole widget is clickable — it updates with every scan.
The public certificate can be generated for any URL, but the public project certificate reflects one selected URL (its status is computed only from that URL's scans). The URL itself is never shown on the public page/widget — see URLs, versions & certificate.
14. 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:
# terminal 1 — keep running
liveapisec connect --project PROJECT_ID
# terminal 2 — route the scan 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
Only the project's base_url host is forwarded (not an open proxy).
Full documentation: see the in-browser docs at https://liveapisec.com/docs (install, config, every command, auth/OAuth2, exit codes, GitHub Actions, SDK).
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: Full pipeline — scan, regression gate, report, certificate
id: sectest
env:
LIVEAPISEC_API_KEY: ${{ secrets.LIVEAPISEC_KEY }}
run: |
liveapisec push --name my-api --base-url "$BASE_URL" \
--endpoint "GET /users" --endpoint "POST /payments"
liveapisec all --project "$PROJECT_ID" --fail-on high \
--format md --report-out security-report.md
- name: Upload security report + certificate
if: always()
uses: actions/upload-artifact@v4
with:
name: liveapisec-report
path: |
security-report.md
liveapisec-certificate-*.pdf
How a failure shows up in CI: all exits 1 when NEW findings reach
--fail-on (compared against the baseline = previous completed scan), so the
Full pipeline step turns red and the workflow fails — exactly like a failing
test suite. The Markdown report (security-report.md) is attached as an
artifact either way (if: always()), so reviewers see which findings are new:
open the run → Artifacts → liveapisec-report. The same exit-code contract
works in GitLab CI, Jenkins or plain bash (set -e stops the pipeline on
regressions). For agents/AI parsing, use --json on verdict/scan instead.
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
scantests the latest state.
Exit codes
| Code | Meaning |
|---|---|
| 0 | OK (verdict: pass — no NEW findings at/above the threshold) |
| 1 | Gate failed — NEW findings at/above --fail-on vs baseline (verdict/all) |
| 2 | Usage error / API error / scan did not complete |
Development / tests
pip install -e ./cli[dev]
cd cli && python -m pytest tests/ -q
SDK (API)
Python
Besides the CLI, the package also exports a 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")
From any other language — plain REST
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 — you get
the same result as the CLI (endpoints pushed, scans run, findings readable by
your agent or CI):
# push a project + endpoints from any language
curl -X POST $LIVEAPISEC_API_URL/developers/projects \
-H "Authorization: Bearer $LIVEAPISEC_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"my-api","base_url":"https://api.example.com",
"endpoints":[{"method":"GET","path":"/users"}]}'
# trigger a scan
curl -X POST $LIVEAPISEC_API_URL/developers/projects/$PROJECT_ID/scans \
-H "Authorization: Bearer $LIVEAPISEC_API_KEY" \
-d '{"branch":"main","commit":"abc123"}'
Instructions for AI coding assistants (Copilot, Cursor, etc.)
Copy-paste the block below into your AI assistant (GitHub Copilot, Cursor, Windsurf…) to let it use the LiveAPISec CLI on your behalf.
You can use the `liveapisec` CLI (https://pypi.org/project/liveapisec/) to
push API specifications, run security scans and read results against the
LiveAPISec platform. It works with APIs in ANY language/framework (not just
Python) — use `scan-code` to extract endpoints from source, or
`push --openapi-url` for an OpenAPI spec.
Environment:
- `LIVEAPISEC_API_KEY` — dev API key (las_dev_...), usually already set.
- `LIVEAPISEC_API_URL` — API base URL (default: https://api.liveapisec.com).
- `PROJECT_ID` — the project id returned by `liveapisec push` / `liveapisec project`.
Fetch information about the portal (to diagnose and fix issues):
- `liveapisec projects` — every project + last test status
- `liveapisec scans --project <id>` — full test history for a project (--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)
Language note: the CLI is written in Python, but it tests APIs built in ANY
language/framework — Python, Node.js, Go, Rust, Java, PHP, Ruby, .NET, etc.
Use `liveapisec scan-code` to auto-extract endpoints from the source
(FastAPI, Flask, Django, Next.js, NestJS, Express, Laravel, PHP/Slim, Spring,
Go, Rust), or `push --openapi-url` for any API that exposes an OpenAPI spec.
Workflow:
1. Push the API under test (idempotent — safe to repeat):
`liveapisec push --name <name> --base-url <url> --endpoint "METHOD /path" [--endpoint ...] [--openapi-url <url>] [--auth-type jwt|bearer|cookie|api_key --auth-token <token>]`
2. Run a security scan and wait for the result:
`liveapisec scan --project <project_id> --branch <branch> --commit <sha> --wait`
3. Read findings (severity, title, target):
`liveapisec findings --project <project_id> --scan <scan_id>` (add `--json` for raw JSON).
Self-repair loop (fix an issue from our test, end-to-end):
1. See what failed: `liveapisec projects`
2. Find the failed scan: `liveapisec scans --project <project_id>`
3. Read the findings: `liveapisec findings --project <project_id> --scan <scan_id> --json`
4. Fix the code (e.g. add a security-header middleware), commit.
5. Re-push (idempotent) and re-run the gate:
`liveapisec push --name <name> --base-url <url> --endpoint "GET /x"`
`liveapisec scan --project <project_id> --branch <branch> --commit <sha> --wait --fail-on high`
6. Confirm the gate is green: `liveapisec projects`
Rules:
- Never print or commit the API key; use the environment variable.
- If a scan fails, read the findings, fix the code, re-push and re-scan.
- Push is idempotent, so re-running it is always safe.
- Exit code 1 from `scan --wait --fail-on <sev>` means the gate failed
(findings at/above that severity); exit 2 means usage/API error.
Auth profile (auto-detected on scan)
After every scan the CLI/API detect and store which endpoint groups require
authentication (universal: from observed 401/403 on GET/HEAD probes and the
OpenAPI per-operation security — works even if the spec is incomplete). See it
with liveapisec project --project PROJECT_ID:
auth schemes (from spec): HTTPBearer(http), DevApiKey(http)
auth requirements (from last scan):
- /api-specs: requires auth (25 auth / 0 public of 25) [HTTPBearer]
- /developers: requires auth (35 auth / 0 public of 35) [HTTPBearer, DevApiKey]
- /public: public (0 auth / 6 public of 6)
credentials configured: clerk, api_key
It also feeds the report as a coverage gap: an endpoint group that requires auth but has no matching credential was tested unauthenticated — so the results don't cover it. Add the right credential (or a per-identity scan) to test it for real.
Credentials per-prefix — mixed auth in one scan
Some APIs expose different auth mechanisms on different routes (e.g. user
JWT/Clerk on the core API, but machine api_key tokens on /developers/*). A
single credential can't authenticate both. Bind a credential to a path prefix
and the scanner picks the right one per request (longest prefix wins):
liveapisec credentials set --project PROJECT_ID --slot a \
--auth-type bearer --auth-token "$CLERK_JWT" # default (all routes)
liveapisec credentials set --project PROJECT_ID --slot devkey --path /developers \
--auth-type api_key --auth-token "$DEV_KEY" --auth-header X-API-Key
liveapisec credentials --project PROJECT_ID
# - slot=a bearer prefix=(default)
# - slot=devkey api_key prefix=/developers
liveapisec credentials rm --project PROJECT_ID --slot devkey
One scan now authenticates both groups; the auto auth profile confirms
it (both shown as public/2xx instead of requires auth). If a group still
shows requires auth, its credential is missing/wrong.
Release files for liveapisec 0.1.39
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| liveapisec-0.1.39.tar.gz | 95.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| liveapisec-0.1.39-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 152.2 kB
Release files / liveapisec-0.1.39.tar.gz
| Download URL | liveapisec-0.1.39.tar.gz |
|---|---|
| Size | 95.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1c89bac27e9c03c3ce80e383fa56fbe216b11a6c1b70fa31bed4d9bc823f4fdf
|
|
BLAKE2b-256 checksum How to use checksums |
552894248f48dba230c3ac09cbfdee63834c0de0d772e03870a1eb4aea003bd3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / liveapisec-0.1.39-py3-none-any.whl
| Download URL | liveapisec-0.1.39-py3-none-any.whl |
|---|---|
| Size | 56.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d99635351cdaffbccddeab46899a1667bd3d783d39b9558c16f7077fec232823
|
|
BLAKE2b-256 checksum How to use checksums |
c25742ecd27c2dd0a5e4227520d634b8fd9061dc2bcfa5678f91a5df2576db5f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|