Die patchletter-API liefert Update-Daten als JSON

patchletter beantwortet per GET, welche Proxmox-VE-Version aktuell ist, was davor kam, welche KEV-Treffer daran hängen und wann der Support endet. Lesen kostet nichts und braucht keinen Account.

Auth & Rate-Limits

Ein persönlicher API-Key ist optional und hebt dein Rate-Limit an. Anlegen kannst du ihn im Dashboard.

Ohne Key

60 req/min · IP

60 Requests/Minute pro IP-Adresse. Standard für alle unauthentifizierten Anfragen.

Mit API-Key

600 req/min · Key

600 Requests/Minute pro Key — 10× mehr. Kostenlos, ein Key pro Account.

API-Key im Dashboard anlegen

Key mitschicken als Bearer-Token oder eigener Header — beide sind gleichwertig:

curl -H "Authorization: Bearer pk_live_YOUR_KEY" "https://patchletter.com/api/v1/products"

# äquivalent:
curl -H "X-API-Key: pk_live_YOUR_KEY" "https://patchletter.com/api/v1/products"

Jede Antwort trägt X-RateLimit-Limit, X-RateLimit-Remaining und X-RateLimit-Reset (Unix-Zeitstempel). Bei Überschreitung liefert die API 429 rate_limited inkl. Retry-After-Header:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1770000000
Retry-After: 23

{ "error": { "code": "rate_limited", "message": "Rate limit exceeded — try again later." } }

Ressourcen

Alle Endpunkte liegen unter der Basis-URL https://patchletter.com/api/v1 und liefern JSON. Listen sind als { data, pagination } gekapselt; pagination.nextCursor ist ein opaker String — unverändert an ?cursor= zurückgeben, nicht selbst parsen.

GET/api/v1/products

Produktliste

Gefilterte, sortierte, paginierte Liste aller aktiven Produkte. Filter: category (exakter Kategorie-Slug), q (Freitextsuche über Name/Hersteller/Slug), cursor, limit (1–100, Default 50).

Beispiel

curl "https://patchletter.com/api/v1/products?category=server-datenbanken&limit=2"

Beispiel-Response

{
  "data": [
    {
      "slug": "nginx",
      "name": "nginx",
      "vendor": "F5 / nginx",
      "category": "server-datenbanken",
      "subcategory": "Reverse Proxy",
      "websiteUrl": "https://nginx.org",
      "isHardware": false,
      "latestVersion": "1.27.4",
      "latestReleasedAt": "2026-02-05T00:00:00.000Z"
    },
    {
      "slug": "postgresql",
      "name": "PostgreSQL",
      "vendor": "PostgreSQL Global Development Group",
      "category": "server-datenbanken",
      "subcategory": null,
      "websiteUrl": "https://www.postgresql.org",
      "isHardware": false,
      "latestVersion": "17.2",
      "latestReleasedAt": "2026-01-09T00:00:00.000Z"
    }
  ],
  "pagination": { "nextCursor": "postgresql", "limit": 2 }
}
GET/api/v1/products/{slug}

Produktdetail

Einzelnes Produkt inkl. aktuellster Version, Kanal und EOL-Kurzform. eol ist null, wenn das Produkt nicht bei endoflife.date getrackt wird. Unbekannter Slug → 404.

Beispiel

curl "https://patchletter.com/api/v1/products/nginx"

Beispiel-Response

{
  "slug": "nginx",
  "name": "nginx",
  "vendor": "F5 / nginx",
  "category": "server-datenbanken",
  "subcategory": "Reverse Proxy",
  "description": "Webserver und Reverse Proxy — überall.",
  "websiteUrl": "https://nginx.org",
  "isHardware": false,
  "latestVersion": "1.27.4",
  "latestChannel": "STABLE",
  "latestReleasedAt": "2026-02-05T00:00:00.000Z",
  "eol": null
}
GET/api/v1/products/{slug}/releases

Release-Historie

Chronologische Release-Liste eines Produkts, neueste Version zuerst. Filter: channel (STABLE, LTS, BETA, SECURITY, FIRMWARE), cursor, limit.

Beispiel

curl "https://patchletter.com/api/v1/products/nginx/releases?limit=2"

Beispiel-Response

