Dokumentation

Die Seite läuft auf einer öffentlichen API mit achtzehn Sofort-Endpunkten. Jeder ist hier dokumentiert: Was er tut, seine Limits und ein Anfrage-/Antwortbeispiel. Ohne Konto; Sofort-Ergebnisse werden nicht gespeichert. Die Verwaltungs-APIs am Ende dieser Seite (Uptime-Monitoring, Statusseiten, Short Links) sind die zustandsbehaftete Ausnahme: Sie bleiben unter ihren eigenen Verwaltungsschlüsseln bestehen.

Statuscodes

  • 301 — Permanente Weiterleitung

    Permanente Weiterleitung. Suchmaschinen übertragen Ranking-Signale auf das Ziel.

  • 302 — Temporäre Weiterleitung

    Temporäre Weiterleitung. Die ursprüngliche URL bleibt kanonisch.

  • 307 — Temporäre Weiterleitung

    Temporäre Weiterleitung, die Methode und Body der Anfrage erhält.

  • 308 — Permanente Weiterleitung

    Permanente Weiterleitung, die Methode und Body der Anfrage erhält.

  • 200 — Erfolg

    Endgültiges Ziel erreicht. Hier endet die Kette.

  • 404 — Client-Fehler

    Das Ziel existiert nicht — ein kaputtes Weiterleitungsziel.

  • 500 — Server-Fehler

    Das Ziel wurde aufgelöst, aber der Server antwortete nicht korrekt.

Klassifizierte Ergebnisse, keine Fehler

Auf den vier Sofort-Endpunkten sind blockierte Ziele, unauf lösbare Domains und ungültige URLs keine Fehler: jede wohlgeformte Anfrage liefert HTTP 200 mit einem Status, der das Ergebnis klassifiziert. Nur fehlerhafte Anfragen, zu große Bodies und Rate-Limiting erzeugen Fehlerantworten.

Gemeinsame Limits

Protokolle
http, https
Methode
GET
Rate-Limits
30 Anfragen/Minute und 500/Tag pro IP — für alle Endpunkte
Anfragekörper
bis 10 KiB, strenges JSON

Serviceverzeichnis & Community-Meldungen (Phase 14)

Ein kuratiertes, öffentliches Verzeichnis populärer Online-Dienste mit anonymen Community-Meldungen. Lesezugriffe sind öffentlich und gecacht; der Meldungs-POST ist die stateful Ausnahme — er persistiert und trägt Rate-Limits, Deduplizierung und Moderation. Community-Signal und automatische Prüfung sind immer getrennte Indikatoren; nichts hier behauptet einen bestätigten Ausfall.

GET /api/v1/catalog/services?sort=reports_24h&page=1&page_size=20
→ 200
{ "items": [ { "slug": "chatgpt", "name": "ChatGPT",
               "category": { "slug": "ai-assistants", "name": "AI Assistants" },
               "community": { "signal": "reports_increasing", "reports_15m": 3,
                              "reports_1h": 11, "reports_24h": 42,
                              "last_report_at": "2026-10-20T09:58:12Z" },
               "automated_check": { "state": "operational",
                                    "checked_at": "2026-10-20T09:55:00Z" } } ],
  "page": 1, "page_size": 20, "total": 1 }

POST /api/v1/catalog/services/chatgpt/reports
{ "problem_type": "site_unreachable", "comment": "Login loop on mobile" }
→ 201
{ "service_slug": "chatgpt", "problem_type": "site_unreachable",
  "comment": "Login loop on mobile", "created_at": "2026-10-20T10:01:33Z" }

Reads are public and cached (ETag + max-age=30); unknown/draft/hidden
slugs all answer 404 (no existence oracle); merged slugs 301 to the
target. Reports are anonymous: no account, no network fetch on
submission, rate limited per IP, comments plain text (≤500 chars).
Community signal and the automated check are always separate blocks —
no value on this API means "confirmed down".
Paginierung
page ≥1, page_size Standard 20, maximal 100; deterministische Reihenfolge (Slug-Tiebreak)
Meldungslimits
Dedup 1 pro Service je 10 Min. pro IP, danach 10/Std. und 30/Tag pro IP; 429 + Retry-After; fail-closed
Moderation & Datenschutz
Auto-Publish- oder Hold-all-Politik; Kill-Schalter; gespeichert wird nur ein täglich rotierender pseudonymer Hash — niemals rohe IP oder User-Agent

Redirect-Checker — POST /api/v1/check

Folgt der kompletten Weiterleitungskette und speichert das Ergebnis.

POST /api/v1/check
Content-Type: application/json

{ "url": "https://bit.ly/example" }

{
  "id": "9pr2kxq4",
  "status": "completed",
  "input_url": "https://bit.ly/example",
  "final_url": "https://example.com/product",
  "final_domain": "example.com",
  "final_status": 200,
  "redirect_count": 3,
  "duration_ms": 482,
  "redirects": [
    { "sequence": 0, "requested_url": "https://bit.ly/example",
      "status_code": 301, "next_url": "https://tracker.example/click",
      "duration_ms": 83 },
    { "sequence": 3, "requested_url": "https://example.com/product",
      "status_code": 200, "duration_ms": 184 }
  ],
  "errors": null
}

GET /api/v1/check/{id} — ruft ein gespeichertes Ergebnis über seine öffentliche ID ab.
Maximale Weiterleitungen
20 Hops
Anfrage-Timeout
15 Sekunden

GET /api/v1/check/{id} — ruft ein gespeichertes Ergebnis über seine öffentliche ID ab.

Uptime Checker — POST /api/v1/uptime-check

Prüft, ob eine Website antwortet. Das Ergebnis wird klassifiziert: UP bei erfolgreicher Antwort, HTTP_ERROR bei 4xx/5xx, dazu TIMEOUT, DNS_ERROR, TLS_ERROR, CONNECTION_ERROR und BLOCKED_TARGET.

