Zum Inhalt springen

Konventionen

Diese Regeln gelten für jeden Aufruf der REST-API, auch wenn die Seite eines Endpunkts sie nicht eigens nennt.

Fehler

Jede Fehlerantwort hat denselben Körper:

code
enumPflicht
Maschinenlesbarer Fehlercode. Die Oberflächen werten ihn aus, nie den Text. Zeichengleich mit dem Rust-Enum `ErrorCode` in `services/api/src/error.rs`. Seit 1.12.0 trägt `organization_blocked` bei einem Kundenkonto, das seine Agentur gesperrt hat, `details.reason = "blocked_by_agency"`; die Oberfläche verweist dann an die Agentur und nicht an den Support.validation_failed · invalid_domain · unsupported_context · unauthenticated · invalid_credentials · totp_required · forbidden · insufficient_role · domain_not_verified · hacking_not_available · read_only_session · organization_blocked · organization_throttled · api_key_scope_insufficient · not_found · conflict · already_exists · scan_not_cancelable · use_acknowledgment · quota_exceeded · plan_upgrade_required · payment_required · payment_method_required · abuse_limit_exceeded · price_not_set · rate_limited · share_link_expired · artifact_expired · internal_error · service_unavailable
message
stringPflicht
Deutscher Text, der dem Nutzer gezeigt werden darf.
details
object
Feldbezogene Hinweise, etwa bei `validation_failed`.
request_id
string
Referenz der Anfrage: `req_` plus 16 Hexstellen. Sie steht auch im Antwortkopf `x-request-id` und im Server-Log; die Oberfläche zeigt sie auf jeder Fehlerseite und setzt sie in die Support-Mail ein. Sie fehlt nur, wenn der Fehler außerhalb einer Anfrage entstanden ist.
Beispiel
HTTP/1.1 404 Not Found
x-request-id: req_9b1e44af0c37d2e5

{
"code": "not_found",
"message": "Domain nicht gefunden.",
"request_id": "req_9b1e44af0c37d2e5"
}

Werten Sie code aus. message ist deutscher Text für Menschen und kann sich ändern. details ist optional und je Code verschieden aufgebaut.

Jede Antwort trägt den Kopf x-request-id, auch eine erfolgreiche. Bei Fehlern steht derselbe Wert als request_id im Körper. Nennen Sie ihn, wenn Sie sich an den Support wenden. Schicken Sie selbst einen Kopf x-request-id mit, übernimmt die API ihn, solange er höchstens 64 Zeichen aus A-Z, a-z, 0-9, _ und - hat.

Fehlercodes

validation_failed
400
Die Eingabe passt nicht zum Vertrag. details.field nennt die Stelle, soweit sie sich bestimmen lässt.
invalid_domain
400
Kein gültiger Domainname.
unsupported_context
400
Der Kontext ist unbekannt.
unauthenticated
401
Die Anfrage trägt weder einen Schlüssel noch eine gültige Sitzung.
invalid_credentials
401
Der Schlüssel ist unbekannt, widerrufen oder abgelaufen.
totp_required
401
Nur Sitzungen der Web-App: der zweite Faktor fehlt. Schlüssel sind ausgenommen.
forbidden
403
Kein Zugriff auf diese Aktion.
insufficient_role
403
Die Rolle reicht nicht. Ein Schlüssel hat die Rolle Mitglied, Aktionen ab Admin sind ihm verwehrt.
domain_not_verified
403
Aktive Prüfung auf einer Domain ohne gültigen Eigentumsnachweis.
hacking_not_available
403
Eine Prüfstufe jenseits von active ist nicht buchbar.
read_only_session
403
Schreibversuch in der Kundensicht des Supports.
organization_blocked
403
Die Organisation ist gesperrt.
organization_throttled
403
Die Organisation ist gedrosselt.
api_key_scope_insufficient
403
Das Recht des Schlüssels deckt die Aktion nicht.
not_found
404
Nicht vorhanden oder für diesen Zugang unsichtbar, etwa eine Domain außerhalb der Domain-Einschränkung.
conflict
409
Der Zustand lässt die Aktion gerade nicht zu.
already_exists
409
Der Eintrag besteht bereits.
scan_not_cancelable
409
Der Lauf ist bereits beendet und lässt sich nicht mehr abbrechen.
use_acknowledgment
400
accepted und not_applicable setzt eine Quittierung, nicht PATCH am Befund.
quota_exceeded
402
Das Kontingent des Plans ist erschöpft.
plan_upgrade_required
402
Der Plan enthält die Funktion nicht. Auch: Schlüssel im Plan Free, MCP ohne Plan Agentur.
payment_required
402
Im Vertrag geführt, wird derzeit von keinem Aufruf erzeugt.
payment_method_required
402
Abrechnung je Lauf ohne Zahlungsart oder Rechnungsanschrift. details.reason nennt, was fehlt.
abuse_limit_exceeded
429
Missbrauchsgrenze bei Abrechnung je Lauf erreicht. details trägt limit, used und period_end.
price_not_set
402
Abrechnung je Lauf ohne vereinbarten Preis für ein Paket des Laufs. details.packages nennt die Pakete.
rate_limited
429
Zu viele Anfragen je Minute. Retry-After nennt die Wartezeit in Sekunden.
share_link_expired
410
Der Teilen-Link ist abgelaufen.
artifact_expired
410
Die Aufbewahrungsfrist des Artefakts ist abgelaufen.
internal_error
500
Unerwarteter Fehler auf unserer Seite.
service_unavailable
503
Ein Dienst dahinter, etwa der Zahlungsdienstleister, ist gerade nicht erreichbar.

