Dokumentation

REST API

Token-basierter API-Zugriff für Scans, Domains, Alerts und Live-Daten (RUM).

turbometrics bietet eine REST API für den programmatischen Zugriff auf Scans, Domains und Account-Daten. Authentifizierung erfolgt über Bearer Tokens, die du unter Profil → API verwaltest.

Authentifizierung

Füge deinen API-Token bei jedem Request als Authorization-Header hinzu:

Authorization: Bearer {dein-token}

Die API antwortet immer mit JSON. Ohne gültigen Token erhältst du 401 Unauthenticated.

Basis-URL

https://turbometrics.de/api/v1

Rate Limiting

Das tägliche Anfrage-Limit hängt von deinem Plan ab:

Plan Tägliches Limit
Starter 500
Pro 5.000
Agency Unbegrenzt

Bei Überschreitung erhältst du 429 Too Many Requests:

{
  "error": "Daily API limit reached",
  "limit": 500,
  "reset_at": "2026-04-01T23:59:59+02:00"
}

Der Zähler wird täglich um Mitternacht zurückgesetzt.


Endpunkte

GET /me

Gibt Account-Informationen und aktuellen API-Nutzungsstand zurück.

Beispiel:

curl -H "Authorization: Bearer {token}" \
  https://turbometrics.de/api/v1/me

Antwort:

{
  "data": {
    "id": 42,
    "name": "Max Mustermann",
    "email": "[email protected]",
    "plan": {
      "key": "starter",
      "label": "Starter",
      "api_enabled": true,
      "api_daily_limit": 500
    },
    "api_usage": {
      "used_today": 12,
      "limit_today": 500,
      "reset_at": "2026-04-01T23:59:59+02:00"
    }
  }
}

GET /scans

Gibt eine paginierte Liste deiner Scans zurück.

Parameter:

Parameter Typ Beschreibung
limit int Ergebnisse pro Seite, max. 50 (Standard: 20)
domain string Filtert nach URL-Inhalt
status string queued, running, finished, failed
page int Seitennummer

Beispiel:

curl -H "Authorization: Bearer {token}" \
  "https://turbometrics.de/api/v1/scans?limit=10&status=finished"

Antwort:

{
  "data": [
    {
      "public_id": "01KN3X...",
      "status": "finished",
      "submitted_url": "https://example.com/",
      "region": "de-fsn1",
      "auth_type": null,
      "requested_at": "2026-03-31T00:29:00+02:00",
      "finished_at": "2026-03-31T00:29:45+02:00",
      "result": {
        "scores": {
          "overall": 87,
          "speed": 100,
          "images": 93,
          "caching": 89,
          "wordpress": 100,
          "technical": 70
        }
      }
    }
  ],
  "meta": {
    "current_page": 1,
    "per_page": 10,
    "total": 143,
    "last_page": 15
  }
}

POST /scans

Startet einen neuen Scan.

Body (JSON):

Feld Typ Pflicht Beschreibung
url string ja Die zu scannende URL
region string nein Scan-Standort (z.B. de-fsn1, de-nbg1)
public bool nein Öffentlich sichtbar (Standard: false)
force bool nein Frischen Scan erzwingen, auch wenn ein aktuelles Ergebnis vorhanden ist (Standard: false)
auth object nein Authentifizierung für geschützte Seiten (ab Pro-Plan, siehe unten)

Hinweis zum Caching: Ohne force: true wird ein vorhandenes Scan-Ergebnis der gleichen URL zurückgegeben, wenn es weniger als 24 Stunden alt ist. Die Antwort enthält dann "cached": true und HTTP 200 statt 202.

Beispiel (normaler Scan):

curl -X POST \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}' \
  https://turbometrics.de/api/v1/scans

Beispiel (frischen Scan erzwingen):

curl -X POST \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com", "force": true}' \
  https://turbometrics.de/api/v1/scans

Antwort — neuer Scan (202 Accepted):

{
  "data": {
    "id": "01KN3X...",
    "status": "queued",
    "url": "https://example.com/",
    "cached": false,
    "auth_type": null
  }
}

Antwort — Cache-Hit (200 OK):