POST /api/v1/uptime-check
Content-Type: application/json

{ "url": "https://example.com" }

{
  "url": "https://example.com",
  "status": "UP",
  "reachable": true,
  "httpStatus": 200,
  "httpStatusText": "OK",
  "responseTimeMs": 184,
  "finalUrl": "https://example.com/",
  "redirectCount": 1,
  "tls": { "enabled": true, "valid": true }
}
Maximale Weiterleitungen
10 Hops
Anfrage-Timeout
10 Sekunden

HTTP Status Checker — POST /api/v1/http-status-check

Liefert den finalen Statuscode einer URL, die Antwortheader der letzten Antwort, eine kompakte Weiterleitungskette und den TLS-Status.

POST /api/v1/http-status-check
Content-Type: application/json

{ "url": "https://example.com" }

{
  "url": "https://example.com",
  "status": "UP",
  "reachable": true,
  "httpStatus": 200,
  "httpStatusText": "OK",
  "finalUrl": "https://example.com/",
  "redirectCount": 1,
  "headers": {
    "Content-Type": ["text/html; charset=utf-8"],
    "Server": ["nginx"]
  },
  "headers_analysis": {
    "security_missing": ["Strict-Transport-Security", "Content-Security-Policy"],
    "caching": { "Cache-Control": "max-age=604800" }
  },
  "tls": { "enabled": true, "valid": true }
}
Maximale Weiterleitungen
10 Hops
Anfrage-Timeout
10 Sekunden

Response Time Checker — POST /api/v1/response-time-check

Misst 1–5 Samples und klassifiziert ein Geschwindigkeitsurteil aus dem medianen Time-to-First-Byte. Liefert die Dauer jedes Samples, Min/Median/Max/Mittel und das Timing der letzten Route.

POST /api/v1/response-time-check
Content-Type: application/json

{ "url": "https://example.com", "samples": 3 }

{
  "url": "https://example.com",
  "samples": 3,
  "status": "UP",
  "verdict": "FAST",
  "completed": 3,
  "timesMs": [184, 201, 176],
  "stats": { "minMs": 176, "medianMs": 184, "maxMs": 201, "meanMs": 187 },
  "breakdown": { "dnsMs": 12, "connectMs": 23, "tlsMs": 45, "ttfbMs": 184, "totalMs": 190 },
  "httpStatus": 200,
  "httpStatusText": "OK",
  "finalUrl": "https://example.com/",
  "redirectCount": 1,
  "tls": { "enabled": true, "valid": true }
}
Samples
1–5 (Standard 3)
Timeout pro Sample
10 Sekunden
Zeitlimit pro Lauf
30 Sekunden

SSL Checker — POST /api/v1/ssl-check

Prüft das TLS-Zertifikat eines Hosts: Gültigkeit, Aussteller, SANs, ausgehandeltes Protokoll und Chiffre sowie die Kette. Nur eine TLS-Sonde — die Seite wird nie geladen; ein fehlerhaftes Zertifikat wird mit einem konkreten Grund gemeldet.

POST /api/v1/ssl-check
Content-Type: application/json

{ "url": "https://example.com" }

{
  "url": "https://example.com",
  "host": "example.com",
  "status": "UP",
  "reachable": true,
  "handshakeMs": 45,
  "tls": {
    "version": "TLS 1.3",
    "cipher": "TLS_AES_256_GCM_SHA384",
    "verified": true,
    "status": "valid",
    "daysRemaining": 89,
    "notBefore": "2026-08-01T00:00:00Z",
    "notAfter": "2026-10-30T00:00:00Z",
    "subject": "CN=example.com",
    "issuer": "CN=R3,O=Let's Encrypt,C=US",
    "sans": ["example.com", "www.example.com"],
    "chain": ["CN=example.com", "CN=R3,O=Let's Encrypt,C=US"]
  }
}
Port
aus der URL (Standard 443)
Sonden-Timeout
10 Sekunden

DNS-Checker — POST /api/v1/dns-check

Schlägt A-, AAAA-, CNAME-, MX-, TXT- und NS-Records eines Hosts nach. Nur Nachschlagen und Berichten: keine Verbindungen, jede aufgelöste Adresse wird als öffentlich/nicht-öffentlich markiert.

POST /api/v1/dns-check
Content-Type: application/json

{ "url": "example.com" }

{
  "url": "example.com",
  "host": "example.com",
  "status": "UP",
  "durationMs": 38,
  "records": {
    "a": ["93.184.216.34"],
    "aaaa": ["2606:2800:220:1:248:1893:25c8:1946"],
    "cname": [],
    "mx": [{ "host": "mail.example.com", "pref": 10 }],
    "txt": ["v=spf1 include:_spf.example.com ~all"],
    "ns": ["ns1.example.com", "ns2.example.com"]
  },
  "addressLabels": [
    { "address": "93.184.216.34", "classification": "public", "reason": "public" }
  ]
}
Record-Familien
A, AAAA, CNAME, MX, TXT, NS
Lookup-Timeout
10 Sekunden gesamt, 3 Sekunden pro Familie

Domain-Ablaufprüfung — POST /api/v1/domain-expiry-check

Beantwortet über den festen rdap.org-RDAP-Fluss, wann eine Domain abläuft: Urteil, verbleibende Tage, Registrierungs-/Ablaufdaten und Registry-Status. Das erste Tool des Repositorys mit festen Drittanbieter-Abfragen: nur HTTPS auf jedem Sprung, kein Proxy, begrenzte Weiterleitungen und Größe; die abgefragte Domain wird nie kontaktiert. 404 wird zum Urteil not_found (nicht registriert / Registry ohne RDAP / nichts veröffentlicht), 429 und 5xx zu ehrlichem UNKNOWN_ERROR.

