Service status
Uptime is the wrong question for a data service. This endpoint answers whether the answer you are about to get can be trusted: how far behind each source is, measured rather than promised, and which checks could not be made.
GET /api/v1/statusThere is a human rendering of the same document at cve.vulnpatch.dev/signal. They read the same data, so they cannot drift.
Response
{
"success": true,
"data": {
"answering": true,
"safeToActOn": true,
"measurementAvailable": true,
"measurementStale": false,
"primarySource": {
"id": "cve-list-v5",
"medianLatencyMinutes": 25.1,
"p90LatencyMinutes": 61.1,
"medianLagMinutes": 25.1,
"p90LagMinutes": 61.1,
"withinThirtyMinutesPct": 61.6
},
"sources": [
{
"id": "cve-list-v5",
"count": 3030,
"p50Minutes": 25.1,
"p90Minutes": 61.1,
"p99Minutes": 1321,
"withinThirtyMinutesPct": 61.6,
"ours": true
}
],
"kevEntries": 1705,
"degraded": [],
"unavailable": [],
"schedulerFailedTasks": [],
"schedulerBlockedTasks": [],
"upstreams": [],
"measuredOver": 4524,
"unmeasurable": 156,
"seenBeforePublished": 185,
"computedAt": "2026-09-11T11:31:45Z"
}
}medianLatencyMinutes/p90LatencyMinutes are the current names; medianLagMinutes/p90LagMinutes carry the identical value for a caller written against the older names.
schedulerFailedTasks/schedulerBlockedTasks name which scheduler tasks, if any, are currently failed or blocked -- blocked meaning a known, non-disruptive condition rather than a genuine failure. upstreams is a parallel panel for third-party dependencies (currently ENISA EUVD): each entry's status, whether its history is kept, and which scheduler tasks feed it.
Some upstreams (currently Repology) are mirrored from outside the scheduler, so their row also carries mirrored/mirroredAt (whether a copy is held, and when it was last proved complete) and, separately, lastAttempt: {at, success, reason} for the most recent attempt to refresh that copy, or null if none has been reported. lastAttemptFailedSinceMirror is true only when that attempt failed and happened no earlier than the copy currently being served. These are deliberately distinct from mirrored/ mirroredAt: a copy can still be within its staleness grace period while the very next attempt to refresh it has already failed, and the two facts do not collapse into one.
Repology's row is a statusFromMirror upstream: as of 2026-10-21, status comes entirely from whether this dump copy is present and its most recent refresh succeeded, not from whether this service's own direct calls to Repology succeed. Repology's maintainer asked bulk consumers to stop making those calls (repology/repology-rs#568), and this service's own network path to Repology has separately been refused since 2026-09-13 for a reason never determined -- a standing, non-actionable condition that reporting as a live incident taught nothing. blockedReason explains the architecture, not an incident; tasks still names the scheduler tasks that read this copy, for context, even though none of them affect status.
unmeasurable counts records this service holds but could not compute a latency for (no upstreamAvailableAt to measure from). seenBeforePublished counts records this service observed before their own publication timestamp -- a real, not an erroneous, measurement: some sources publish out of clock order.
The field that matters
safeToActOn goes false when a source an answer depends on could not be read. An agent about to change a production dependency can stop on this rather than discover the gap afterwards.
It is deliberately conservative. A missing freshness measurement sets it false even though the API is still answering, because a service that cannot say how fresh its data is has no business telling you it is fresh.
What the latency means
Latency runs from a record being published to this service being able to serve it. It therefore includes the publisher's own propagation as well as ours, and upstreamAvailableAt on a record is what separates the two where the source provides it.
Sources are reported separately, never blended. Their tails differ in kind: the CVE Program list is a live feed, GitHub republishes historical advisories in bulk, and the NixOS security review waits on human adjudication. A single combined number would describe none of them.
Only the source marked ours: true has a latency this service controls.
ENISA EUVD appears among upstream dependencies. A scheduled archive walks publication months and separately revisits records by update date. Its euvdCoverage block reports historicalRecords from completed publication windows, the dated sourceTotal observed at ENISA, historicalPercent, lastCompletedMonth, scanningMonth, scanningUpdatedDay, scanningUpdatedPage, updatedThrough and lastSuccessfulAt. updatedThrough is null until the first update-date window has completed; it is not an error while scanningUpdatedDay and scanningUpdatedPage show active progress. A partial backfill is not reported as a complete mirror. The percentage is backfill progress, not proof that every record is current. The EUVD row is marked mirrored only after the historical count agrees with the observed total and the update scan and source count are recent. An absent block means no successful archive checkpoint has been reported; an outage does not turn a partial archive into a complete one. Exact-ID lookups prefer ENISA and can use verified archived records if ENISA is unavailable.
What it does not measure
Records never indexed do not appear here, so this measures latency and not coverage. A source that is silent about a CVE contributes nothing to these figures.
Honest absences
measurementAvailable: falsemeans no measurement exists. It is never reported as zero latency.measurementStale: truemeans the measurement is over two hours old and describes a service that has since moved on.kevEntries: nullor0means the exploitation catalogue could not be read as a non-empty catalogue.kevappears inunavailableandsafeToActOnis false; this is not the same as nothing being known-exploited.