{
  "data": {
    "id": "01KN3X...",
    "status": "finished",
    "url": "https://example.com/",
    "cached": true,
    "auth_type": null
  }
}

Der Scan wird asynchron verarbeitet. Rufe GET /scans/{id} ab, um den Status zu prüfen.

Scan mit Authentifizierung (ab Pro-Plan)

Seiten, die per HTTP Basic Auth oder eigenem HTTP-Header geschützt sind, können mit dem optionalen auth-Objekt gescannt werden. Verfügbar ab dem Pro-Plan.

Felder im auth-Objekt:

Feld Typ Beschreibung
type string "basic" oder "header"
username string Benutzername (nur bei type: "basic")
password string Passwort (nur bei type: "basic")
header_name string Name des HTTP-Headers (nur bei type: "header")
header_value string Wert des HTTP-Headers (nur bei type: "header")

Beispiel — HTTP Basic Auth:

curl -X POST \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://staging.example.com",
    "auth": {
      "type": "basic",
      "username": "admin",
      "password": "geheim"
    }
  }' \
  https://turbometrics.de/api/v1/scans

Beispiel — HTTP-Header:

curl -X POST \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://staging.example.com",
    "auth": {
      "type": "header",
      "header_name": "X-Preview-Key",
      "header_value": "abc123"
    }
  }' \
  https://turbometrics.de/api/v1/scans

Antwort mit Authentifizierung:

{
  "data": {
    "id": "01KN3X...",
    "status": "queued",
    "url": "https://staging.example.com/",
    "cached": false,
    "auth_type": "basic"
  }
}

Die Antwort enthält auth_type als Indikator — Zugangsdaten werden niemals zurückgegeben. Scans mit Authentifizierung werden automatisch als privat behandelt.

Ohne das scan_auth-Feature (Free / Starter) wird das auth-Objekt mit 403 Forbidden abgewiesen.


GET /scans/{id}

Gibt Details zu einem einzelnen Scan zurück.

{id} ist die public_id (z.B. 01KN3X...).

Beispiel:

curl -H "Authorization: Bearer {token}" \
  https://turbometrics.de/api/v1/scans/01KN3X...

Antwort (laufender Scan):

{
  "data": {
    "public_id": "01KN3X...",
    "status": "running",
    "submitted_url": "https://example.com/",
    "region": "de-fsn1",
    "auth_type": null
  }
}

Antwort (abgeschlossener Scan):

{
  "data": {
    "public_id": "01KN3X...",
    "status": "finished",
    "is_public": false,
    "submitted_url": "https://example.com/",
    "region": "de-fsn1",
    "auth_type": null,
    "share_enabled": false,
    "share_url": null,
    "requested_at": "2026-03-31T00:29:00+02:00",
    "finished_at": "2026-03-31T00:29:45+02:00",
    "result": {
      "final_url": "https://example.com/",
      "final_host": "example.com",
      "http_status": 200,
      "scores": {
        "overall": 87,
        "speed": 100,
        "images": 93,
        "caching": 89,
        "wordpress": 100,
        "technical": 70
      },
      "summary_short": "Die Seite lädt schnell, hat aber Optimierungsbedarf bei technischen Metriken.",
      "summary_long": "...",
      "metrics": {
        "ttfb_ms": 182,
        "desktop": {
          "fcp_ms": 412,
          "lcp_ms": 830,
          "cls": 0.02,
          "tbt_ms": 0,
          "request_count": 34,
          "total_bytes": 512000
        },
        "mobile": {
          "fcp_ms": 980,
          "lcp_ms": 2100,
          "cls": 0.04,
          "tbt_ms": 120,
          "request_count": 34,
          "total_bytes": 512000
        }
      },
      "screenshots": {
        "desktop_url": "https://turbometrics.de/scan/01KN3X.../screenshot?profile=desktop",
        "mobile_url": "https://turbometrics.de/scan/01KN3X.../screenshot?profile=mobile"
      },
      "findings": [
        {
          "category": "images",
          "code": "unoptimized_images",
          "severity": "warning",
          "title": "Bilder nicht optimiert",
          "message": "3 Bilder könnten kleiner sein.",
          "recommendation": "Nutze WebP und komprimiere Bilder vor dem Upload."
        }
      ]
    }
  }
}