POST /api/v1/domain-expiry-check
Content-Type: application/json

{ "url": "example.com" }

{
  "url": "example.com",
  "host": "example.com",
  "status": "UP",
  "verdict": "ok",
  "daysRemaining": 214,
  "registration": "2019-01-15T05:00:00Z",
  "expiration": "2027-04-15T04:00:00Z",
  "lastChanged": "2026-08-01T11:20:00Z",
  "registryStatuses": ["ok"],
  "source": "rdap",
  "durationMs": 420
}
Urteile
ok, expiring (≤30 Tage), expired, not_found, unknown
Abfrage-Timeout
10 Sekunden insgesamt (DOMAIN_EXPIRY_TIMEOUT)
Ausgehende Verbindung
nur rdap.org; HTTPS auf jedem Sprung; Proxy deaktiviert; Weiterleitungslimit 10; 1-MiB-Größenlimit; die Domain wird nie kontaktiert

WHOIS-Abfrage — POST /api/v1/whois-check

Beantwortet, was die Registry über eine Domain weiß: Registrar, Nameserver, Daten und Statusflags. Zuerst RDAP über rdap.org, sonst klassisches WHOIS (rohes TCP 43) — das erste Tool des Repositorys mit rohem TCP: Jeder Verweis muss ein Ziel der Form host[:43] sein, wird durch die gemeinsame SSRF-Pipeline geprüft und an die gepinnte öffentliche Adresse verwählt; Referral-Limit 2, 64-KiB-Antwortlimit; die abgefragte Domain wird nie kontaktiert. 404 von RDAP löst die Rückfallebene aus; eine eindeutige „Domain existiert nicht“-Antwort erscheint als notFound.

POST /api/v1/whois-check
Content-Type: application/json

{ "url": "mail.ru" }

{
  "url": "mail.ru",
  "host": "mail.ru",
  "status": "UP",
  "source": "whois",
  "registrar": "VK-TECH",
  "nameservers": ["ns1.mail.ru", "ns2.mail.ru"],
  "registration": "1997-10-01T00:00:00Z",
  "expiration": "2026-10-01T00:00:00Z",
  "statuses": ["REGISTERED, DELEGATED, VERIFIED"],
  "durationMs": 640
}
Quellen
RDAP über rdap.org; klassisches WHOIS (TCP 43) über die whois.iana.org-Referral-Kette
Abfrage-Timeout
15 Sekunden insgesamt (WHOIS_TIMEOUT)
Ausgehende Verbindung
Referrals nur host[:43]; SSRF-geprüft und gepinnt vor dem Verbinden; Limit 2 Referrals; 64-KiB-Limit; die Domain wird nie kontaktiert

Domain-Verfügbarkeit — POST /api/v1/domain-availability

Beantwortet pro TLD, ob ein Name registrierbar ist — mit einer ehrlichen Zustandsmaschine: AVAILABLE nur, wenn die RDAP-Abfrage 404 liefert und die eingebettete TLD-Metadaten den RDAP-Betrieb der Registry bestätigen; ein WHOIS-only-Nichtfund bleibt UNKNOWN (wahrscheinlich verfügbar); RESTRICTED folgt den Metadaten. Volle IDN-Unterstützung (Unicode rein, Punycode kanonisch, displayDomain raus) und optionale Multi-TLD-Abfrage (1–10 pro Request). Premium bleibt in MVP stets unknown — Preise sind ein eigenes künftiges Subsystem.

POST /api/v1/domain-availability
Content-Type: application/json

{ "domain": "пример.рф", "tlds": ["com", "io"] }

{
  "url": "пример.рф",
  "displayDomain": "пример.рф",
  "host": "xn--e1afmkfd.xn--p1ai",
  "status": "UP",
  "results": [
    {
      "tld": "com",
      "availability": "AVAILABLE",
      "reason": "rdap_not_found",
      "confidence": "high",
      "source": "rdap",
      "premium": "unknown",
      "checkedAt": "2026-09-03T12:00:02Z"
    },
    {
      "tld": "io",
      "availability": "UNKNOWN",
      "reason": "tld_rdap_unknown",
      "confidence": "low",
      "source": "tld-metadata",
      "premium": "unknown",
      "checkedAt": "2026-09-03T12:00:02Z"
    }
  ],
  "tldMetaVersion": "2026-09-02",
  "durationMs": 1240
}
TLDs pro Anfrage
1–10 eindeutig (Unicode oder Punycode); höchstens 4 parallele Lookups innerhalb eines 15-Sekunden-Budgets (DOMAIN_AVAILABILITY_TIMEOUT)
Urteile
AVAILABLE | REGISTERED | RESTRICTED | INVALID | UNKNOWN | ERROR — UNKNOWN wird nie zu AVAILABLE verschönt; PREMIUM ist in MVP unerreichbar
Caching
di:avail 60s, di:reg 6h, fail-open; negative Ergebnisse werden nie gecacht

Domain-Alter — POST /api/v1/domain-age

Meldet, wie alt eine Domain ist: das genaue Erstellungsdatum aus der Registry und eine deterministische Jahre/Monate/Tage-Aufschlüsselung. Dünne Projektion über die WHOIS-Daten — ein Provider-Fetch dient Verfügbarkeit, Alter und Registrar innerhalb des Cache-Fensters.

POST /api/v1/domain-age
Content-Type: application/json

{ "domain": "example.com" }