{
  "data": [
    {
      "version": "1.27.4",
      "versionNorm": "1.27.4",
      "channel": "STABLE",
      "releasedAt": "2026-02-05T00:00:00.000Z",
      "detectedAt": "2026-02-06T03:00:12.000Z",
      "notesUrl": "https://nginx.org/en/CHANGES",
      "summary": "Security fix for a request-smuggling edge case in HTTP/2 handling.",
      "isSecurity": true
    },
    {
      "version": "1.27.3",
      "versionNorm": "1.27.3",
      "channel": "STABLE",
      "releasedAt": "2025-12-16T00:00:00.000Z",
      "detectedAt": "2025-12-17T03:00:05.000Z",
      "notesUrl": "https://nginx.org/en/CHANGES",
      "summary": null,
      "isSecurity": false
    }
  ],
  "pagination": { "nextCursor": "eyJ2ZXJzaW9uTm9ybSI6IjEuMjcuMyIsImlkIjoiY2xxeHh4In0", "limit": 2 }
}
GET/api/v1/products/{slug}/versions

Bekannte Versionen

Dedupliziertes Dropdown-Vokabular aller bekannten Versionsstrings eines Produkts ("Deine Version"), priorisiert STABLE/LTS.

Beispiel

curl "https://patchletter.com/api/v1/products/nginx/versions"

Beispiel-Response

{
  "versions": ["1.27.4", "1.27.3", "1.26.3", "1.26.2", "1.24.0"]
}
GET/api/v1/products/{slug}/cves

CVE-Treffer eines Produkts

CVE-/KEV-Feed eines einzelnen Produkts, neueste Erkennung zuerst. Filter: severity (CRITICAL, HIGH, MEDIUM, LOW — case-insensitiv), cursor, limit. severity/cvss stammen aus der NVD und sind null, solange dort noch keine Bewertung vorliegt.

Beispiel

curl "https://patchletter.com/api/v1/products/nginx/cves?severity=high"

Beispiel-Response

{
  "data": [
    {
      "cveId": "CVE-2026-31337",
      "title": "Example: heap buffer overflow when parsing a malformed HTTP/2 header block",
      "severity": "HIGH",
      "cvss": 8.6,
      "knownExploited": true,
      "ransomware": false,
      "dueDate": "2026-08-01T00:00:00.000Z",
      "publishedAt": "2026-07-10T00:00:00.000Z",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-31337"
    }
  ],
  "pagination": { "nextCursor": null, "limit": 50 }
}
GET/api/v1/products/{slug}/eol

EOL-Zyklen eines Produkts

Roh-Zyklen aus dem endoflife.date-Cache. cycles ist ein leeres Array (kein Fehler), wenn das Produkt dort nicht gelistet ist.

Beispiel

curl "https://patchletter.com/api/v1/products/postgresql/eol"

Beispiel-Response

{
  "slug": "postgresql",
  "name": "PostgreSQL",
  "cycles": [
    {
      "cycle": "17",
      "releaseDate": "2024-09-26",
      "eol": "2029-11-08",
      "latest": "17.2",
      "lts": false,
      "support": "2027-11-11"
    },
    {
      "cycle": "16",
      "releaseDate": "2023-09-14",
      "eol": "2028-11-09",
      "latest": "16.6",
      "lts": false,
      "support": "2026-11-12"
    }
  ]
}
GET/api/v1/releases/recent

Jüngste Releases (produktübergreifend)

Neueste Release-Erkennungen über alle aktiven Produkte, optional nur sicherheitsrelevante (securityOnly=1). Filter: cursor, limit.

Beispiel

curl "https://patchletter.com/api/v1/releases/recent?securityOnly=1&limit=2"

Beispiel-Response

{
  "data": [
    {
      "product": { "slug": "nginx", "name": "nginx" },
      "version": "1.27.4",
      "prevVersion": "1.27.3",
      "channel": "STABLE",
      "isSecurity": true,
      "date": "2026-02-05T00:00:00.000Z"
    },
    {
      "product": { "slug": "fortios", "name": "FortiOS" },
      "version": "7.6.3",
      "prevVersion": "7.6.2",
      "channel": "FIRMWARE",
      "isSecurity": true,
      "date": "2026-02-03T00:00:00.000Z"
    }
  ],
  "pagination": { "nextCursor": "eyJkZXRlY3RlZEF0IjoiMjAyNi0wMi0wM1QwMDowMDowMFoiLCJpZCI6ImNseXh4eHgifQ", "limit": 2 }
}
GET/api/v1/cves

Globaler CVE-/KEV-Feed

CVE-/KEV-Treffer über alle aktiven Produkte, inkl. Produktreferenz je Zeile. Filter: severity, cursor, limit.

Beispiel

curl "https://patchletter.com/api/v1/cves?severity=critical&limit=1"