POST /scans/{id}/share/enable

Aktiviert den Share-Link für einen Scan und gibt die öffentliche Share-URL zurück. Erfordert mindestens den Starter-Plan.

{id} ist die public_id des Scans (z.B. 01KN3X...).

Beispiel:

curl -X POST \
  -H "Authorization: Bearer {token}" \
  https://turbometrics.de/api/v1/scans/01KN3X.../share/enable

Antwort:

{
  "data": {
    "share_enabled": true,
    "share_url": "https://turbometrics.de/s/abc123xyz012"
  }
}

Der Token bleibt stabil — bei erneutem Aktivieren nach einem Deaktivieren wird dieselbe URL verwendet.


POST /scans/{id}/share/disable

Deaktiviert den Share-Link. Der Share-Token wird intern beibehalten, sodass ein späteres Reaktivieren dieselbe URL liefert.

Beispiel:

curl -X POST \
  -H "Authorization: Bearer {token}" \
  https://turbometrics.de/api/v1/scans/01KN3X.../share/disable

Antwort:

{
  "data": {
    "share_enabled": false
  }
}

GET /domains

Gibt eine paginierte Liste deiner überwachten Scan-Ziele zurück.

Beispiel:

curl -H "Authorization: Bearer {token}" \
  https://turbometrics.de/api/v1/domains

Antwort:

{
  "data": [
    {
      "id": 7,
      "host": "example.com",
      "url": "https://example.com/",
      "schedule": "daily",
      "is_active": true,
      "last_dispatched_at": "2026-03-31T08:00:00+02:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "per_page": 20,
    "total": 5,
    "last_page": 1
  }
}

GET /domains/{id}/history

Gibt die letzten 30 abgeschlossenen Scans für ein Scan-Ziel zurück.

{id} ist die numerische ID aus GET /domains.

Beispiel:

curl -H "Authorization: Bearer {token}" \
  https://turbometrics.de/api/v1/domains/7/history

Antwort:

{
  "data": [
    {
      "score": 87,
      "created_at": "2026-03-31T08:01:23+02:00",
      "region": "de-fsn1"
    },
    {
      "score": 84,
      "created_at": "2026-03-30T08:00:55+02:00",
      "region": "de-fsn1"
    }
  ]
}

GET /alerts

Gibt eine paginierte Liste deiner Alerts zurück.

Parameter:

Parameter Typ Beschreibung
status string open (offen, nicht ausgeblendet), resolved, unread
severity string critical, warning
limit int Ergebnisse pro Seite, max. 50 (Standard: 20)
page int Seitennummer

Beispiel:

curl -H "Authorization: Bearer {token}" \
  "https://turbometrics.de/api/v1/alerts?status=open&severity=critical"

Antwort:

{
  "data": [
    {
      "id": 123,
      "type": "score_below_threshold",
      "severity": "critical",
      "title": "Score unter Schwelle",
      "message": "Score 34 unter Kritisch-Schwelle 60.",
      "is_read": false,
      "is_dismissed": false,
      "url": "https://example.com/",
      "host": "example.com",
      "scan_id": "01KN3X...",
      "created_at": "2026-03-31T08:01:23+02:00",
      "resolved_at": null
    }
  ],
  "meta": {
    "current_page": 1,
    "per_page": 20,
    "total": 3,
    "last_page": 1
  }
}

GET /alerts/{id}

Gibt einen einzelnen Alert zurück.

Beispiel:

curl -H "Authorization: Bearer {token}" \
  https://turbometrics.de/api/v1/alerts/123

Antwort: gleiche Struktur wie ein einzelnes Element aus GET /alerts.


POST /alerts/mark-read

Markiert Alerts als gelesen. Ohne ids werden alle ungelesenen Alerts des Nutzers markiert.

Body (JSON):

Feld Typ Pflicht Beschreibung
ids array nein Array von Alert-IDs; fehlt → alle

Beispiel (bestimmte Alerts):

curl -X POST \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"ids": [123, 124]}' \
  https://turbometrics.de/api/v1/alerts/mark-read

Beispiel (alle als gelesen markieren):