{
  "url": "example.com",
  "host": "example.com",
  "status": "UP",
  "age": {
    "known": true,
    "createdAt": "2019-01-15T05:00:00Z",
    "ageInDays": 2809,
    "years": 7,
    "months": 7,
    "days": 20
  },
  "source": "rdap",
  "durationMs": 390
}
Alter-Mathematik
nur UTC-Kalenderdaten; volle Jahre/Monate über geclampten Monatsanker; Gesamttage abgerundet
Unbekanntes Alter
age.known=false + begrenzter Grund (no_data, inconsistent_data) — nie eine Schätzung
Caching
di:reg 6h, geteilt mit Verfügbarkeit/Registrar (fail-open)

Registrar prüfen — POST /api/v1/domain-registrar

Meldet, bei welchem Registrar eine Domain registriert ist, normalisiert gegen eine kuratierte Alias-Tabelle (GoDaddy, Namecheap, Cloudflare und mehr) — unbekannte Namen werden exakt wie veröffentlicht gezeigt. Registry-Organisation und RDAP/WHOIS-Herkunft inklusive; teilt den Registrierungs-Cache mit Alter/Verfügbarkeit.

POST /api/v1/domain-registrar
Content-Type: application/json

{ "domain": "example.com" }

{
  "url": "example.com",
  "host": "example.com",
  "status": "UP",
  "registrar": "GoDaddy.com, LLC",
  "registrarCanonical": "GoDaddy",
  "registrarIanaId": 625,
  "registry": "Verisign, Inc.",
  "source": "rdap",
  "checkedAt": "2026-09-04T12:00:00Z",
  "durationMs": 410
}
Registrar
Anzeigename + kanonisches Alias-Badge bei Treffer; IANA-ID zeigt „—“ (Registry-Daten tragen sie noch nicht)
Nicht veröffentlicht
Privacy-Proxy- oder geschwärzte Registrierungen antworten UP mit Grund no_data — nie eine leere Hülle

Domain-Generator — POST /api/v1/domain-generate

Erzeugt Kandidaten-Domains aus 1–3 Keywords: direkte Formen, Präfixe, Suffixe, Komposita und Kurzformen — dedupliziert, geordnet und begrenzt. Rein und sofort: keine Registry-Aufrufe während der Generierung; Verfügbarkeitsprüfungen sind separate explizite Aktionen.

POST /api/v1/domain-generate
Content-Type: application/json

{ "keywords": ["coffee", "map"], "tlds": ["com", "io"], "limit": 24 }

{
  "status": "UP",
  "candidates": [
    { "domain": "coffee.com", "strategy": "direct" },
    { "domain": "coffee.io", "strategy": "direct" },
    { "domain": "getcoffee.com", "strategy": "prefix" },
    { "domain": "coffeemap.com", "strategy": "compound" }
  ],
  "total": 24
}
Kandidaten
hartes Limit 50, standardmäßig 24; ≤10 TLDs, gefiltert durch den TLD-Metadaten-Snapshot
Kein Provider-Traffic
die Generierung ruft null Registry auf — Einzelprüfungen treffen den Verfügbarkeits-Endpunkt mit dessen Limits

Domain-Überblick — POST /api/v1/domain-overview

Ein komponiertes Profil: Verfügbarkeit auf der eigenen TLD, Erstellungsdatum mit deterministischer Altersaufschlüsselung, Registrar (normalisiert, mit IANA-Nummer), Ablaufprojektion und die Konfigurationsbefunde der Registry. Abschnitte sind unabhängig — ein fehlgeschlagener Lookup leert nie die anderen.

POST /api/v1/domain-overview
Content-Type: application/json

{ "domain": "example.com" }

{
  "url": "example.com",
  "host": "example.com",
  "status": "UP",
  "availability": {
    "tld": "com", "availability": "REGISTERED", "reason": "registered",
    "confidence": "high", "source": "rdap", "premium": "unknown",
    "checkedAt": "2026-09-05T12:00:00Z"
  },
  "registration": {
    "known": true, "createdAt": "2019-01-15T05:00:00Z",
    "ageYears": 7, "ageMonths": 7, "ageDays": 21,
    "registrar": "GoDaddy.com, LLC", "registrarCanonical": "GoDaddy",
    "registrarIanaId": 625, "registry": "Verisign, Inc.", "source": "rdap",
    "checkedAt": "2026-09-05T12:00:01Z"
  },
  "expiry": {
    "host": "example.com", "source": "rdap", "verdict": "ok",
    "daysRemaining": 222, "expiration": "2027-04-15T04:00:00Z",
    "checkedAt": "2026-09-05T12:00:02Z"
  },
  "holds": [],
  "dnssec": [{ "id": "dnssec-absent", "state": "info", "severity": "info", "detail": "unsigned" }],
  "tldMetaVersion": "2026-09-02",
  "durationMs": 1620
}
Abschnitte
Verfügbarkeit (metadaten-gegate) + Registrierung (di:reg, 6h geteilt) + Ablauf (rdap.org) + Holds/DNSSEC-Befunde
Befunde sind Fakten
Holds/DNSSEC sind Registry-Konfigurationssignale — nie Sicherheitsurteile; DNS/SSL bleiben bei ihren eigenständigen Tools

Security Checker — POST /api/v1/security-check

Passive, beratende Konfigurationsprüfung einer abgerufenen Antwort: Sicherheits-Header (HSTS-Tiefe, CSP-Highlights, COOP/COEP/CORP, X-XSS-Protection), Cookie-Flags, TLS-Fakten, Ketten-Downgrades und Offenlegung. Kein Sondieren, keine Schwachstellenbehauptungen, keine Noten; Cookie-Werte verlassen das Backend nie. Der HTTP-Status blockiert die Prüfung nicht (erreichbare 404/500 werden geprüft).

POST /api/v1/security-check
Content-Type: application/json

{ "url": "https://example.com" }