Welche Codes ein einzelner Aufruf liefern kann, steht auf seiner Seite unter den Antwortcodes.

Paginierung

Listen mit vielen Einträgen werden seitenweise ausgeliefert, mit einem Cursor. Das gilt für GET /v1/domains, GET /v1/scans, GET /v1/clients, GET /v1/reports und GET /v1/billing/usage/scans/entries.

ParameterBedeutung
limitEinträge je Seite, 1 bis 200, Vorgabe 50. Werte außerhalb setzt die API auf die nächste Grenze.
cursorDer Wert von next_cursor aus der vorigen Antwort. Beim ersten Aufruf weglassen.

Die Antwort hat die Form { "items": [...], "next_cursor": "..." }. Steht next_cursor auf null, ist das die letzte Seite. Behandeln Sie den Cursor als undurchsichtige Zeichenkette. Einen Cursor, den die API nicht lesen kann, beantwortet sie mit 400 validation_failed.

Kürzere Listen kommen ohne Seiten als ganzes Array, etwa die Zeitpläne und die Quittierungen einer Domain. Ein Beispiel für das Blättern steht unter Scans auflisten.

Rate-Limits

Anfragen mit API-Schlüssel werden je Kalenderminute gezählt, REST und MCP zusammen:

GrenzeWert
je Schlüssel30 Anfragen je Minute
je Organisation, über alle Schlüssel300 Anfragen je Minute

Wer darüber liegt, bekommt 429 mit dem Code rate_limited. Der Kopf Retry-After nennt die Sekunden bis zum Beginn der nächsten Minute. details sagt, welche Grenze gegriffen hat:

429 rate_limited
HTTP/1.1 429 Too Many Requests
Retry-After: 17

{
"code": "rate_limited",
"message": "Zu viele Anfragen mit diesem API-Schlüssel: höchstens 30 je Minute. Bitte 17 Sekunden warten.",
"details": { "scope": "api_key", "limit": 30, "retry_after": 17 },
"request_id": "req_9b1e44af0c37d2e5"
}

details.scope ist api_key oder organization. Warten Sie die genannte Zeit ab, bevor Sie es erneut versuchen. Auch eine abgewiesene Anfrage zählt mit.

Domain-Einschränkung

Ein Schlüssel kann auf einzelne Domains der Organisation beschränkt sein. Für ihn existieren die übrigen Domains nicht: Listen lassen sie aus, und ein Aufruf auf eine solche Domain, ihre Läufe oder ihre Zeitpläne endet mit 404 not_found. Ein 403 würde verraten, dass es die Domain gibt.

Die Nutzung gilt für die ganze Organisation. Ein Schlüssel mit Domain-Einschränkung liest sie deshalb nicht und bekommt dort 403 api_key_scope_insufficient, auch mit dem Recht full oder read_only.

Keine Webhooks

Redcheck ruft keine Adresse bei Ihnen auf, wenn ein Lauf fertig ist. Für Automatik gibt es zwei Wege:

  • Abfragen von GET /v1/scans/{id}, bis status einen Endzustand erreicht. Fragen Sie dabei höchstens alle fünf Sekunden.
  • Der Ereignisstrom GET /v1/scans/{id}/stream als Server-Sent Events, der mit dem Ereignis done endet.

POST /v1/billing/webhook steht zwar im Vertrag, nimmt aber nur Meldungen des Zahlungsdienstleisters an.

Zugang nach Plan

PlanREST mit SchlüsselMCP-Server
Freeneinnein
Projanein
Agenturjaja

Die API prüft den Plan bei jedem Aufruf. Fällt eine Organisation auf Free zurück, ruhen ihre Schlüssel: jeder Aufruf endet mit 402 plan_upgrade_required. Widerrufen wird dabei nichts. Mit der Rückkehr zu Pro oder Agentur gelten dieselben Schlüssel wieder. Ein Schlüssel einer Pro-Organisation bekommt am MCP-Server ebenfalls plan_upgrade_required.