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 & Apps 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.io/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.io/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.io/api/v1/scans?limit=10&status=finished"
Antwort:
{
"data": [
{
"public_id": "01KN3X...",
"report_url": "https://turbometrics.io/scan/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.io/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.io/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.io/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.io/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...).
report_url verweist auf den Report in der Oberfläche. Der Link ist bei privaten
Scans nur für den eingeloggten Eigentümer erreichbar — zum Weitergeben an Dritte
ist share_url gedacht (siehe Share-Links).
Beispiel:
curl -H "Authorization: Bearer {token}" \
https://turbometrics.io/api/v1/scans/01KN3X...
Antwort (laufender Scan):
{
"data": {
"public_id": "01KN3X...",
"report_url": "https://turbometrics.io/scan/01KN3X...",
"status": "running",
"submitted_url": "https://example.com/",
"region": "de-fsn1",
"auth_type": null
}
}
Antwort (abgeschlossener Scan):
{
"data": {
"public_id": "01KN3X...",
"report_url": "https://turbometrics.io/scan/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.io/scan/01KN3X.../screenshot?profile=desktop",
"mobile_url": "https://turbometrics.io/scan/01KN3X.../screenshot?profile=mobile",
"filmstrip": {
"desktop": [
"https://turbometrics.io/scan/01KN3X.../strip/desktop/0?...",
"https://turbometrics.io/scan/01KN3X.../strip/desktop/1?..."
],
"mobile": [
"https://turbometrics.io/scan/01KN3X.../strip/mobile/0?..."
]
},
"filmstrip_frames": {
"desktop": [
{ "url": "https://turbometrics.io/scan/01KN3X.../strip/desktop/0?...", "ms": 0, "event": null },
{ "url": "https://turbometrics.io/scan/01KN3X.../strip/desktop/1?...", "ms": 850, "event": "lcp" }
],
"mobile": [
{ "url": "https://turbometrics.io/scan/01KN3X.../strip/mobile/0?...", "ms": 0, "event": "fcp" }
]
}
},
"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.io/api/v1/scans/01KN3X.../share/enable
Antwort:
{
"data": {
"share_enabled": true,
"share_url": "https://turbometrics.io/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.io/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.io/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.io/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.io/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.io/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.io/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.io/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.io/api/v1/rum/sites
Antwort:
{
"data": [
{
"id": 1,
"domain": "turbometrics.io",
"active": true,
"embed_snippet": "<script src=\"https://turbometrics.io/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.io/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.io/api/v1/rum/sites/1/summary?period=24h&device=all"
Antwort:
{
"data": {
"domain": "turbometrics.io",
"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.io/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.io/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.io/api/v1/rum/sites/1/alerts
Antwort:
{
"data": [
{
"id": 209,
"title": "turbometrics.io — 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.io/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.io/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.io/api/v1/scans
# Status prüfen
curl -H "Authorization: Bearer {token}" \
https://turbometrics.io/api/v1/scans/01KN3X...
# Letzte 5 Scans
curl -H "Authorization: Bearer {token}" \
"https://turbometrics.io/api/v1/scans?limit=5&status=finished"
PHP
$token = 'dein-api-token';
$base = 'https://turbometrics.io/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.
Apps anbinden (OAuth 2.1)
Die Abschnitte oben beschreiben den Zugriff auf dein eigenes Konto mit einem selbst erstellten Token. Wenn du eine Anwendung baust, die im Namen anderer turbometrics-Nutzer zugreift, gibt es dafür seit August 2026 einen zweiten Weg: OAuth 2.1. Der Nutzer klickt einmal auf „Erlauben" und muss nie einen Token kopieren.
Der ausgegebene Zugriffstoken ist ein gewöhnlicher Bearer-Token und trägt durch alle oben beschriebenen Endpunkte — nicht nur durch den MCP-Server.
| Dokument | Adresse |
|---|---|
| Authorization Server | https://turbometrics.io/.well-known/oauth-authorization-server |
| Registrierung | POST https://turbometrics.io/oauth/register |
| Autorisierung | https://turbometrics.io/oauth/authorize |
| Token | POST https://turbometrics.io/oauth/token |
Was du wissen musst:
- PKCE mit
S256ist Pflicht. Anfragen ohnecode_challengewerden abgewiesen. - Öffentliche Clients, kein Secret. Deine App registriert sich selbst über den Registrierungs-Endpunkt (RFC 7591) oder weist sich über ein Client ID Metadata Document aus.
- Rückleitungen müssen
httpssein — oderhttpauf einer Loopback-Adresse, für Anwendungen, die lokal einen Port öffnen. - Zugriffstoken gelten eine Stunde, Refresh-Token 30 Tage. Refresh-Token rotieren: bei jeder Erneuerung bekommst du ein neues und das alte verfällt.
- Der Nutzer braucht mindestens den Starter-Plan und sieht deine App danach unter Profil → API & Apps, wo er den Zugriff jederzeit widerrufen kann.
Kein OpenID Connect: es gibt keinen id_token und keinen userinfo-Endpunkt.
Für „wer ist das?" nutzt du nach der Anmeldung GET /api/v1/me.
Token-Verwaltung
API-Token erstellst und verwaltest du unter Profil → API & Apps:
- 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