Skip to content

GET /v1/projects/{id}/alerts

Alerts are created automatically when a CVE matches an item in a project’s stack. Each alert includes the associated CVE metadata (CVSS score, severity, KEV, PoC).

GET /api/v1/projects/{project_id}/alerts
Authorization: Bearer twa_your_key_here
ParameterTypeDescription
project_idUUIDProject identifier
ParameterTypeDefaultDescription
unread_onlybooleanfalseIf true, returns only unread alerts
severitystringFilter by severity (comma-separated). Values: CRITICAL, HIGH, MEDIUM, LOW
sincedatetime (ISO 8601)Returns only alerts triggered after this date
pageinteger ≥ 11Page number
limitinteger 1–20050Alerts 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
},
{
"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
}
],
"total": 42,
"unread_count": 7
}
FieldTypeDescription
itemsarrayAlerts on the current page
totalintegerTotal alerts matching the active filters
unread_countintegerTotal unread alerts in this project (independent of filters)
FieldTypeDescription
idstring (UUID)Alert identifier
cve_idstringCVE identifier (e.g. CVE-2024-11477)
triggered_atstring (ISO 8601)Trigger timestamp
is_readbooleantrue if the alert was marked as read in the app
severitystringCVE severity: CRITICAL, HIGH, MEDIUM, LOW, NONE, UNKNOWN
descriptionstring | nullEnglish description of the CVE
vendorstring | nullIdentified primary vendor
productstring | nullIdentified primary product
cvss_scorefloat | nullCVSS score (0.0 – 10.0)
is_kevbooleantrue if listed in the CISA KEV catalog
has_pocbooleantrue if at least one public PoC is known (nomi-sec/PoC-in-GitHub)

GET /api/v1/projects/{project_id}/alerts/{alert_id}
Authorization: Bearer twa_your_key_here
ParameterTypeDescription
project_idUUIDProject identifier
alert_idUUIDAlert identifier

Same structure as a list item.

CodeDetailCause
404Projet introuvableproject_id does not exist
403Accès refusé à ce projetProject not accessible
404Alerte introuvablealert_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/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
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}/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"}
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}/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.")