Skip to content

GET /v1/organizations/{org_id}/projects/{id}/alerts

Alerts are created automatically when a vulnerability matches an item in a project’s stack: a CVE, or a GHSA or OSV advisory without a CVE identifier. The cve_id field carries the primary identifier. aliases lists the others, and fusion_de lists advisories that became this vulnerability (the case history is kept).

GET /api/v1/organizations/{org_id}/projects/{project_id}/alerts
Authorization: Bearer twa_your_key_here
Parameter Type Description
org_id UUID Organization identifier
project_id UUID Project identifier
Parameter Type Default Description
unread_only boolean false If true, returns only unread alerts
severity string — Filter by severity (comma-separated). Values: CRITICAL, HIGH, MEDIUM, LOW
since datetime (ISO 8601) — Returns only alerts triggered after this date
page integer ≥ 1 1 Page number
limit integer 1–200 50 Alerts per page
{
"items": [
{
"id": "018e9999-0000-7000-8000-000000000030",
"cve_id": "CVE-2024-11477",
"triggered_at": "2024-11-05T14:32:00Z",
"is_read": false,
"severity": "CRITICAL",
"description": "7-Zip contains a heap-based buffer overflow vulnerability...",
"vendor": "7-zip",
"product": "7-zip",
"cvss_score": 7.8,
"is_kev": false,
"has_poc": true,
"tags": [
{ "id": "018ec0de-0000-7000-8000-0000000000a1", "name": "production", "color": "#ef4444" },
{ "id": "018ec0de-0000-7000-8000-0000000000a2", "name": "to-patch", "color": "#f59e0b" }
]
},
{
"id": "018e9999-0000-7000-8000-000000000031",
"cve_id": "CVE-2024-38816",
"triggered_at": "2024-09-13T08:00:00Z",
"is_read": true,
"severity": "HIGH",
"description": "Applications serving static resources through the functional web...",
"vendor": "vmware",
"product": "spring_framework",
"cvss_score": 7.5,
"is_kev": false,
"has_poc": false,
"tags": []
}
],
"total": 42,
"unread_count": 7
}
Field Type Description
items array Alerts on the current page
total integer Total alerts matching the active filters
unread_count integer Total unread alerts in this project (independent of filters)
Field Type Description
id string (UUID) Alert identifier
cve_id string CVE identifier (e.g. CVE-2024-11477)
triggered_at string (ISO 8601) Trigger timestamp
is_read boolean true if at least one member has read the alert. The key is nobody: reading stays the team’s
severity string CVE severity: CRITICAL, HIGH, MEDIUM, LOW, NONE, UNKNOWN
description string | null English description of the CVE
vendor string | null Identified primary vendor
product string | null Identified primary product
cvss_score float | null CVSS score (0.0 – 10.0)
is_kev boolean true if listed in the CISA KEV catalog
has_poc boolean true if at least one public PoC or exploit is known (GitHub via nomi-sec/PoC-in-GitHub, Exploit-DB, Metasploit, Nuclei)
tags array<Tag> Team tags assigned to this CVE in this project (see Tag object)

Organization-wide shared vocabulary, assigned by the team to a CVE within a project. Empty array if none.

Field Type Description
id string (UUID) Tag identifier
name string Label (e.g. production, to-patch)
color string Hex color #rrggbb

GET /api/v1/organizations/{org_id}/projects/{project_id}/alerts/{alert_id}
Authorization: Bearer twa_your_key_here
Parameter Type Description
org_id UUID Organization identifier
project_id UUID Project identifier
alert_id UUID Alert identifier

Same structure as a list item.

Code Detail Cause
404 Projet introuvable Project does not exist, belongs to another organization, or is outside the key’s project restriction
403 Cette clé API n'a pas le droit d'accéder à cette ressource. The alerts scope is missing from the key
404 Alerte introuvable alert_id does not exist or does not belong to this project

Unread critical alerts from the last 30 days

Fenêtre de terminal
SINCE=$(date -u -d '30 days ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \
|| date -u -v-30d +%Y-%m-%dT%H:%M:%SZ)
curl -s \
-H "Authorization: Bearer twa_your_key_here" \
"https://app.techwatchalert.com/api/v1/organizations/${ORG_ID}/projects/${PROJECT_ID}/alerts?severity=CRITICAL,HIGH&unread_only=true&since=${SINCE}&limit=100" \
| jq '.items[] | {cve: .cve_id, score: .cvss_score, kev: .is_kev, poc: .has_poc}'

CI/CD script — fail build on critical CVE with PoC

#!/bin/bash
set -euo pipefail
ORG_ID="${TWA_ORG_ID}"
PROJECT_ID="${TWA_PROJECT_ID}"
API_KEY="${TWA_API_KEY}"
BASE="https://app.techwatchalert.com/api/v1"
CRITICAL_POC=$(curl -sf \
-H "Authorization: Bearer ${API_KEY}" \
"${BASE}/organizations/${ORG_ID}/projects/${PROJECT_ID}/alerts?severity=CRITICAL&unread_only=true&limit=200" \
| jq '[.items[] | select(.has_poc == true)] | length')
if [ "$CRITICAL_POC" -gt 0 ]; then
echo "ERROR: ${CRITICAL_POC} critical CVE(s) with PoC unaddressed."
exit 1
fi
echo "OK — no critical CVEs with PoC."

Python — export alerts to CSV

import csv, httpx
from datetime import datetime, timedelta, timezone
BASE = "https://app.techwatchalert.com/api/v1"
headers = {"Authorization": "Bearer twa_your_key_here"}
org_id = "018e5678-abcd-7000-8000-000000000001"
project_id = "018e1234-abcd-7000-8000-000000000010"
since = (datetime.now(timezone.utc) - timedelta(days=7)).isoformat()
page, all_alerts = 1, []
while True:
r = httpx.get(
f"{BASE}/organizations/{org_id}/projects/{project_id}/alerts",
headers=headers,
params={"since": since, "limit": 200, "page": page},
).json()
all_alerts.extend(r["items"])
if len(all_alerts) >= r["total"]:
break
page += 1
with open("alerts.csv", "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=["cve_id", "severity", "cvss_score", "is_kev", "has_poc", "triggered_at"])
w.writeheader()
w.writerows(all_alerts)
print(f"{len(all_alerts)} alerts exported.")

Same scope as alerts (alerts). Each advisory is shown with its primary identifier, its aliases, its tier (a_patcher, haute, or none) and the stack matches.

GET /api/v1/organizations/{org_id}/projects/{project_id}/vulnerabilities
Authorization: Bearer twa_your_key_here
Parameter Description
source ghsa or osv
palier a_patcher, haute or aucun