{
  "url": "https://example.com",
  "finalUrl": "https://example.com/",
  "status": "UP",
  "durationMs": 610,
  "summary": { "total": 14, "passed": 9, "warn": 3, "failed": 2 },
  "findings": [
    { "id": "hsts-present", "state": "fail", "severity": "high" },
    { "id": "tls-cert", "state": "pass", "severity": "info", "detail": "valid" }
  ],
  "cookies": [
    { "name": "session", "secure": false, "httpOnly": true, "sameSite": "Lax" }
  ],
  "tls": { "enabled": true, "version": "TLS 1.3", "certStatus": "valid", "daysRemaining": 89 }
}
Umfang
~23 Check-IDs über Header/Cookies/TLS/Kette/Offenlegung; nur passiver Abruf
Cookies
Nur Namen und Flags (Secure/HttpOnly/SameSite) — Werte verlassen das Backend nie
Prüfungs-Timeout
10 Sekunden insgesamt (SECURITY_CHECK_TIMEOUT)

URL Analyzer — POST /api/v1/url-analyze

Eine rein syntaktische URL-Analyse: kanonische Identität mit Schwärzung (Schema, Host, IDN-Formen, naive Registrierungsdomain, Port, Pfad, Query, Fragment), geordnete Parameter mit Duplikaten und versionierter Tracking-Klassifizierung, Tracking-Zähler, informative Signale und Normalisierungsnotizen. Keine Anfragen, kein DNS, keine Speicherung — die Analyse ist lokal und erfolgt in Millisekunden.

POST /api/v1/url-analyze
Content-Type: application/json

{ "url": "https://xn--e1afmkfd.xn--p1ai/search?q=thing&utm_source=news&id=7&id=8" }

{
  "status": "UP",
  "identity": {
    "hasCredentials": false,
    "scheme": "https",
    "host": "xn--e1afmkfd.xn--p1ai",
    "displayHost": "пример.рф",
    "registrableDomain": "пример.рф",
    "isIdn": true,
    "path": "/search",
    "query": "q=thing&utm_source=news&id=7&id=8",
    "normalized": "https://xn--e1afmkfd.xn--p1ai/search?q=thing&utm_source=news&id=7&id=8"
  },
  "parameters": [
    { "name": "q", "value": "thing", "classification": { "category": "unknown", "confidence": "none" } },
    { "name": "utm_source", "value": "news", "classification": { "category": "utm", "label": "utm_source", "confidence": "exact" } },
    { "name": "id", "value": "7", "occurrence": 1 },
    { "name": "id", "value": "8", "occurrence": 2 }
  ],
  "tracking": { "utm": 1, "analytics": 0, "adsClickId": 0, "sessionSensitive": 0, "unknown": 3 },
  "signals": ["idn_host"],
  "normalization": { "schemeAssumed": false, "punycodeApplied": true, "defaultPortOmitted": false, "hostLowercased": false },
  "registryVersion": "2026-09-1"
}
Umfang
Komponenten + geordnete Parameter + Registry-Klassifizierung + informative Signale; null Netzwerk
Schwärzung
Passwörter werden nie zurückgegeben; Werte sensibler Parameter sind überall maskiert (***), Namen bleiben sichtbar

URL Expander — POST /api/v1/url-expand

Sofortige, persistenzfreie Auflösung einer Redirect-Kette über die gemeinsame Engine: jeder Hop durchläuft dieselbe zentrale SSRF-Prüfung, Schleifen und das 10-Redirect-Limit werden mit unterschiedlichen Reasons unterschieden, und die finale URL erhält eine vollständige Tracking-Analyse. Zurückgegebene URLs sind geschwärzt — Passwörter verlassen das Backend nie. Ohne Cache: Ketten sind zeitempfindlich, Aktualität ist die richtige Antwort.

POST /api/v1/url-expand
Content-Type: application/json

{ "url": "https://bit.ly/3xyz" }

{
  "url": "https://bit.ly/3xyz",
  "status": "UP",
  "finalUrl": "https://example.com/landing?utm_source=n",
  "hopCount": 2,
  "chain": [
    { "url": "https://bit.ly/3xyz", "status": 301, "location": "https://bit.ly/abc" },
    { "url": "https://bit.ly/abc", "status": 302, "location": "https://example.com/landing?utm_source=n" }
  ],
  "analysis": { "status": "UP", "tracking": { "utm": 1, "analytics": 0, "adsClickId": 0, "sessionSensitive": 0, "unknown": 0 } },
  "source": "engine",
  "durationMs": 820
}
Umfang
Geschwärzte Hop-Kette + klassifizierter Status (Schleife vs. Limit) + Analyse der finalen URL; kein DNS/TLS/Timing pro Hop (Sache des Redirect Checkers)
Auflösungsbudget
10 Sekunden insgesamt (URL_EXPAND_TIMEOUT); Hop-Limit 10

UTM Builder — POST /api/v1/utm-build

Deterministische, zustandslose Konstruktion von Kampagnen-URLs: nicht zugehörige Parameter bleiben in ihrer Reihenfolge, kanonische UTMs werden pro Feld überschrieben oder behalten, Duplikate kollabieren zum letzten Vorkommen, das Fragment bleibt erhalten, Ziele mit Zugangsdaten werden in-band abgelehnt. Gleiche Eingabe ergibt immer byteidentische Ausgabe.

POST /api/v1/utm-build
Content-Type: application/json

{ "url": "https://example.com/landing?foo=1&utm_source=old#pricing", "utmSource": "newsletter", "utmMedium": "email", "utmCampaign": "spring_sale", "utmContent": "header_cta" }