curl -X POST \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{}' \
  https://turbometrics.de/api/v1/alerts/mark-read

Antwort:

{
  "data": {
    "marked_read": 5
  }
}

GET /rum/sites

Gibt eine paginierte Liste deiner Live-Daten-Websites zurück. Nur verfügbar ab Starter-Plan.

Parameter:

Parameter Typ Beschreibung
limit int Ergebnisse pro Seite, max. 50 (Standard: 20)
page int Seitennummer

Beispiel:

curl -H "Authorization: Bearer {token}" \
  https://turbometrics.de/api/v1/rum/sites

Antwort:

{
  "data": [
    {
      "id": 1,
      "domain": "turbometrics.de",
      "active": true,
      "embed_snippet": "<script src=\"https://turbometrics.de/tm.min.js\" data-site-id=\"...\" async></script>",
      "pageviews_this_month": 988,
      "monthly_limit": 1000000,
      "created_at": "2026-04-01T00:00:00+02:00"
    }
  ],
  "meta": { "current_page": 1, "per_page": 20, "total": 2, "last_page": 1 }
}

GET /rum/sites/{id}

Gibt Details einer einzelnen Live-Daten-Website zurück.

Beispiel:

curl -H "Authorization: Bearer {token}" \
  https://turbometrics.de/api/v1/rum/sites/1

GET /rum/sites/{id}/summary

Gibt p75-Werte und Core Web Vitals Status für eine Website zurück.

Parameter:

Parameter Typ Beschreibung
period string 24h, 7d, 30d (Standard: 24h)
device string all, desktop, mobile, tablet (Standard: all)

Beispiel:

curl -H "Authorization: Bearer {token}" \
  "https://turbometrics.de/api/v1/rum/sites/1/summary?period=24h&device=all"

Antwort:

{
  "data": {
    "domain": "turbometrics.de",
    "period": "24h",
    "device": "all",
    "cwv_pass": true,
    "cwv_insufficient_data": false,
    "metrics": {
      "LCP":  { "p75": 226,   "rating": "good", "samples": 127 },
      "CLS":  { "p75": 0.0,   "rating": "good", "samples": 12 },
      "INP":  { "p75": 112,   "rating": "good", "samples": 16 },
      "FCP":  { "p75": 201,   "rating": "good", "samples": 26 },
      "TTFB": { "p75": 143,   "rating": "good", "samples": 27 }
    }
  }
}

cwv_pass ist true wenn alle drei Core Web Vitals (LCP, CLS, INP) im Zielbereich liegen und jeweils mindestens 20 Messungen vorhanden sind. Bei zu wenig Daten ist cwv_pass = null und cwv_insufficient_data = true.


GET /rum/sites/{id}/history

Gibt tägliche p75/p50-Werte für eine Metrik als Zeitreihe zurück.

Parameter:

Parameter Typ Beschreibung
metric string Erforderlich: LCP, CLS, INP, FCP, TTFB
days int 7, 30, 90 (Standard: 30)
device string all, desktop, mobile, tablet (Standard: all)

Beispiel:

curl -H "Authorization: Bearer {token}" \
  "https://turbometrics.de/api/v1/rum/sites/1/history?metric=LCP&days=30"

Antwort:

{
  "data": [
    { "date": "2026-04-04", "p75": 226, "p50": 180, "samples": 127 },
    { "date": "2026-04-03", "p75": 240, "p50": 195, "samples": 98 }
  ],
  "meta": { "metric": "LCP", "days": 30, "device": "all" }
}

GET /rum/sites/{id}/pages

Gibt die langsamsten Seiten nach p75 für eine Metrik zurück.

Parameter:

Parameter Typ Beschreibung
metric string LCP, FCP, TTFB (Standard: LCP)
period string 24h, 7d (Standard: 24h)
limit int 1–100 (Standard: 25)

Beispiel:

curl -H "Authorization: Bearer {token}" \
  "https://turbometrics.de/api/v1/rum/sites/1/pages?metric=LCP&limit=10"

Antwort:

{
  "data": [
    { "path": "/", "p75": 1437, "samples": 3 },
    { "path": "/preise", "p75": 98, "samples": 12 }
  ],
  "meta": { "metric": "LCP", "period": "24h" }
}

