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,
"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."
}
]
}
}
}
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
}
}
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
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