{
  "status": "UP",
  "generatedUrl": "https://example.com/landing?foo=1&utm_source=newsletter&utm_medium=email&utm_campaign=spring_sale&utm_content=header_cta#pricing",
  "warnings": ["existing_utm_overwritten:utm_source", "empty_field_skipped:utm_term"],
  "parameters": { "utm_source": "newsletter", "utm_medium": "email", "utm_campaign": "spring_sale", "utm_content": "header_cta" }
}
Umfang
UTM-Anhängen in fester Reihenfolge + Preserve/Overwrite/Collapse-Politik + Warnungen; rein, ohne Netzwerk
Determinismus
Byteidentische Ausgabe bei identischer Eingabe; Felder ≤256 Zeichen; unbekannte Anfragefelder werden abgelehnt

Website Health — POST /api/v1/website-health

Die Verbunddiagnose: Ein Request normalisiert das Ziel und startet begrenzte parallele Lanes über den vorhandenen Engines — ein einziger HTTP-Check speist fünf Sektionen (Erreichbarkeit, Status, Antwortzeit, Header, Sicherheitskonfiguration); DNS, die TLS-Zertifikatsprobe und das Domänenprofil laufen als eigene Lanes. Das Ergebnis ist ein aggregierter Gesamtzustand mit Details je Prüfung und Deep-Links zu den Einzeltools. Befunde beschreiben nur die ausgeführten Prüfungen — niemals eine Sicherheitsgarantie.

POST /api/v1/website-health
Content-Type: application/json

{ "url": "https://example.com" }

{
  "target": {
    "canonical": "https://example.com/",
    "displayHost": "example.com",
    "scheme": "https",
    "hasCredentials": false,
    "isDomain": true,
    "isHttp": true,
    "valid": true
  },
  "overall": "WARNING",
  "summaryKey": "health.summary.warning",
  "checks": [
    { "type": "http_availability", "state": "pass",
      "summaryKey": "health.check.httpAvailability.pass",
      "value": "200", "durationMs": 612, "applicable": true,
      "detailUrl": "/uptime-checker" },
    { "type": "http_status", "state": "pass",
      "summaryKey": "health.check.httpStatus.pass",
      "value": "200 OK", "applicable": true,
      "detailUrl": "/http-status-checker" },
    { "type": "response_time", "state": "pass",
      "summaryKey": "health.check.responseTime.pass",
      "value": "612 ms", "applicable": true,
      "detailUrl": "/response-time-checker" },
    { "type": "headers", "state": "warn",
      "summaryKey": "health.check.headers.warn",
      "value": "2 missing", "reason": "findings", "applicable": true,
      "detailUrl": "/security-checker" },
    { "type": "security", "state": "warn",
      "summaryKey": "health.check.security.warn",
      "value": "14 of 21 passed", "reason": "findings", "applicable": true,
      "detailUrl": "/security-checker" },
    { "type": "tls", "state": "pass",
      "summaryKey": "health.check.tls.pass",
      "value": "TLS 1.3 · valid, 89 days", "durationMs": 140,
      "applicable": true, "detailUrl": "/ssl-checker" },
    { "type": "dns", "state": "pass",
      "summaryKey": "health.check.dns.pass",
      "value": "A, AAAA, MX, NS", "durationMs": 95,
      "applicable": true, "detailUrl": "/dns-checker" },
    { "type": "domain", "state": "pass",
      "summaryKey": "health.check.domain.pass",
      "value": "expires in 214 days", "durationMs": 730,
      "applicable": true, "detailUrl": "/domain-overview" }
  ],
  "meta": { "checksTotal": 8, "checksPassed": 6, "checksWarn": 2,
            "checksFailed": 0, "checksUnknown": 0,
            "tldMetaVersion": "2026-09-03", "durationMs": 1480 }
}
Umfang
Eine HTTP-Ausführung speist fünf Sektionen; DNS/TLS/Domänen-Lanes; aggregiert HEALTHY/WARNING/ERROR/PARTIAL/UNKNOWN
Grenzen
25 s Gesamt-Budget + Lane-Budgets, ≤3 Lanes parallel; ungültige Ziele in-band; kein Cache — Frische zuerst

Uptime Monitoring — die Verwaltungs-API /api/v1/monitors

Die zustandsbehaftete Ausnahme zu den Sofort-Tools: Erstellen Sie einen Monitor für eine URL, und der Worker prüft sie nach festem Zeitplan — mit Ausführungshistorie, Verfügbarkeitsstatistik, Incident-Episoden und Webhook-Benachrichtigungen. Das Eigentum ist ein Verwaltungsschlüssel, der bei der Erstellung genau einmal angezeigt wird; jede Lese- und Schreiboperation authentifiziert sich damit, und ein falscher Schlüssel ist von einem fehlenden Monitor nicht zu unterscheiden (einheitlicher 404).

POST /api/v1/monitors
Content-Type: application/json

{ "url": "https://example.com", "name": "Prod site", "interval": 300 }

201 Created
{
  "monitor": { "id": "b1…", "name": "Prod site",
               "normalizedTarget": "https://example.com/",
               "state": "unknown", "interval": 300 },
  "manageUrl": "/monitors/b1…?key=…",
  "key": "…shown exactly once…"
}

GET /api/v1/monitors/{id}?key=…       detail + stats window + incidents
GET /api/v1/monitors/{id}/history     cursor-paginated executions
GET /api/v1/monitors/{id}/history/daily  per-day buckets (30-day cap)
GET /api/v1/monitors/{id}/incidents   incident episodes
POST /api/v1/monitors/{id}/check      enqueue a priority manual check
PATCH /api/v1/monitors/{id}           name / interval / webhook / pause
DELETE /api/v1/monitors/{id}          cascade delete

Credentials in the target are rejected (credentials_not_allowed); the
target is SSRF-pre-validated at creation and re-validated on every run.
Umfang
Erstellen / Auflisten / Details / Pause / Löschen / manuelle Prüfung / Verlauf / Incidents; feste Intervalle 60–3600s; in-band INVALID_URL und BLOCKED_TARGET bei der Erstellung
Schlüsselverwaltung
256-Bit-Schlüssel wird einmal angezeigt (sha256 gespeichert); Zugangsdaten in Zielen werden abgelehnt; SSRF-Prüfung bei Erstellung und vor jedem Lauf