GET /rum/sites/{id}/alerts

Gibt die konfigurierten Alerts für eine Live-Daten-Website zurück.

Beispiel:

curl -H "Authorization: Bearer {token}" \
  https://turbometrics.de/api/v1/rum/sites/1/alerts

Antwort:

{
  "data": [
    {
      "id": 209,
      "title": "turbometrics.de — Auto-Alert",
      "mode": "auto",
      "metric": null,
      "threshold": null,
      "window_minutes": 60,
      "min_samples": 20,
      "consecutive_threshold": 2,
      "status": "active",
      "emailed_at": null,
      "resolved_at": null,
      "created_at": "2026-04-05T10:00:00+02:00"
    }
  ]
}

Mögliche Werte für status: active (konfiguriert, nie ausgelöst), triggered (aktuell ausgelöst), resolved (aufgelöst).


Fehlercodes

Code Bedeutung
401 Kein oder ungültiger Token
403 Plan unterstützt keine API (Starter oder höher nötig) — oder auth-Objekt übergeben, aber kein Pro-Plan
404 Ressource nicht gefunden
422 Validierungsfehler (z.B. ungültige URL)
429 Stündliches Scan-Limit oder tägliches API-Limit überschritten
500 Interner Fehler

Beispiel 422:

{
  "message": "The url field is required.",
  "errors": {
    "url": ["The url field is required."]
  }
}

Code-Beispiele

curl

# Scan starten
curl -X POST \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com", "region": "de-fsn1"}' \
  https://turbometrics.de/api/v1/scans

# Scan mit HTTP Basic Auth (ab Pro-Plan)
curl -X POST \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://staging.example.com", "auth": {"type": "basic", "username": "admin", "password": "geheim"}}' \
  https://turbometrics.de/api/v1/scans

# Scan mit HTTP-Header (ab Pro-Plan)
curl -X POST \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://staging.example.com", "auth": {"type": "header", "header_name": "X-Preview-Key", "header_value": "abc123"}}' \
  https://turbometrics.de/api/v1/scans

# Status prüfen
curl -H "Authorization: Bearer {token}" \
  https://turbometrics.de/api/v1/scans/01KN3X...

# Letzte 5 Scans
curl -H "Authorization: Bearer {token}" \
  "https://turbometrics.de/api/v1/scans?limit=5&status=finished"

PHP

$token = 'dein-api-token';
$base  = 'https://turbometrics.de/api/v1';

// Scan starten
$ch = curl_init("$base/scans");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $token,
        'Content-Type: application/json',
        'Accept: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['url' => 'https://example.com']),
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

$scanId = $response['data']['id']; // z.B. "01KN3X..."

// Scan mit HTTP Basic Auth starten (ab Pro-Plan)
$ch = curl_init("$base/scans");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $token,
        'Content-Type: application/json',
        'Accept: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'url'  => 'https://staging.example.com',
        'auth' => [
            'type'     => 'basic',
            'username' => 'admin',
            'password' => 'geheim',
        ],
    ]),
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

// auth_type in der Antwort zeigt "basic", Zugangsdaten werden nie zurückgegeben
echo $response['data']['auth_type']; // "basic"

// Status prüfen
$ch = curl_init("$base/scans/$scanId");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $token,
        'Accept: application/json',
    ],
]);
$scan = json_decode(curl_exec($ch), true);
curl_close($ch);

echo $scan['data']['status']; // queued | running | finished | failed

Lieber ohne Code? MCP-Server nutzen

Wer Scans, Alerts und Live-Daten lieber per natürlicher Sprache abfragen möchte, kann turbometrics direkt mit Claude Desktop und anderen KI-Tools verbinden — ohne eigene API-Aufrufe zu schreiben.

MCP-Server einrichten


Token-Verwaltung

API-Token erstellst und verwaltest du unter Profil → API:

  • Gib jedem Token einen beschreibenden Namen (z.B. Monitoring-Script, CI/CD)
  • Setze ein Ablaufdatum für sicherheitskritische Umgebungen
  • Der Token-Wert wird nur einmal nach der Erstellung angezeigt
  • Kompromittierte Token sofort löschen und neu erstellen