PatchFlow API · v1
Repo status
The single endpoint a SIEM needs: open CVEs, in-flight patch PRs, and the 30-day merge rollup for one watched repository. No token required.
GET
application/json
Public
URL pattern
Both path segments are validated against /^[A-Za-z0-9._-]+$/ (1–100 chars). Requests that don't match are rejected with 400 before any data lookup.
GET https://<host>/api/v1/repos/{owner}/{name}/status
- owner — GitHub org or user slug (1–100 chars).
- name — repository name (1–100 chars).
Authentication
Token-free by design.
No authentication is required. This endpoint is intentionally public so SIEM platforms can poll without provisioning or rotating API tokens. Rate limiting and abuse controls are applied at the edge; clients should respect standard back-off signals (HTTP 429 + Retry-After) rather than opening many concurrent connections.
HTTP semantics
Status codes the handler emits.
| Status | When | Body |
|---|---|---|
| 200 | Repo exists and is enabled. | RepoStatusResponse (JSON object). |
| 400 | Either path segment fails the regex / length check. | { "error": "invalid path" } |
| 404 | Repo is not in the watch list. | { "error": "Repo {owner}/{name} not found" } |
Response shape
Schemas live in src/lib/contracts/repo-status.ts (`RepoStatusResponse`). Integrate against those, not a hand-written copy.
repo
{ owner, name, defaultBranch, enabled, riskScore, lastCheckedAt }
- owner — GitHub org or user, copied from the URL path.
- name — repository name, copied from the URL path.
- defaultBranch — the branch GitHub reports as default.
- enabled — whether the watcher is currently polling this repo.
- riskScore— integer 0–100, nullable; the watcher's blended risk for this repo.
- lastCheckedAt — ISO-8601 timestamp; nullable when the watcher has never run.
openCves
Array of { ghsaId, cveId, cweIds, severity, summary, publishedAt, repoFullName }.
- ghsaId — GitHub Security Advisory id (e.g. GHSA-abcd-…).
- cveId — nullable; not every advisory has a CVE assignment.
- cweIds — list of CWE ids; empty array if none.
- severity — publisher severity label.
- summary — short advisory summary.
- publishedAt — ISO-8601 timestamp.
- repoFullName — denormalised {owner}/{name} so SIEM consumers don't have to thread the URL path back through their correlation.
patchArtifactSummary
{ inFlight, mergedLast30d, latestMergedAt }
- inFlight — count of patch artifacts whose PR is open but not yet merged.
- mergedLast30d — count of patches that merged in the trailing 30-day window.
- latestMergedAt — ISO-8601 timestamp of the most recent merge across the artifact set; null when none has ever merged.
Examples
Three idiomatic copies — the body fetched is identical in all three.
curl
curl -sS -X GET 'https://${HOST}/api/v1/repos/acme-co/widgets/status' \
-H 'Accept: application/json' \
-H 'User-Agent: patchflow-siem-poll/1.0'fetch (browser / Deno / Node 22+)
const response = await fetch(`https://${HOST}/api/v1/repos/acme-co/widgets/status`, {
method: 'GET',
headers: {
'Accept': 'application/json',
'User-Agent': 'patchflow-siem-poll/1.0',
},
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const body = await response.json();Python · requests
import os
import requests
host = os.environ['PATCHFLOW_HOST'] # e.g. https://api.patchflow.dev
url = f"{host}/api/v1/repos/acme-co/widgets/status"
headers = {'Accept': 'application/json'}
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
print(response.json())Sample response
A live call against /api/v1/repos/acme-co/widgets/status returns the JSON below. The body is constructed and zod-validated once at module load in src/lib/business/docs/repo-status-sample.ts, so the doc cannot drift from the live contract.
{
"repo": {
"owner": "acme-co",
"name": "widgets",
"defaultBranch": "main",
"enabled": true,
"riskScore": 68,
"lastCheckedAt": "2026-07-25T08:14:00.000Z"
},
"openCves": [
{
"ghsaId": "GHSA-abcd-1234-efgh",
"cveId": null,
"cweIds": [],
"severity": "high",
"summary": "Prototype pollution in utils.merge allows attackers to inject properties on Object.prototype.",
"publishedAt": "2026-07-23T17:02:00.000Z",
"repoFullName": "acme-co/widgets"
},
{
"ghsaId": "GHSA-wxyz-9876-lmno",
"cveId": "CVE-2026-31415",
"cweIds": [
"CWE-79",
"CWE-1321"
],
"severity": "critical",
"summary": "Reflected XSS in the legacy /search route renders attacker-controlled HTML without escaping.",
"publishedAt": "2026-07-19T12:45:00.000Z",
"repoFullName": "acme-co/widgets"
}
],
"patchArtifactSummary": {
"inFlight": 1,
"mergedLast30d": 1,
"latestMergedAt": "2026-07-22T19:31:00.000Z"
}
}