This document describes the public API surface exposed to customers.
/api/v1
Public APIs accept:
X-API-Key) — Registered / Pro / Enterprise users generate their own Fetch, MCP, and Malware-Firewall keys self-service from My Account (see PLATFORM_API_KEYS.md).Public APIs enforce tier-based response filtering for sensitive data.
Scoring formulas, weights, and internal rationale are not exposed in the public API.
Public Swagger UI is available in debug/non-production environments only (returns 404 in production):
GET /api/docsGET /api/openapi.jsonThe public OpenAPI schema is built from a default-deny allow-list of public endpoint prefixes. Admin (/api/v1/admin/*), any path with an /admin segment, the Vuln Weekly pipeline (/api/v1/vw/*), the MPI admin backend (/api/v1/malware-intel/*), exploit-recreation actions, and all /internal/* PAI routes are excluded — a new router does not appear in the public docs until explicitly allow-listed. The internal API docs (/internal/docs, /internal/openapi.json, /internal/redoc) are also debug-only and 404 in production.
| Tier | Access |
|---|---|
| FREE | Minimal fields |
| REGISTERED | Standard fields |
| PRO | Expanded fields |
| ENTERPRISE | Full fields (public plane only) |
/api/v1/graphql/api/v1/mcp/api/v1/* and /api/token-hub-registration/* (CVEs, analytics, EOL, premium package intelligence, BYOK registration, etc.)GET /api/v1/cves
The base collection route is the CVE search endpoint (there is no
/cves/search path). Available to FREE (subject to the search
daily quota); results are tier-filtered.
| Param | Type | Notes |
|---|---|---|
q | string | CVE ID prefix or description substring |
year | int (1999–2030) | Filter by CVE year |
severity | string | CRITICAL / HIGH / MEDIUM / LOW |
kev_only | bool | Only CISA KEV CVEs |
epss_min | float (0–1) | Minimum EPSS score |
sort | string | published[:desc|:asc] or cvss[:desc|:asc]; default year-descending |
published_after | YYYY-MM-DD | Inclusive lower publish-date bound |
published_before | YYYY-MM-DD | Inclusive upper publish-date bound |
has_analysis | bool | true → only Phoenix-analyzed CVEs; false → only un-analyzed |
limit | int (1–200) | Page size (Data-Shield pagination applies) |
offset | int | Pagination offset |
Every result carries a has_analysis flag. Recipes:
GET /api/v1/cves?severity=CRITICAL&sort=published:desc&limit=10GET /api/v1/cves?published_after=YYYY-MM-DD&sort=published:descGET /api/v1/cves?severity=CRITICAL&has_analysis=true
Related FREE reads: GET /api/v1/cves/by-product?vendor=&product=,
/cves/trending, /cves/kev, /cves/homepage/intel,
/cves/stats/{year}. Curated "Phoenix Intelligence" is
GET /api/v1/phoenix/high-profile (REGISTERED — auth required).
Gating v2 (enable_cve_search_gating_v2, default off): when
enabled, by-product requires an authenticated identity (401 otherwise), and
trending, kev, homepage/intel, and
kev-public/combined-exploited consume the search daily quota.
GET /api/v1/analysis/kev-public/combined-exploited
Returns the public combined exploited vulnerability catalog used by
exploited-vulnerabilities.html. The backend reads
web/data/kev_public/combined_exploited.json. Unavailable data returns
503.
ENABLE_CWE_OWASP_THREAT_TIERED_API
(default false). When the flag is off, all five endpoints below behave exactly as they did
before this feature — fully open, no tier shaping — so this is a safe no-op until enabled.
This is a payload-shaping feature, not a hard gate: none of these endpoints return 403 for tier
reasons, and every response is HTTP 200.
| Method | Path | Source dataset |
|---|---|---|
GET | /api/v1/analysis/cwe | cwe_analysis.json |
GET | /api/v1/analysis/cwe-top25 | cwe_top25_analysis.json |
GET | /api/v1/analysis/kev-cwe | kev_cwe_analysis.json |
GET | /api/v1/analysis/owasp-top10 | owasp_top10_analysis.json |
GET | /api/v1/analysis/reference-threat-frequencies | see note below — the data source itself is flag-gated, not just the shaping |
Each has a full-fidelity PAI mirror under /internal/v1/analysis/* — see PAI_INTERNAL_API.html.
| Caller | Payload |
|---|---|
| Anonymous / Free / Registered / Pro (JWT or API key) |
Shaped: CWE/OWASP category mappings, names, rankings, and MITRE links are unchanged
(public reference data). Proprietary numeric fields — raw NVD/H1/KEV/VulnCheck/GitHub PoC counts,
per-CWE and per-category statistics, threat_mapping counts, and yearly-trend raw numbers
— are converted to percentage shares only. The raw counts and the totals used to
derive a percentage are stripped together, so a caller cannot recompute the original count from the
shaped response.
|
| Enterprise (JWT) or global admin | Full numeric payload: raw counts, baseline_ratio, cross_dataset_analysis, and full yearly trends. |
PAI (X-PAI-Key, /internal/v1/analysis/*) |
Always full numeric payload — PAI access is itself the Enterprise gate; no additional tier parameter or header is needed. |
Because there is no 403 on these base routes, the existing public pages that already call them
(owasp-top10-analysis.html, cwe-top25-analysis.html, cwe.html,
kev-cwe-analysis.html, threat-analytics.html, index.html) continue to
work unmodified at every tier — an Enterprise upgrade only changes response richness, not
endpoint availability.
reference-threat-frequencies — data source is also flag-gated
Unlike the other four endpoints (which only gate the shaping step against an always-available source
file), /api/v1/analysis/reference-threat-frequencies also switches its underlying data
source on the same flag:
reference_threat_frequencies_public.json snapshot — byte-for-byte the same as before this feature shipped, no shaping applied, no tier awareness.reference_threat_frequencies.json (fresher; carries real cross_dataset_analysis, coverage_pct, nvd_representation_*) and shapes it per caller tier. As a result, Enterprise callers only receive the freshest, fullest data on this specific endpoint once the flag is enabled — before that, even an Enterprise caller only sees the older, pre-baked public snapshot.
For every distribution in this dataset (the baseline threat-type/threat-impact distributions, and
each per-dataset threat_type_frequencies/threat_impact_frequencies), Pro-and-below
callers receive %-only — count is never returned, and
baseline_ratio/cross_dataset_analysis are stripped/emptied. Threat-type and
threat-impact frequency of vulnerabilities is exposed as percentages only to any caller below Enterprise.
POST /api/v1/packages/intel
Returns package-version CVE intelligence plus premium MPI malware intelligence for Pro and Enterprise Intelligence API keys.
Gated by feature flag enable_package_intel_api (default false).
When the flag is off the endpoint returns 404 (not 403). Registered/basic
keys return 403.
Successful calls are counted as REST API calls and as mpi_package_intel_lookups
in MPI usage accounting.
{
"ecosystem": "Maven",
"name": "com.h2database:h2",
"version": "1.3.176"
}
| Field | Notes |
|---|---|
cves | Version-filtered OSV CVE/advisory records. |
vulnerabilities | Alias of cves. |
malware | Premium MPI malware summary. Raw signals, IOCs, scan IDs, and internal evidence are not exposed on the public plane. |
ps_oss_score | Derived package risk score. |
source_attribution | Sources used to build the response. |
/api/token-hub-registration
Gated by feature flag enable_token_hub_byok_registration (default
false). When the flag is off these endpoints return
404 (not 403).
Tenant identity is derived server-side from the authenticated user's database
tenant membership. Callers must not send customerId,
orgId, or userId.
BYOK onboarding, key registration, key revocation, and key listing require an authenticated user with Token Hub organization membership. Token Hub upstream availability/auth failures return 503; invalid upstream responses return 502; revoke for a missing key returns 404.
| Method | Path | Purpose |
|---|---|---|
POST | /api/token-hub-registration/byok/onboarding | Register tenant BYOK in one Token Hub onboarding call. |
POST | /api/token-hub-registration/byok/api-key | Register or replace a BYOK API key. |
POST | /api/token-hub-registration/byok/keys/{platform}/{vendor}/revoke | Revoke an active BYOK key. |
GET | /api/token-hub-registration/byok/keys | List BYOK key summaries; secretRef is never returned. |
Accepted platform values: blue, purple,
green. Accepted vendor values: openai,
anthropic, gemini.
{
"orgId": "bb610723-161c-4e63-807a-0ca0d207606f",
"keys": [
{
"orgId": "bb610723-161c-4e63-807a-0ca0d207606f",
"platform": "blue",
"vendor": "anthropic",
"displayName": "Anthropic Production Key",
"apiKey": "sk-ant-...here"
}
]
}
apiKey is a masked hint from Token Hub, not the raw secret.
secretRef remains internal to Token Hub client DTOs and is stripped
before returning public API responses.
GET /api/v1/ai-attributed-model-cves
Returns CVEs discovered, reported, or co-reported with the assistance of frontier AI models (Claude, GPT, Gemini, Llama, Grok) and AI-native security firms (AISLE).
Gated by feature flag enable_frontier_model_cve_intel (default false).
When the flag is off the endpoint returns 404 (not 403) so the feature's existence is not leaked.
Auth is optional: Free tier is rate-limited; Pro+ unlocks bulk access.
| Param | Type | Description |
|---|---|---|
provider | csv string | Filter by provider(s): anthropic,openai,google,meta,xai,aisle |
program | csv string | Filter by program: glasswing,quiltworks,madbugs |
min_confidence_tier | int (1–3) | Default 1 |
min_cvss | float | Default none |
since | ISO date | Filter discovered_date >= since |
cursor | string | Pagination cursor |
limit | int | Default 50, max 200 |
Tier-restricted fields are filtered through ResponseTransformer: confidence_tier and
credit_text/collaboration_chain require Pro+, the numeric confidence_score
requires Enterprise. The CSV variant
GET /api/v1/ai-attributed-model-cves.csv returns 501 Not Implemented in v1.0.
Flag: enable_scf_seat_licensing (default true in the current rollout). These endpoints return 404 when the flag is off.
GET /api/v1/firewall/licenseReturns the authenticated caller's organization SCF license, computed quota, and live usage.
Auth: Requires an authenticated user bound to an SCF organization.
{
"license": { "org_key": "acme", "tier": "registered", "base_seats": 3, "purchased_seats": 0, "endpoints_per_seat": null, "calls_per_seat": null, "tenant_id": "..." },
"quota": { "tier": "registered", "total_seats": 3, "endpoints_per_seat": 3, "calls_per_seat": 1000, "endpoint_topup": 0, "pooled": false, "endpoint_quota": 0, "call_quota": 0, "per_seat_endpoint_quota": 3, "per_seat_call_quota": 1000 },
"usage": { "seats_used": 2, "endpoints_used": 7, "calls_used": 1234 }
}
registered, pro, and enterprise. Legacy standard licenses normalize to pro; legacy free licenses normalize to registered.pooled = true only for Enterprise. Registered and Pro enforce per-seat monthly call and endpoint caps via per_seat_call_quota and per_seat_endpoint_quota.endpoint_quota = 0 / call_quota = 0 means the org is not pooled on that dimension. For Enterprise, 0 still means unlimited where endpoints_per_seat is 0.POST /api/v1/firewall/license/seat-requestSubmit a seat-purchase request. Global admins approve or reject the request; callers cannot allocate seats directly.
Request body: { "requested_seats": 10, "note": "optional" }. requested_seats must be greater than 0; note max 500 chars.
Response 200: Creates an scf_seat_request row with status: "pending".
Related: docs/Individual_Feature/2026-06-17-scf-seat-licensing.md
/api/v1/admin/*) and PAI/internal (/internal/v1/*) endpoints are excluded from the public schema.
Flag: enable_scf_seat_licensing (default false). All endpoints below return 404 when off.
GET /api/v1/firewall/licenseReturns the authenticated user's organization SCF license, computed quota, and live usage.
Auth: Requires authenticated user with an SCF organization.
Response 200:
{
"license": { "org_key": "acme", "tier": "pro", "base_seats": 25, "purchased_seats": 0, "endpoints_per_seat": null, "calls_per_seat": null, "tenant_id": "..." },
"quota": { "tier": "pro", "total_seats": 25, "endpoints_per_seat": 10, "calls_per_seat": 50000, "pooled": false, "endpoint_quota": 0, "call_quota": 0, "per_seat_endpoint_quota": 10, "per_seat_call_quota": 50000 },
"usage": { "seats_used": 2, "endpoints_used": 7, "calls_used": 1234 }
}
pooled is true only for Enterprise — org-wide endpoint_quota/call_quota are valid ONLY when pooled is true. For Registered/Pro (pooled: false), each user has their own allotment: per_seat_endpoint_quota/per_seat_call_quota. endpoint_quota/call_quota are 0 for non-pooled tiers — this means "not applicable," not "unlimited."pooled: true), endpoint_quota = 0 means unlimited.403 when caller has no org; 404 when flag off.POST /api/v1/firewall/license/seat-requestSubmit a seat-purchase request (global admin approves; caller cannot allocate seats directly).
Request body: { "requested_seats": 10, "note": "optional" } — requested_seats must be > 0, note max 500 chars.
Response 200: Created scf_seat_request row with status: "pending".
Related: docs/Individual_Feature/2026-06-17-scf-seat-licensing.md
Server-side sequential batch worker for draining Kanban columns. Admin-only (requires MPI pipeline enabled).
POST /api/v1/malware-intel/queue/bulk-processSchedule a bulk job; returns immediately with a job_id.
| Field | Type | Default | Description |
|---|---|---|---|
kanban_status | string | "awaiting_review" | Source column |
max_packages | int | 50 | Pipeline cap 1 000; approve_malicious cap 100 000 |
mode | string | "pipeline" | pipeline = analyst+judge; approve_malicious = confirm by score |
min_score | int|null | null | Only include packages with heuristic_score ≥ min_score |
batch_size | int | 50 | Items per batch (approve_malicious mode) |
pause_seconds | float | 0.0 | Pause between batches |
pipeline_steps | int | 2 | 1=analyst, 2=analyst+judge, 3=+verifier |
retry_inconsistent | bool | true | Re-run pair on analyst/judge disagreement |
reason | string | "" | Operator note for audit log |
400: invalid mode, max_packages exceeds cap, pipeline_steps not in {1,2,3}. 429: job already running.
GET /api/v1/malware-intel/queue/bulk-process/{job_id}/statusPoll job progress. Returns { job_id, status, processed, total, batch_index, batch_total, started_at, finished_at, errors, mode }. status: queued → running → complete | error.
Related: docs/Individual_Feature/2026-06-26-mpi-score-batch-confirm.md