Skip to main content
Version: Local Β· In Progress

API Reference

Interactive API Playground

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​

EnvironmentBackend API URL
Local developmenthttp://localhost:4005/api
UAT / Devhttps://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 typeDefault lifetimeCookie path
Access token15 minutes (configurable via JWT_EXPIRES_IN)/
Refresh token7 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​

CodeMeaning in ThreatWeaver context
200 OKRequest succeeded
201 CreatedResource created successfully
204 No ContentRequest succeeded, no body (e.g., DELETE)
400 Bad RequestValidation error, malformed JSON, or invalid parameter
401 UnauthorizedNo token, invalid token, or expired token
403 ForbiddenAuthenticated but lacks permission, module disabled, or CSRF block
404 Not FoundResource does not exist or is not accessible to this tenant
409 ConflictDuplicate resource (e.g., email already registered)
413 Payload Too LargeRequest body exceeds 1 MB limit
422 Unprocessable EntitySemantically invalid request
423 LockedLicense locked or revoked
429 Too Many RequestsRate limit exceeded
500 Internal Server ErrorUnhandled server error (check backend logs)
503 Service UnavailableDatabase unreachable or service degraded

Rate Limits​

Endpoint categoryLimitWindowNotes
/api/auth/login10 requests15 minutesPer IP
/api/auth/change-password10 requests15 minutesPer IP
/api/auth/mfa/validate10 requests15 minutesPer IP
/api/auth/forgot-password10 requests1 minutePer IP
/api/auth/invite5 requests1 minutePer IP
/api/auth/reset-password5 requests1 minutePer IP
All other /api/* routes100 requests1 minutePer IP, configurable
/api/appsec/* (read)2,000 requests1 minutePer user, per-route
/api/appsec/* (write)120 requests1 minutePer user, per-route
/api/dashboard/*Exempt from global limitβ€”High-traffic polling route

Rate limit headers are included in every response:

  • RateLimit-Remaining: 87
  • RateLimit-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.

EndpointMethodDescription
/auth/loginPOSTUsername/password login, returns JWT + sets cookie
/auth/logoutPOSTRevoke current session, clear cookies
/auth/refreshPOSTExchange refresh token for new access token
/auth/meGETGet current authenticated user profile
/auth/registerPOSTCreate a new user account (admin only in most deployments)
/auth/change-passwordPOSTChange current user's password
/auth/forgot-passwordPOSTRequest password reset email
/auth/reset-passwordPOSTSubmit new password via reset token
/auth/mfa/setupPOSTInitialize TOTP MFA (returns QR code and secret)
/auth/mfa/validatePOSTVerify TOTP code during login
/auth/mfa/disablePOSTDisable MFA for current user
/auth/sso/callbackGET/POSTSSO/SAML callback handler
/auth/select-tenantPOSTSelect tenant (multi-tenant: for users with access to multiple tenants)
/auth/switch-tenantPOSTSwitch active tenant context
/auth/invitePOSTAccept a user invitation
/auth/verify-emailGETVerify email address via token
/auth/public-keyGETGet the server's E2EE public key (unauthenticated)

Requires vulnerability_dashboard module license.

EndpointMethodDescription
/dashboard/kpisGETCore KPI summary: total assets, vuln counts by severity, risk score
/dashboard/widgetsGETConfigurable widget data for the dashboard layout
/dashboard/trendsGETVulnerability trend data (new, remediated, persisting) over time
/dashboard/risk-scoreGETComposite risk score calculation
/dashboard/severity-breakdownGETVulnerabilities grouped by severity with counts
/dashboard/asset-exposureGETAsset exposure heatmap data
/dashboard/compliance-statusGETCompliance control status summary
/dashboard/slaGETSLA compliance metrics by severity tier
/dashboard/anomaliesGETAnomaly 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.

EndpointMethodDescription
/assetsGETPaginated asset list with search and filter support
/assets/:uuidGETSingle asset detail with full vulnerability count
/assets/:uuid/vulnerabilitiesGETVulnerabilities 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.

EndpointMethodDescription
/vulnerabilitiesGETPaginated vulnerability list with rich filtering
/vulnerabilities/:idGETSingle vulnerability detail
/vulnerabilities/searchPOSTAI-powered natural language vulnerability search
/vulnerabilities/exportGETTrigger async CSV/JSON export job
/vulnerabilities/statsGETAggregate statistics for filter result
/vulnerabilities/cve/:cveGETVulnerabilities matching a specific CVE ID
/vulnerabilities/plugin/:idGETVulnerabilities 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.

EndpointMethodDescription
/appsec/assessmentsGET, POSTList or create assessments
/appsec/assessments/:idGET, PUT, DELETEAssessment detail, update, delete
/appsec/assessments/:id/launchPOSTStart an assessment scan
/appsec/assessments/:id/stopPOSTStop a running scan
/appsec/assessments/:id/findingsGETFindings for a completed assessment
/appsec/findingsGETCross-assessment findings with filters
/appsec/findings/:idGET, PUTFinding detail and status update
/appsec/findings/:id/accept-riskPOSTAccept risk (suppress finding)
/appsec/reports/:assessmentIdGETGenerate assessment report
/appsec/agentsGETList available scanner agent types
/appsec/ci/scanPOSTCI/CD scan trigger (X-API-Key auth)
/appsec/ci/status/:scanIdGETPoll CI scan status
/appsec/ci/results/:scanIdGETRetrieve CI scan results

/api/sync/* β€” Tenable Sync Management (18 endpoints)​

EndpointMethodDescription
/sync/statusGETCurrent sync status and last sync timestamp
/sync/startPOSTManually trigger a sync
/sync/historyGETSync job history with durations and record counts
/sync/configGET, PUTSync configuration (interval, scope)
/sync/progressGETReal-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.

EndpointMethodDescription
/admin/usersGET, POSTList users, create user
/admin/users/:idGET, PUT, DELETEUser detail, update, deactivate
/admin/users/:id/reset-passwordPOSTForce password reset for a user
/admin/rolesGET, POST, PUTRBAC v2 role management
/admin/settingsGET, PUTGlobal tenant settings
/admin/settings/licenseGET, PUTLicense status and import
/admin/settings/feature-flagsGET, PUTFeature flag configuration
/admin/securityGETSecurity audit log
/admin/security/ip-whitelistGET, POST, DELETEIP allowlist management
/admin/security/ip-blacklistGET, POST, DELETEIP blocklist management
/admin/archivesGET, POST, DELETEScan data archive management

/api/reports/* β€” Report Management (6 endpoints)​

Requires compliance_reporting module license.

EndpointMethodDescription
/reportsGETList generated reports
/reportsPOSTCreate and generate a new report
/reports/:idGETReport detail and download link
/reports/:id/schedulePOSTSchedule recurring report
/reports/templatesGETAvailable report templates

/api/scanner/* β€” Scan Sensor Management (168 endpoints)​

Requires scanner_management module license.

EndpointMethodDescription
/scanner/sensorsGET, POSTList sensors, enroll a new sensor
/scanner/sensors/:idGET, PUT, DELETESensor detail, update, remove
/scanner/sensors/:id/tasksGETTasks assigned to a sensor
/scanner/relaysGET, POSTRelay (gateway) management
/scanner/targetsGET, POSTScan target configuration
/scanner/schedulesGET, POST, PUTScan scheduling

/api/sso/* β€” SSO Configuration (7 endpoints)​

EndpointMethodDescription
/sso/configGET, PUTSSO provider configuration
/sso/metadataGETSAML service provider metadata (XML)
/sso/testPOSTTest SSO configuration
/sso/providersGETList configured SSO providers
/sso/role-mappingGET, PUTMap IdP groups to ThreatWeaver roles

/api/ai/* β€” AI Features (37 endpoints)​

Requires ai_features module license.

EndpointMethodDescription
/ai/fix-planPOSTGenerate an AI-powered fix plan for a vulnerability
/ai/ticketPOSTDraft a remediation ticket (Jira/ServiceNow format)
/ai/exec-summaryPOSTGenerate executive summary for a vulnerability set
/ai/root-causePOSTRoot cause analysis for a finding
/ai/chatPOSTConversational AI assistant for security questions
/ai/searchPOSTNatural language vulnerability search
/ai/audit/exportGETExport AI usage audit log

/api/webhooks/* β€” Webhook Receiver Management (2 endpoints)​

EndpointMethodDescription
/webhook-receiversGET, POSTList or configure inbound webhook handlers
/webhook-receivers/:idDELETERemove a webhook receiver

/api/license/* β€” License Management (6 endpoints)​

EndpointMethodDescription
/license/statusGETCurrent license state and claims (lightweight β€” only state and modules)
/license/activatePOSTActivate license from JWT (works in UNLICENSED state without auth)
/license/importPOSTImport a renewed license (requires admin role)
/license/eventsGETLicense audit event log
/license/check-seatsGETCurrent seat usage vs. licensed maximum

Other Route Groups​

GroupEndpointsDescription
/api/vfp/*90Vulnerability Fix Planner β€” work packages, teams, SLA policies, exceptions
/api/integration/*15Jira, ServiceNow, Slack integration configs
/api/export/*7Async CSV/PDF export job management
/api/notification/*7Notification channels and user preferences
/api/security/*14Security audit log queries, IP management
/api/tags/*10Asset tagging
/api/asset-groups/*8Asset group management
/api/sbom/*7Software Bill of Materials
/api/saved-filters/*4Saved filter presets
/api/ai-security/*12AI model inventory, risk assessment, governance
/api/anomaly/*5Anomaly 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