API-Referenz von Guard.ch
Alle Endpunkte, die du mit einem App-Schlüssel aufrufen kannst, mit Feldern, Beispielen und Fehlern.
Hier steht, was die API annimmt und zurückgibt. Wie du vom App-Schlüssel zum laufenden Playwright-Skript kommst, zeigt die Anleitung zur eigenen Integration. KI-Assistenten bindest du einfacher über MCP an.
Grundlagen
- Basis-URL
- https://api.guard.ch/v8
- Authentifizierung
- Ein App-Schlüssel im Authorization-Header
- Format
- JSON über HTTPS
- Zugang
- Guard Analyst oder Guard Team, auch in der Testphase
Die Pfade in dieser Referenz beziehen sich auf die Basis-URL. Schick einen Body immer als JSON mit Content-Type: application/json. Antworten können weitere Felder enthalten, die hier fehlen; ignoriere einfach, was du nicht brauchst.
App-Schlüssel erstellst du unter Apps im Dashboard. Ein Schlüssel handelt für dein Konto: Die Sitzungen, die er startet, gehören dir, zählen gegen deine Limits und stehen in deiner Sitzungsliste.
Authentifizierung
Schick den Schlüssel bei jeder Anfrage mit:
Authorization: Bearer YOUR_API_KEYSchlüssel beginnen mit brl-k-v7-. Die API liest sie nur aus diesem Header, nie aus der URL. GET /image ist der einzige Endpunkt auf dieser Seite, der ohne Schlüssel funktioniert. Ein Schlüssel läuft nach einem Jahr ohne Nutzung ab oder an dem festen Datum, das du beim Erstellen gewählt hast, je nachdem, was früher eintritt.
Antworten und Fehler
Jeder Endpunkt antwortet mit HTTP 200 und einem JSON-Body. Ob es geklappt hat, steht im Feld status. Prüf also dieses Feld und nicht den HTTP-Code:
| Status | Bedeutung |
|---|---|
ok | Die Anfrage hat geklappt. Die übrigen Felder enthalten das Ergebnis. |
denied | Die Anfrage wurde abgelehnt, zum Beispiel weil der Schlüssel fehlt oder abgelaufen ist, ein Wert ungültig ist, kein Sitzungsplatz frei ist oder es die Sitzung nicht gibt. |
upgrade | Dein Plan enthält das nicht: den API-Zugang selbst oder eine Option wie einen Standort, einen eigenen Proxy oder den Residential-Ausgang. |
error | Bei uns ist etwas schiefgelaufen, oder den Pfad gibt es nicht. Versuch es später noch einmal. |
Werte jeden anderen Status als ok als Fehler. message nennt den Grund in einem Satz, den du einer Person zeigen kannst. Die Sprache folgt dem Header Accept-Language und ist ohne ihn Englisch. Werte den Text deshalb nicht aus, sondern verzweige nach status und, falls vorhanden, nach code.
{
"status": "denied",
"message": "This browser session could not be found. Check the session ID and try again."
}Fehlt der Schlüssel oder ist er ungültig, widerrufen oder abgelaufen, lautet die Antwort denied mit loggedIn: false. Ist deine E-Mail-Adresse noch nicht bestätigt, kommt denied mit verified: false. Einzige Ausnahme von HTTP 200 sind Datei-Downloads, siehe Datei herunterladen.
Endpunkte
| Endpunkt | Beschreibung |
|---|---|
POST /web/sessions | Sitzung starten |
GET /web/sessions | Eigene Sitzungen auflisten |
GET /web/sessions/:id | Eine Sitzung abrufen |
DELETE /web/sessions/:id | Sitzung beenden |
GET /web/sessions/:id/downloads/:downloadId | Vom Browser heruntergeladene Datei abholen |
GET /web/usage | Deine API-Nutzung der letzten 30 Tage |
GET /user/quota | Limits deines Plans und was davon belegt ist |
GET /image | Browser-Images und Standorte |
Sitzungen
Eine Sitzung ist ein isolierter Browser. Dein Code steuert ihn über CDP, und eine Person kann in der Live-Ansicht zuschauen oder übernehmen. Diese Endpunkte erreichen nur Sitzungen deines eigenen Kontos, nie die deiner Kolleginnen und Kollegen.
Sitzung starten
POST https://api.guard.ch/v8/web/sessionsStartet einen Browser und antwortet sofort, während der Browser im Hintergrund weiter hochfährt: status ist erst starting, dann running. Verbinde Playwright mit connectOverCDP oder Puppeteer mit browserWSEndpoint auf die connectUrl. Wird die Verbindung anfangs abgelehnt, warte, bis GET /web/sessions/:id running meldet.
Alle Felder im Body sind optional:
| Feld | Beschreibung |
|---|---|
image | ID des Browser-Images. Jedes aktive Image mit supports_programmatic in GET /image. Standard: chrome. |
name | Anzeigename für deine Sitzungsliste, 1 bis 64 Zeichen. Ohne Angabe entsteht ein Name wie brisk-otter-27. |
url | Adresse, die beim Start geöffnet wird. Erlaubt sind nur http und https. |
country | Standort als Länder- oder Stadtcode aus vpnLocations in GET /image, zum Beispiel de oder us-dal. Ohne Angabe nutzt die Sitzung die Verbindung des Rechenzentrums. Nicht mit proxy kombinierbar. |
egress | Mit residential läuft der Verkehr über einen Residential-Ausgang statt über ein Rechenzentrum. Das Land wählst du zusätzlich mit country. Der Verkehr zählt gegen das Residential-Kontingent deines Plans. Nicht mit proxy kombinierbar. |
proxy | Dein eigener Proxy im Format protocol://[user:password@]host:port, mit http, https, socks4 oder socks5. Private und interne Adressen werden abgelehnt. Nicht mit country oder egress kombinierbar. |
screen | Viewport als {"width": 1440, "height": 900}: Breite 320 bis 1920, Höhe 480 bis 1080. Standard: 1366 x 768. |
idempotencyKey | Wiederholungsschlüssel mit 1 bis 128 Zeichen. Schickst du die Anfrage innerhalb von 10 Minuten mit demselben App-Schlüssel und Wiederholungsschlüssel noch einmal, bekommst du die erste erfolgreiche Antwort zurück statt eines zweiten Browsers. Fehlgeschlagene Versuche werden nicht gespeichert; nach einer Ablehnung startet eine Wiederholung also wirklich neu. |
Zum Beispiel:
curl -X POST https://api.guard.ch/v8/web/sessions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "triage-4821",
"url": "https://example.com",
"country": "de",
"screen": { "width": 1440, "height": 900 },
"idempotencyKey": "ticket-4821"
}'{
"status": "ok",
"id": "brl-v-v7-q8m2r7k4d1",
"name": "triage-4821",
"image": "chrome",
"connectUrl": "wss://api.guard.ch/web/brl-v-v7-q8m2r7k4d1/cdp?token=3f9c2a7d",
"liveViewUrl": "https://guard.ch/en/viewer?id=brl-v-v7-q8m2r7k4d1",
"createdAt": "2026-09-26T08:14:03.512Z",
"screen": { "width": 1440, "height": 900 },
"quota": {
"running_session_limit": 3,
"running_sessions_used": 1,
"running_sessions_remaining": 2
}
}Eine erfolgreiche Antwort enthält:
| Feld | Beschreibung |
|---|---|
id | Sitzungs-ID für die anderen Endpunkte. |
name | Der Name, den du angegeben hast, oder der erzeugte. |
image | Das Image, auf dem die Sitzung läuft. |
connectUrl | CDP-WebSocket-URL für Playwright oder Puppeteer. Sie enthält ein eigenes Token der Sitzung; behandle sie wie ein Passwort. |
liveViewUrl | Die Live-Ansicht der Sitzung in Guard.ch, zum Zuschauen und Übernehmen. Zum Öffnen musst du in deinem Konto angemeldet sein. |
createdAt | Startzeit im Format ISO 8601. |
screen | Der Viewport, mit dem der Browser läuft. |
quota | Deine gleichzeitigen Sitzungen inklusive dieser: running_session_limit, running_sessions_used und running_sessions_remaining. |
Ein abgelehnter Start enthält zusätzlich einen maschinenlesbaren code:
| Code | Bedeutung |
|---|---|
invalid_arguments | Ein Wert ist nicht verwendbar, etwa ein fehlerhafter Proxy. Die meisten Feldprüfungen antworten ohne Code; dann nennt message das Feld. |
image_not_supported | Das Image gibt es nicht, oder es kann keine API-Sitzungen ausführen. allowedImages listet die Images, die du nutzen kannst. |
image_restricted | Dein Plan kann dieses Image nicht starten (Status upgrade). allowedImages listet die Images, die du nutzen kannst. |
quota_exceeded | Alle deine Sitzungsplätze sind belegt, ein Kontingent ist aufgebraucht, oder deinem Plan fehlt eine Option, die du angefragt hast. Beende eine Sitzung oder ändere die Anfrage; derselbe Aufruf noch einmal hilft nicht. |
rate_limited | Du hast in kurzer Zeit zu viele Sitzungen gestartet. retryAfterMs sagt dir, wie viele Millisekunden du warten sollst. |
internal_error | Bei uns ist etwas fehlgeschlagen (Status error). Versuch es später noch einmal. |
Sitzungen auflisten
GET https://api.guard.ch/v8/web/sessionsGibt deine Sitzungen in data zurück, die neuste zuerst. Aufgelistet werden nur Sitzungen, die über die API oder MCP gestartet wurden. Untersuchungen, die du in Guard.ch von Hand startest, fehlen hier; mit GET /web/sessions/:id findest du sie trotzdem über ihre ID.
| Parameter | Beschreibung |
|---|---|
status | all nimmt beendete Sitzungen der letzten 30 Tage dazu. Ohne den Parameter siehst du nur Sitzungen, die gerade starten oder laufen. |
limit | Höchstzahl der Sitzungen, 1 bis 200. Standard: 50. |
curl "https://api.guard.ch/v8/web/sessions?status=all&limit=20" \
-H "Authorization: Bearer YOUR_API_KEY"{
"status": "ok",
"data": [
{
"id": "brl-v-v7-q8m2r7k4d1",
"name": "triage-4821",
"image": "chrome",
"status": "running",
"createdAt": "2026-09-26T08:14:03.512Z",
"endedAt": null,
"endedReason": null,
"expiresAt": "2026-09-27T02:14:03.512Z",
"lastseen": "2026-09-26T08:31:40.087Z",
"url": "https://example.com",
"country": "de",
"connectUrl": "wss://api.guard.ch/web/brl-v-v7-q8m2r7k4d1/cdp?token=3f9c2a7d",
"liveViewUrl": "https://guard.ch/en/viewer?id=brl-v-v7-q8m2r7k4d1",
"startedByKind": "agent",
"analysisEnabled": false,
"startedBy": { "id": 4821, "email": "[email protected]", "firstname": "Ana", "lastname": "Meier" }
}
]
}Jede Sitzung hat diese Felder:
| Feld | Beschreibung |
|---|---|
id, name, image | Sitzungs-ID, Anzeigename und Image, wie beim Start zurückgegeben. |
status | starting oder running, solange die Sitzung läuft. Jeder andere Wert heisst, dass sie beendet ist. |
createdAt, endedAt | Start- und Endzeit im Format ISO 8601. endedAt ist null, solange die Sitzung läuft. |
endedReason | Warum sie endete: stopped (von dir oder über die API beendet), timeout (maximale Laufzeit erreicht), disconnect (zu lange nichts verbunden), runtime (Laufzeitkontingent des Plans aufgebraucht), error oder lost (der Browser ist ausgefallen oder seine Maschine ist weg). Null, solange sie läuft. |
expiresAt | Der späteste Zeitpunkt, zu dem die Sitzung endet, festgelegt durch deinen Plan. Sie kann auch früher enden, siehe Limits. |
lastseen | Wann ein verbundener Client die Sitzung zuletzt am Leben gehalten hat. |
url | Die Startadresse aus der Anfrage oder null. |
country | Standortcode oder null. |
connectUrl | CDP-WebSocket-URL, solange die Sitzung startet oder läuft, sonst null. |
liveViewUrl | Die Live-Ansicht in Guard.ch. |
startedByKind | agent für Sitzungen, die über die API oder MCP gestartet wurden, app für Untersuchungen, die jemand von Hand gestartet hat. |
analysisEnabled | Ob die Live-Analyse gerade eingeschaltet ist. |
startedBy | Das Konto, das die Sitzung gestartet hat: id, email, firstname und lastname. |
Sitzung abrufen
GET https://api.guard.ch/v8/web/sessions/:idGibt eine Sitzung in data zurück, mit denselben Feldern wie die Liste. So findest du auch Untersuchungen, die du in Guard.ch von Hand gestartet hast, und ein Skript kann sich über ihre connectUrl damit verbinden. Eine unbekannte ID oder die Sitzung einer anderen Person ergibt denied.
Sitzung beenden
DELETE https://api.guard.ch/v8/web/sessions/:idBeendet die Sitzung, entfernt ihren Browser und gibt den Platz sofort frei. Die Antwort ist ok, auch wenn die Sitzung schon beendet war. endedReason wird zu stopped, ausser die Sitzung endete vorher aus einem anderen Grund. Das beendet auch Untersuchungen, die du von Hand gestartet hast; beende also nur, was dein Skript gestartet hat.
curl -X DELETE https://api.guard.ch/v8/web/sessions/brl-v-v7-q8m2r7k4d1 \
-H "Authorization: Bearer YOUR_API_KEY"Datei herunterladen
GET https://api.guard.ch/v8/web/sessions/:id/downloads/:downloadIdGibt die Bytes einer Datei zurück, die der Browser während der Sitzung heruntergeladen hat, mit Inhaltstyp und Dateiname. Die Download-ID (d1, d2, ...) liefert das MCP-Tool browser_downloads zusammen mit dieser URL.
Anders als alle anderen Endpunkte antwortet dieser mit echten HTTP-Statuscodes: 200 mit der Datei oder 404 mit Status denied, wenn die Datei nicht verfügbar ist. Die Datei wird mit den Cookies der Seite noch einmal angefordert; ein einmaliger oder abgelaufener Download-Link ergibt deshalb 404.
Nutzung und Kontingent
API-Nutzung
GET https://api.guard.ch/v8/web/usageSummen über die Sitzungen, die dein Konto über die API oder MCP gestartet hat:
| Feld | Beschreibung |
|---|---|
activeSessions | Sitzungen, die gerade starten oder laufen. |
sessionsLast30d | In den letzten 30 Tagen gestartete Sitzungen. |
totalMinutesLast30d | Ihre gesamte Laufzeit in Minuten; laufende Sitzungen zählen bis jetzt. |
plan | Dein Plan: name, runningSessionLimit (gleichzeitige Sitzungen) und featureProgrammaticAccess. |
pools | Ein Eintrag pro Abo: subscription_id, plan_id, plan_name, running_session_limit und running_sessions_used. Ein Datenpaket, das nur Residential-Verkehr finanziert, zeigt das Limit 0. |
Limits des Plans
GET https://api.guard.ch/v8/user/quotaDie Zähler, die dein Plan durchsetzt, über alle Sitzungen deines Kontos, egal ob von Hand oder über die API gestartet:
| Feld | Beschreibung |
|---|---|
has_plan | Ob ein aktiver Plan gilt. |
running_session_limit, running_sessions_used, running_sessions_remaining | Gleichzeitige Sitzungen: erlaubt, belegt und frei. |
cycle_start, cycle_session_limit, cycle_sessions_used, cycle_sessions_remaining | Beginn des aktuellen Abrechnungszyklus und die darin gezählten Sitzungen. Null als Limit heisst unbegrenzt. |
residential_cycle_mb_limit, residential_bytes_used_cycle | Dein Residential-Kontingent für den Zyklus in MB (null, wenn unbegrenzt oder ohne Plan) und der Verbrauch in Bytes. |
pools | Dieselben Zähler pro Abo, mit subscription_id, plan_id und plan_name. |
Images und Standorte
GET https://api.guard.ch/v8/imageDer Katalog hinter den Feldern image, country und egress. Dafür brauchst du keinen Schlüssel.
curl https://api.guard.ch/v8/image| Feld | Beschreibung |
|---|---|
images | Browser-Images mit id, name, picture, enabled, requires_feature_restricted_images, supports_analysis und supports_programmatic. Nimm ein Image, das aktiv ist und programmatischen Zugriff unterstützt. |
vpnLocations | Länder mit code, name, default (die Stadt, zu der ein reiner Ländercode aufgelöst wird) und cities mit je code und location. Als country funktionieren Länder- und Stadtcodes. |
residential | Abdeckung des Residential-Ausgangs: configured und countries mit den erreichbaren Ländercodes (null: alle Länder). |
Limits
- Drei gleichzeitige Sitzungen pro Person. Das gilt für Guard Analyst und Guard Team, und Sitzungen, die du von Hand startest, zählen mit. Sind alle Plätze belegt, wird eine neue Sitzung abgelehnt und nicht eingereiht.
- Sitzungen enden von selbst. Eine Sitzung endet etwa fünf Minuten, nachdem sich der letzte Client getrennt hat, spätestens aber bei
expiresAt: 18 Stunden nach dem Start. Beende Sitzungen, die du nicht mehr brauchst, dann ist ihr Platz sofort wieder frei. - Das Starten ist begrenzt. Pro Minute, Stunde und Tag gelten Limits, je App-Schlüssel und je Konto. Eine Ablehnung enthält
code: rate_limitedundretryAfterMs. - Auch Anfragen sind begrenzt. Der API-Host nimmt von einer IP-Adresse etwa zwei Anfragen pro Sekunde an, kurze Spitzen darüber sind möglich. Darüber hinaus lautet die Antwort
denied; warte kurz und versuch es noch einmal. - Aufrufe kosten nichts extra. Weder Anfragen noch Sitzungen werden nach Menge abgerechnet. Residential-Verkehr zählt gegen das Kontingent deines Plans im Abrechnungszyklus.
Sicherheit
- Ein App-Schlüssel hat auf diesen Endpunkten dieselben Rechte wie dein Konto. Bewahr ihn in einem Secret Store auf und widerrufe ihn unter Apps, falls er je nach aussen gelangt.
- Schick Schlüssel nur im Authorization-Header, nie in URLs, wo sie in Logs und im Browserverlauf landen.
- Jede
connectUrlhat ein eigenes Token und funktioniert nicht mehr, sobald die Sitzung endet. Logge oder teile sie nicht. - Zielseiten laden in unserer Infrastruktur, nie auf dem Rechner, der die API aufruft.
Fragen zur API?
Unklarheiten bei einem Endpunkt, oder fehlt dir etwas für deine Integration? Schreib uns.