API Reference
The fastest way to explore and test the API is the interactive Swagger UI at /api-playground. Every endpoint is documented with request/response schemas, and you can execute live API calls directly from your browser after setting your JWT token once.
ThreatWeaver exposes a REST API with 700+ endpoints across 41 route groups. The API is built on Express.js with TypeScript, uses JSON for all requests and responses, and requires JWT authentication on all endpoints except the initial login and setup flows.
Base URLsβ
| Environment | Backend API URL |
|---|---|
| Local development | http://localhost:4005/api |
| UAT / Dev | https://threatweaver-backend.onrender.com/api |
| Production (SaaS) | https://kina-vulnerability-management-uq1t.onrender.com/api |
Replace the base URL with your environment. All paths in this document are relative to /api.
Authenticationβ
Getting a Tokenβ
Standard login (username + password):
curl -X POST https://kina-vulnerability-management-uq1t.onrender.com/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "password": "YourPassword"}'
Successful response:
{
"token": "eyJhbGciOiJIUzI1NiJ9...",
"user": {
"id": "uuid",
"email": "user@example.com",
"role": "analyst",
"tenantId": "uuid",
"tenantSlug": "acme"
}
}
The token is also set as an HttpOnly cookie (token). Browser clients receive the token automatically via the cookie β no manual header handling needed.
Using the Tokenβ
For API clients, scripts, and CI/CD pipelines β pass the token as a Bearer header:
curl https://kina-vulnerability-management-uq1t.onrender.com/api/dashboard/kpis \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..."
In the Swagger playground β click Authorize at the top of /api-playground, enter your token in the Bearer field, and all subsequent calls in that session are authenticated.
Token Expiry and Refreshβ
| Token type | Default lifetime | Cookie path |
|---|---|---|
| Access token | 15 minutes (configurable via JWT_EXPIRES_IN) | / |
| Refresh token | 7 days (configurable via JWT_REFRESH_EXPIRES_IN) | /api/auth |
When the access token expires, call /api/auth/refresh to get a new one using the refresh token (which is sent automatically via cookie from the browser):
curl -X POST https://.../api/auth/refresh \
-H "Content-Type: application/json" \
--cookie "refreshToken=eyJhbGciOiJIUzI1NiJ9..."
CI/CD API Key Authenticationβ
For pipeline integrations where interactive login is not practical, ThreatWeaver supports X-API-Key header authentication on a subset of endpoints:
# AppSec CI scan trigger
curl -X POST https://.../api/appsec/ci/scan \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"targetUrl": "https://staging.example.com", "profile": "api-only"}'
API keys are managed in Admin β User Management β API Tokens. Each API key is scoped to a specific user's permissions.
API Conventionsβ
Versioningβ
The current API version is v1. The /api/ prefix is the version namespace β no explicit version segment is included in path URLs (e.g., /api/assets, not /api/v1/assets). Breaking changes will be introduced with explicit versioning.
Response Formatβ
Successful responses:
Most endpoints return data directly or in a data envelope:
{
"data": { ... },
"meta": {
"total": 1250,
"page": 1,
"limit": 50,
"totalPages": 25
}
}
Some endpoints return the payload directly without an envelope (especially auth endpoints):
{
"token": "...",
"user": { ... }
}
Paginated responses include a meta object with total, page, limit, and totalPages. Pass ?page=2&limit=100 as query parameters to navigate pages.
Error Response Formatβ
All errors follow this structure:
{
"error": "Error type (short string)",
"message": "Human-readable explanation",
"code": "MACHINE_READABLE_CODE"
}
Examples:
// 401 Unauthorized
{
"error": "Unauthorized",
"message": "No valid session or token found. Please log in again.",
"code": "NO_TOKEN"
}
// 403 Module disabled
{
"error": "MODULE_DISABLED",
"message": "Module not enabled in your license.",
"moduleId": "appsec"
}
// 423 License locked
{
"error": "LICENSE_LOCKED",
"message": "License is locked. Import a new license via Settings > License.",
"state": "LOCKED",
"canRecover": true,
"recoveryUrl": "/settings/license"
}
// 400 Validation error
{
"error": "Validation Error",
"message": "Invalid request body",
"details": [
{ "field": "email", "message": "Invalid email format" }
]
}
HTTP Status Codesβ
| Code | Meaning in ThreatWeaver context |
|---|---|
200 OK | Request succeeded |
201 Created | Resource created successfully |
204 No Content | Request succeeded, no body (e.g., DELETE) |
400 Bad Request | Validation error, malformed JSON, or invalid parameter |
401 Unauthorized | No token, invalid token, or expired token |
403 Forbidden | Authenticated but lacks permission, module disabled, or CSRF block |
404 Not Found | Resource does not exist or is not accessible to this tenant |
409 Conflict | Duplicate resource (e.g., email already registered) |
413 Payload Too Large | Request body exceeds 1 MB limit |
422 Unprocessable Entity | Semantically invalid request |
423 Locked | License locked or revoked |
429 Too Many Requests | Rate limit exceeded |
500 Internal Server Error | Unhandled server error (check backend logs) |
503 Service Unavailable | Database unreachable or service degraded |
Rate Limitsβ
| Endpoint category | Limit | Window | Notes |
|---|---|---|---|
/api/auth/login | 10 requests | 15 minutes | Per IP |
/api/auth/change-password | 10 requests | 15 minutes | Per IP |
/api/auth/mfa/validate | 10 requests | 15 minutes | Per IP |
/api/auth/forgot-password | 10 requests | 1 minute | Per IP |
/api/auth/invite | 5 requests | 1 minute | Per IP |
/api/auth/reset-password | 5 requests | 1 minute | Per IP |
All other /api/* routes | 100 requests | 1 minute | Per IP, configurable |
/api/appsec/* (read) | 2,000 requests | 1 minute | Per user, per-route |
/api/appsec/* (write) | 120 requests | 1 minute | Per user, per-route |
/api/dashboard/* | Exempt from global limit | β | High-traffic polling route |
Rate limit headers are included in every response:
RateLimit-Remaining: 87RateLimit-Reset: 1743812100
When the limit is exceeded, the response is 429 Too Many Requests with Retry-After indicating when to retry.
Endpoint Referenceβ
The following sections describe each route group. For full endpoint schemas and live testing, see the API Playground.
/api/auth/* β Authentication (17 endpoints)β
Handles all authentication flows. No license module required.
| Endpoint | Method | Description |
|---|---|---|
/auth/login | POST | Username/password login, returns JWT + sets cookie |
/auth/logout | POST | Revoke current session, clear cookies |
/auth/refresh | POST | Exchange refresh token for new access token |
/auth/me | GET | Get current authenticated user profile |
/auth/register | POST | Create a new user account (admin only in most deployments) |
/auth/change-password | POST | Change current user's password |
/auth/forgot-password | POST | Request password reset email |
/auth/reset-password | POST | Submit new password via reset token |
/auth/mfa/setup | POST | Initialize TOTP MFA (returns QR code and secret) |
/auth/mfa/validate | POST | Verify TOTP code during login |
/auth/mfa/disable | POST | Disable MFA for current user |
/auth/sso/callback | GET/POST | SSO/SAML callback handler |
/auth/select-tenant | POST | Select tenant (multi-tenant: for users with access to multiple tenants) |
/auth/switch-tenant | POST | Switch active tenant context |
/auth/invite | POST | Accept a user invitation |
/auth/verify-email | GET | Verify email address via token |
/auth/public-key | GET | Get the server's E2EE public key (unauthenticated) |
/api/dashboard/* β KPIs, Widgets, and Trends (30 endpoints)β
Requires vulnerability_dashboard module license.
| Endpoint | Method | Description |
|---|---|---|
/dashboard/kpis | GET | Core KPI summary: total assets, vuln counts by severity, risk score |
/dashboard/widgets | GET | Configurable widget data for the dashboard layout |
/dashboard/trends | GET | Vulnerability trend data (new, remediated, persisting) over time |
/dashboard/risk-score | GET | Composite risk score calculation |
/dashboard/severity-breakdown | GET | Vulnerabilities grouped by severity with counts |
/dashboard/asset-exposure | GET | Asset exposure heatmap data |
/dashboard/compliance-status | GET | Compliance control status summary |
/dashboard/sla | GET | SLA compliance metrics by severity tier |
/dashboard/anomalies | GET | Anomaly detection summary |
Query parameters accepted by most dashboard endpoints:
?startDate=2026-01-01&endDate=2026-04-01β date range filter?assetGroup=uuidβ filter by asset group?severity=CRITICAL,HIGHβ filter by severity (comma-separated)?tag=productionβ filter by asset tag
/api/assets/* β Asset Inventory (3 endpoints)β
Requires vulnerability_dashboard module license.
| Endpoint | Method | Description |
|---|---|---|
/assets | GET | Paginated asset list with search and filter support |
/assets/:uuid | GET | Single asset detail with full vulnerability count |
/assets/:uuid/vulnerabilities | GET | Vulnerabilities for a specific asset |
Query parameters for /assets:
?page=1&limit=50β pagination?search=hostnameβ text search across FQDN, IP, hostname?severity=CRITICALβ filter by worst-severity vulnerability on asset?tag=productionβ filter by tag?assetGroup=uuidβ filter by group
/api/vulnerabilities/* β Vulnerability Data (7 endpoints)β
Requires vulnerability_dashboard module license.
| Endpoint | Method | Description |
|---|---|---|
/vulnerabilities | GET | Paginated vulnerability list with rich filtering |
/vulnerabilities/:id | GET | Single vulnerability detail |
/vulnerabilities/search | POST | AI-powered natural language vulnerability search |
/vulnerabilities/export | GET | Trigger async CSV/JSON export job |
/vulnerabilities/stats | GET | Aggregate statistics for filter result |
/vulnerabilities/cve/:cve | GET | Vulnerabilities matching a specific CVE ID |
/vulnerabilities/plugin/:id | GET | Vulnerabilities by Tenable plugin ID |
/api/appsec/* β AppSec Assessments and Findings (113 endpoints)β
Requires appsec module license. Full endpoint list in the API Playground β key endpoints below.
| Endpoint | Method | Description |
|---|---|---|
/appsec/assessments | GET, POST | List or create assessments |
/appsec/assessments/:id | GET, PUT, DELETE | Assessment detail, update, delete |
/appsec/assessments/:id/launch | POST | Start an assessment scan |
/appsec/assessments/:id/stop | POST | Stop a running scan |
/appsec/assessments/:id/findings | GET | Findings for a completed assessment |
/appsec/findings | GET | Cross-assessment findings with filters |
/appsec/findings/:id | GET, PUT | Finding detail and status update |
/appsec/findings/:id/accept-risk | POST | Accept risk (suppress finding) |
/appsec/reports/:assessmentId | GET | Generate assessment report |
/appsec/agents | GET | List available scanner agent types |
/appsec/ci/scan | POST | CI/CD scan trigger (X-API-Key auth) |
/appsec/ci/status/:scanId | GET | Poll CI scan status |
/appsec/ci/results/:scanId | GET | Retrieve CI scan results |
/api/sync/* β Tenable Sync Management (18 endpoints)β
| Endpoint | Method | Description |
|---|---|---|
/sync/status | GET | Current sync status and last sync timestamp |
/sync/start | POST | Manually trigger a sync |
/sync/history | GET | Sync job history with durations and record counts |
/sync/config | GET, PUT | Sync configuration (interval, scope) |
/sync/progress | GET | Real-time progress of an in-progress sync |
/api/admin/* β User Management and Settings (48 endpoints)β
Requires admin role. No license module check β admin routes are always accessible to admins.
| Endpoint | Method | Description |
|---|---|---|
/admin/users | GET, POST | List users, create user |
/admin/users/:id | GET, PUT, DELETE | User detail, update, deactivate |
/admin/users/:id/reset-password | POST | Force password reset for a user |
/admin/roles | GET, POST, PUT | RBAC v2 role management |
/admin/settings | GET, PUT | Global tenant settings |
/admin/settings/license | GET, PUT | License status and import |
/admin/settings/feature-flags | GET, PUT | Feature flag configuration |
/admin/security | GET | Security audit log |
/admin/security/ip-whitelist | GET, POST, DELETE | IP allowlist management |
/admin/security/ip-blacklist | GET, POST, DELETE | IP blocklist management |
/admin/archives | GET, POST, DELETE | Scan data archive management |
/api/reports/* β Report Management (6 endpoints)β
Requires compliance_reporting module license.
| Endpoint | Method | Description |
|---|---|---|
/reports | GET | List generated reports |
/reports | POST | Create and generate a new report |
/reports/:id | GET | Report detail and download link |
/reports/:id/schedule | POST | Schedule recurring report |
/reports/templates | GET | Available report templates |
/api/scanner/* β Scan Sensor Management (168 endpoints)β
Requires scanner_management module license.
| Endpoint | Method | Description |
|---|---|---|
/scanner/sensors | GET, POST | List sensors, enroll a new sensor |
/scanner/sensors/:id | GET, PUT, DELETE | Sensor detail, update, remove |
/scanner/sensors/:id/tasks | GET | Tasks assigned to a sensor |
/scanner/relays | GET, POST | Relay (gateway) management |
/scanner/targets | GET, POST | Scan target configuration |
/scanner/schedules | GET, POST, PUT | Scan scheduling |
/api/sso/* β SSO Configuration (7 endpoints)β
| Endpoint | Method | Description |
|---|---|---|
/sso/config | GET, PUT | SSO provider configuration |
/sso/metadata | GET | SAML service provider metadata (XML) |
/sso/test | POST | Test SSO configuration |
/sso/providers | GET | List configured SSO providers |
/sso/role-mapping | GET, PUT | Map IdP groups to ThreatWeaver roles |
/api/ai/* β AI Features (37 endpoints)β
Requires ai_features module license.
| Endpoint | Method | Description |
|---|---|---|
/ai/fix-plan | POST | Generate an AI-powered fix plan for a vulnerability |
/ai/ticket | POST | Draft a remediation ticket (Jira/ServiceNow format) |
/ai/exec-summary | POST | Generate executive summary for a vulnerability set |
/ai/root-cause | POST | Root cause analysis for a finding |
/ai/chat | POST | Conversational AI assistant for security questions |
/ai/search | POST | Natural language vulnerability search |
/ai/audit/export | GET | Export AI usage audit log |
/api/webhooks/* β Webhook Receiver Management (2 endpoints)β
| Endpoint | Method | Description |
|---|---|---|
/webhook-receivers | GET, POST | List or configure inbound webhook handlers |
/webhook-receivers/:id | DELETE | Remove a webhook receiver |
/api/license/* β License Management (6 endpoints)β
| Endpoint | Method | Description |
|---|---|---|
/license/status | GET | Current license state and claims (lightweight β only state and modules) |
/license/activate | POST | Activate license from JWT (works in UNLICENSED state without auth) |
/license/import | POST | Import a renewed license (requires admin role) |
/license/events | GET | License audit event log |
/license/check-seats | GET | Current seat usage vs. licensed maximum |
Other Route Groupsβ
| Group | Endpoints | Description |
|---|---|---|
/api/vfp/* | 90 | Vulnerability Fix Planner β work packages, teams, SLA policies, exceptions |
/api/integration/* | 15 | Jira, ServiceNow, Slack integration configs |
/api/export/* | 7 | Async CSV/PDF export job management |
/api/notification/* | 7 | Notification channels and user preferences |
/api/security/* | 14 | Security audit log queries, IP management |
/api/tags/* | 10 | Asset tagging |
/api/asset-groups/* | 8 | Asset group management |
/api/sbom/* | 7 | Software Bill of Materials |
/api/saved-filters/* | 4 | Saved filter presets |
/api/ai-security/* | 12 | AI model inventory, risk assessment, governance |
/api/anomaly/* | 5 | Anomaly detection data |
Using the API from Codeβ
JavaScript / TypeScript (fetch)β
const BASE_URL = 'https://kina-vulnerability-management-uq1t.onrender.com/api'
// Login and retrieve token
async function login(email: string, password: string): Promise<string> {
const response = await fetch(`${BASE_URL}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
})
if (!response.ok) throw new Error(`Login failed: ${response.status}`)
const data = await response.json()
return data.token
}
// Authenticated request helper
async function apiGet(path: string, token: string): Promise<any> {
const response = await fetch(`${BASE_URL}${path}`, {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.message || `API error: ${response.status}`)
}
return response.json()
}
// Example: get dashboard KPIs
const token = await login('user@example.com', 'password')
const kpis = await apiGet('/dashboard/kpis', token)
console.log('Total assets:', kpis.totalAssets)
JavaScript / TypeScript (axios)β
import axios from 'axios'
const api = axios.create({
baseURL: 'https://kina-vulnerability-management-uq1t.onrender.com/api',
headers: { 'Content-Type': 'application/json' },
})
// Login
const loginResponse = await api.post('/auth/login', {
email: 'user@example.com',
password: 'password',
})
const token = loginResponse.data.token
// Set token for all subsequent requests
api.defaults.headers.common['Authorization'] = `Bearer ${token}`
// Fetch paginated vulnerabilities
const vulns = await api.get('/vulnerabilities', {
params: { severity: 'CRITICAL', page: 1, limit: 50 },
})
console.log(`${vulns.data.meta.total} critical vulnerabilities`)
Pythonβ
import requests
BASE_URL = "https://kina-vulnerability-management-uq1t.onrender.com/api"
def login(email: str, password: str) -> str:
response = requests.post(f"{BASE_URL}/auth/login", json={
"email": email,
"password": password
})
response.raise_for_status()
return response.json()["token"]
def api_get(path: str, token: str, params: dict = None) -> dict:
headers = {"Authorization": f"Bearer {token}"}
response = requests.get(f"{BASE_URL}{path}", headers=headers, params=params)
response.raise_for_status()
return response.json()
# Example: fetch all critical vulnerabilities (paginated)
token = login("user@example.com", "password")
page = 1
all_vulns = []
while True:
data = api_get("/vulnerabilities", token, {
"severity": "CRITICAL",
"page": page,
"limit": 100
})
all_vulns.extend(data["data"])
if page >= data["meta"]["totalPages"]:
break
page += 1
print(f"Total critical vulnerabilities: {len(all_vulns)}")
CI/CD Pipeline (GitHub Actions example)β
# .github/workflows/appsec-scan.yml
name: AppSec Security Scan
on:
push:
branches: [main]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- name: Trigger AppSec scan
id: trigger
run: |
RESPONSE=$(curl -sf -X POST ${{ secrets.TW_API_URL }}/api/appsec/ci/scan \
-H "X-API-Key: ${{ secrets.TW_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{
"targetUrl": "https://staging.example.com",
"profile": "api-only",
"branch": "${{ github.ref_name }}"
}')
SCAN_ID=$(echo $RESPONSE | jq -r '.scanId')
echo "scan_id=$SCAN_ID" >> $GITHUB_OUTPUT
- name: Wait for scan completion
run: |
for i in $(seq 1 30); do
STATUS=$(curl -sf \
-H "X-API-Key: ${{ secrets.TW_API_KEY }}" \
"${{ secrets.TW_API_URL }}/api/appsec/ci/status/${{ steps.trigger.outputs.scan_id }}" \
| jq -r '.status')
echo "Scan status: $STATUS"
if [ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ]; then
break
fi
sleep 60
done
- name: Check for critical findings
run: |
RESULTS=$(curl -sf \
-H "X-API-Key: ${{ secrets.TW_API_KEY }}" \
"${{ secrets.TW_API_URL }}/api/appsec/ci/results/${{ steps.trigger.outputs.scan_id }}")
CRITICAL=$(echo $RESULTS | jq '.findings | map(select(.severity == "CRITICAL")) | length')
echo "Critical findings: $CRITICAL"
if [ "$CRITICAL" -gt "0" ]; then
echo "::error::$CRITICAL critical security findings discovered"
exit 1
fi
Multi-Tenant Behaviorβ
In multi-tenant deployments, no tenant headers are needed. The tenant is resolved automatically from the authenticated user's JWT payload (tenantId and tenantSlug claims). All queries are automatically scoped to that tenant's PostgreSQL schema.
A user cannot access another tenant's data even with a valid token β the schema isolation is enforced at the database level.
If you are building a multi-tenant admin tool (e.g., a custom provisioning script), use the TLM (ThreatWeaver License Manager) API rather than the ThreatWeaver application API.
No Official SDKβ
There is no official ThreatWeaver client SDK at this time. The code examples above (fetch, axios, Python requests) represent the recommended approach. The API follows standard REST conventions, so any HTTP client library works.
Endpoint schemas for all 700+ endpoints are available in the OpenAPI 3.0 specification served at /api-docs/swagger.json. You can generate typed client code from this spec using tools like openapi-generator, swagger-codegen, or the TypeScript-first orval.
# Generate a TypeScript client using orval
npx orval --input https://kina-vulnerability-management-uq1t.onrender.com/api-docs/swagger.json \
--output ./src/api-client \
--client axios