Öffentliche Statusseiten — die /api/v1/status-pages-Management-API

Fassen Sie Ihre Monitore zu einer teilbaren Statusseite zusammen: Komponenten wählen, anordnen, Anzeigenamen überschreiben und unter einer stabilen Slug veröffentlichen. Seiten gehören zum selben Verwaltungsschlüssel wie die Monitore; Entwürfe sind privat, die Veröffentlichung ist idempotent und umkehrbar, und jede Mutation löscht den öffentlichen Cache-Eintrag — Zugriffsänderungen greifen innerhalb des Requests.

POST /api/v1/status-pages
Content-Type: application/json
X-Monitor-Key: <your key>

{ "name": "Prod API" }

201 Created
{
  "page": { "publicId": "p1…", "name": "Prod API",
            "slug": "prod-api", "published": false },
  "manageUrl": "/status-pages/p1…?key=…"
}

GET  /api/v1/status-pages/{id}?key=…   editor payload (members + monitors)
PATCH /api/v1/status-pages/{id}        name/description/slug + membership
POST /api/v1/status-pages/{id}/publish      → live at /status/{slug}
POST /api/v1/status-pages/{id}/unpublish    → removed within the request
DELETE /api/v1/status-pages/{id}       cascade delete

GET /api/v1/public/status-pages/{slug}   the public DTO (no key; cached 60s)

Membership is same-key only (≤25 monitors, replace-list semantics);
publish requires ≥1 visible member; the public DTO is an explicit
projection — target URLs, keys and internal ids never cross.
Umfang
Erstellen / Auflisten / Bearbeiten / Mitgliedschafts-Ersatzliste (≤25, nur eigener Schlüssel) / Veröffentlichen / Zurückziehen / Löschen; Slugs 3-63 Zeichen mit reservierten Wörtern; max. 5 Seiten pro Schlüssel
Öffentliche Fläche
GET /api/v1/public/status-pages/{slug} + /status/{slug}; nur explizites öffentliches DTO — Ziel-URLs, Schlüssel, Benachrichtigungs-Hosts und interne IDs überschreiten die Grenze nie; Redis-Cache 60s, Fail-open

Verwandeln Sie eine lange URL in einen kurzen /go/{code}-Link, den Sie verwalten können: validiertes Ziel, kryptografisch zufälliger Code, Klickstatistiken mit Heute-/7-Tage-/30-Tage-Fenstern. Links liegen unter demselben Verwaltungsschlüssel wie Ihre Monitore und Statusseiten — die Erstellung hängt sich an einen bestehenden Schlüssel und erzeugt nie einen neuen. Ziele werden beim Erstellen und Bearbeiten validiert (Syntax, Zugangsdaten abgelehnt, SSRF-Klassifizierung); die öffentliche Weiterleitung selbst ruft nichts ab und antwortet mit 302 ohne Caching.

POST /api/v1/short-links
Content-Type: application/json
X-Monitor-Key: <your key>

{ "destinationUrl": "https://example.com/launch?utm_source=newsletter" }

201 Created
{
  "link": { "id": "sl1…", "code": "a3f9k2mz",
            "shortUrl": "/go/a3f9k2mz",
            "destination": "https://example.com/launch?utm_source=newsletter" }
}

GET    /api/v1/short-links?key=…              your links (newest first)
GET    /api/v1/short-links/{id}?key=…         full link + stats
PATCH  /api/v1/short-links/{id}?key=…         destination/title/expiry (re-validated)
POST   /api/v1/short-links/{id}/disable       public 404, stats kept (enable restores)
DELETE /api/v1/short-links/{id}?key=…         soft delete (idempotent)
GET    /api/v1/short-links/{id}/stats?key=…   total + today/7d/30d clicks

GET /go/a3f9k2mz   → 302 Found + Location (Cache-Control: no-store);
                     unknown/disabled/expired/deleted all answer 404.

Destinations are validated at create/update (http/https, credentials
rejected, SSRF classification); the redirect itself never fetches.
Umfang
Erstellen / Auflisten / Bearbeiten / Deaktivieren / Aktivieren / Soft-Löschen / Statistiken; ≤100 aktive Links pro Schlüssel, 30 Erstellungen pro Schlüssel und Stunde; das Ziel wird bei jeder Änderung neu validiert
Öffentliche Weiterleitung
GET /go/{code} → 302 + no-store; unbekannt/deaktiviert/abgelaufen/gelöscht antworten mit demselben neutralen 404; die Weiterleitung ist eine reine Suche — sie akzeptiert keinen Ziel-Parameter und löst oder ruft das Ziel nie auf; keine IPs, keine User-Agents gespeichert

Wenn ein /go/{code}-Link wie Phishing, Malware, Spam oder Scam aussieht, melden Sie ihn — kein Konto nötig, eine Antwort erhalten Sie nicht. Meldungen landen in der Prüfwarteschlange des Betreibers; nur der Betreiber kann einen Link abschalten. Auf jede wohlgeformte Meldung antwortet der Endpunkt identisch — ob der Code existiert, erfährt der Meldende nicht.

POST /api/v1/short-link-reports
Content-Type: application/json

{ "code": "a3f9k2mz", "reason": "phishing",
  "detail": "Imitates a login page" }

202 Accepted
{ "status": "received" }