Beispiel-Response

{
  "data": [
    {
      "cveId": "CVE-2026-31337",
      "title": "Example: heap buffer overflow when parsing a malformed HTTP/2 header block",
      "severity": "CRITICAL",
      "cvss": 9.1,
      "knownExploited": true,
      "ransomware": true,
      "dueDate": "2026-08-01T00:00:00.000Z",
      "publishedAt": "2026-07-10T00:00:00.000Z",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-31337",
      "product": { "slug": "nginx", "name": "nginx" }
    }
  ],
  "pagination": { "nextCursor": null, "limit": 1 }
}
GET/api/v1/categories

Kategorien

Vollständige, stabile Kategorienliste inkl. Anzahl aktiver Produkte. Unpaginiert — pagination.nextCursor ist immer null.

Beispiel

curl "https://patchletter.com/api/v1/categories"

Beispiel-Response

{
  "data": [
    { "slug": "browser-clients", "label": "Browser & Clients", "labelEn": "Browsers & Clients", "count": 14 },
    { "slug": "betriebssysteme", "label": "Betriebssysteme", "labelEn": "Operating Systems", "count": 22 }
  ],
  "pagination": { "nextCursor": null, "limit": 2 }
}

Maschinenlesbare Spezifikation

Die vollständige OpenAPI-3.1-Spezifikation beschreibt jeden Endpunkt, jeden Parameter und jedes Feld maschinenlesbar — ideal zum Generieren von API-Clients oder zum Import in Postman/Insomnia.

GET /api/v1/openapi.json ansehen

Webhooks — statt zu pollen

Statt die API abzufragen, kannst du dir jedes erkannte Update zuschicken lassen: an einen eigenen Endpunkt (JSON) oder direkt in einen Chat-Kanal (Slack, Mattermost, Rocket.Chat). Ziele legst du im Dashboard an. Webhooks kommen sofort bei jedem Update — unabhängig davon, wie oft du Mails bekommst.

Beispiel-Nutzlast (Format „JSON generisch“)

POST /dein-endpunkt
X-Patchletter-Event: release.detected
X-Patchletter-Signature: sha256=1f8ac10f23c5b5bc11678d7…
X-Patchletter-Timestamp: 1786181400

{
  "event": "release.detected",
  "id": "clr123",
  "product": { "name": "Proxmox VE", "slug": "proxmox-ve", "url": "https://patchletter.com/de/software/proxmox-ve" },
  "version": "9.2",
  "previous_version": "9.1",
  "channel": "STABLE",
  "security": true,
  "notes_url": "https://example.com/notes",
  "detected_at": "2026-08-08T09:30:00.000Z"
}

Signatur prüfen

Jede Zustellung trägt X-Patchletter-Signature (sha256=…) und X-Patchletter-Timestamp. Signiert wird der HMAC-SHA256 über „<Zeitstempel>.<Körper>“ mit dem Secret aus deinem Dashboard. Verwirf alles, was älter als ein paar Minuten ist — sonst ließe sich eine abgefangene Nachricht erneut einspielen.

import { createHmac, timingSafeEqual } from "node:crypto";

function istEcht(koerper, signatur, zeitstempel, secret) {
  // Alles aelter als fuenf Minuten verwerfen.
  if (Math.abs(Date.now() / 1000 - Number(zeitstempel)) > 300) return false;
  const erwartet =
    "sha256=" + createHmac("sha256", secret).update(zeitstempel + "." + koerper).digest("hex");
  const a = Buffer.from(erwartet);
  const b = Buffer.from(signatur);
  // Laengenvergleich zuerst: timingSafeEqual wirft bei ungleicher Laenge.
  return a.length === b.length && timingSafeEqual(a, b);
}

Zustellung ist „mindestens einmal“: Bleibt deine Antwort auf halbem Weg, siehst du dieselbe Nachricht womöglich erneut. Das Feld id ist je Release stabil — dedupliziere darüber.

Faire Nutzung

patchletter ist kostenlos und wird aus offenen Quellen gespeist — Hersteller-Release-Notes, dem CISA-KEV-Katalog und endoflife.date. Sei fair: cache Antworten (Cache-Control ist gesetzt), poll nicht öfter als nötig, und wenn du Daten weiterverwendest, nenn patchletter als Quelle. Für höheres Volumen: hello@patchletter.com.

Schick die erste Anfrage

Ein curl auf /api/v1/products reicht zum Anfangen. Wer öfter anfragt, legt sich im Dashboard einen kostenlosen API-Key an.