Reasons: phishing | malware | spam | scam | other (detail ≤500 chars,
optional plain text). The SAME 202 comes back for unknown, disabled
and deleted codes — no existence oracle. Limits per IP: one report
per code per 10 min, 10/hour, 30/day (429 + Retry-After; Redis
failure = 503, fail-closed). Reports go to the operator queue; only
the operator can take a link down (the owner key cannot override).
Limits & Datenschutz
1 Meldung pro Code und 10 Min. pro IP, danach 10/Std. und 30/Tag (429 + Retry-After; bei Redis-Fehlern 503, fail-closed); Gründe phishing | malware | spam | scam | other; kein Konto, keine E-Mail, keine Roh-IP — nur ein täglich rotierender Fingerabdruck
Einheitliche Antwort
jede wohlgeformte Meldung erhält dasselbe 202 received — für lebende, deaktivierte, gelöschte und unbekannte Codes gleichermaßen (kein Existenz-Orakel); fehlerhafte Codes oder unbekannte Gründe werden vor jeder Suche mit 400 beantwortet

Konten & API-Schlüssel — /api/v1/auth/register und /api/v1/api-keys

Browser-Konten (E-Mail + Passwort, offene Registrierung; die E-Mail wird in dieser Version nicht bestätigt) mit serverseitigen Sitzungen in einem gehärteten Cookie. API-Schlüssel authentifizieren Server-zu-Server-Aufrufe über eine explizite Erlaubnisliste der Ressourcenfamilien. Anmeldefehler sind generisch — unbekannte E-Mail und falsches Passwort sind ununterscheidbar, auch im Timing.

POST /api/v1/auth/register
Content-Type: application/json

{ "email": "you@example.com", "password": "…", "displayName": "…" }

201 Created + Set-Cookie: wg_session (HttpOnly; Secure; SameSite=Lax)
{ "account": { "id": "acc…", "email": "you@example.com", … } }

POST /api/v1/auth/login     200 + Set-Cookie (401 generic on failure)
POST /api/v1/auth/logout    deletes the server-side session
GET  /api/v1/account        the session's own profile
PATCH /api/v1/account       update display name (displayName)
GET  /api/v1/account/summary  account-owned resource counts
POST /api/v1/account/claim  management key → re-own key-held resources

POST /api/v1/api-keys               (SESSION) create; secret shown ONCE
{ "name": "CI", "scopes": ["monitors:read"] }
GET  /api/v1/api-keys               (SESSION) list — no secrets
POST /api/v1/api-keys/{id}/revoke   (SESSION) immediate 401 on next use

Bearer access (Authorization: Bearer wg_live_…) is an EXPLICIT
allowlist only: account GET/PATCH, monitors CRUD + reads, status-pages
GET, short-links CRUD + stats; everything else refuses API keys.
Missing/unknown/revoked → generic 401; wrong scope → 403; per-key and
per-account rate limits → 429 + Retry-After.
Bearer-Liste
account GET/PATCH (account:read), Monitore (lesen/schreiben), Statusseiten GET (lesen), Kurzlinks (lesen/schreiben); alles andere weist API-Schlüssel zurück. Nicht angebundene Key-Ressourcen bleiben unsichtbar, bis sie per Claim-by-key angebunden werden.
Umgang mit dem Geheimnis
Der vollständige wg_live_-Schlüssel wird genau einmal bei der Erstellung angezeigt; gespeichert wird nur ein Einweg-Hash. Fehlende/unbekannte/widerrufene Schlüssel erhalten ein generisches 401; fehlender Scope → 403; Limits → 429 + Retry-After.

Konto-E-Mail-Identität (Bestätigung & Wiederherstellung)

E-Mail-Fundament von Phase J: Adresse bestätigen, Passwort wiederherstellen und aktuelles Passwortwissen für sensible Aktionen nachweisen.

POST /api/v1/auth/verification/request     (SESSION) 202 {accepted:true}
POST /api/v1/auth/verification/confirm     { "token": "…" } → 200 {verified:true}
POST /api/v1/auth/password-reset/request   { "email": "you@example.com" } → 202 (always the same answer)
POST /api/v1/auth/password-reset/confirm   { "token": "…", "password": "…" } → 200 {reset:true}
POST /api/v1/auth/reauthenticate           (SESSION) { "password": "…" } → 200 {confirmed:true}

Reset revokes ALL sessions in the same transaction; API keys stay
active. Tokens ride mail links as URL fragments — never query strings —
and every mismatch (wrong account, replay, expiry, unknown) answers the
same generic 404.
Tokens
einmalig, 24 Std. (Bestätigung) / 30 Min. (Reset), nur im Fragment, generisches 404 bei jeder Abweichung
Reset
beendet alle Sitzungen atomar; API-Schlüssel bleiben gültig
Erneute Authentifizierung
5 Minuten, serverseitig, an die Sitzung gebunden
Arbeitsbereiche
GET /api/v1/workspaces — persönlich + Organisationen, no-store, nur Sitzung
Organisationen
anlegen/auflisten/lesen/umbenennen/löschen + Eigentumsübergang; verifizierte Sitzungen, optimistische Versionen, Reauth für destruktive Aktionen
Einladungen
E-Mail-Einladungen mit einmaligen 7-Tage-Links, vier festen Rollen, Plätze reservierenden Limits und erforderlichen Ratenfenstern
Organisations-Ressourcen
gemeinsame Monitore/Seiten/Links unter /organizations/{orgId}; Sitzungs-RBAC, versionierte Mutationen, Legacy-Keys SQL-seitig ausgeschlossen
Ressourcentransfer
persönliche Monitore/Seiten/Links atomar in eine Organisation verschieben (Abschluss ≤100, versionengeprüft, idempotent)
Organisations-Schlüssel
dienstliche Schlüssel (wg_live_…), einmalig angezeigt, mit Scopes, überleben den Ersteller, Widerruf sofort
Organisations-Audit
Nur-anhängende Historie übernommener Änderungen (365 Tage), Owner/Admin-Lesezugriff, minimale Akteursangaben