API-Dokumentation
Die Privago REST-API deckt den kompletten Upload → Redact → Export Flow ab. Hinweis: Einen Maschinenzugang (API-Schlüssel oder Service-Accounts) gibt es derzeit nicht — die folgenden Beispiele setzen ein Token aus einer aktiven Browser-Sitzung voraus. Interaktive Swagger-UI: privago.eu/docs
1. Authentifizierung
Alle Endpunkte (außer /health) erfordern einen gültigen JWT-Bearer-Token aus Keycloak. Token-Lebensdauer: 5 Minuten.
# Token abrufen (Keycloak)
# HINWEIS: Der Password-Grant (Direct Access Grants) ist im Realm derzeit
# DEAKTIVIERT — dieses Beispiel setzt voraus, dass er fuer API-Zugriffe
# freigeschaltet wurde. Eigene API-Keys existieren noch nicht (Roadmap).
TOKEN=$(curl -s -X POST \
https://privago.eu/auth/realms/privago/protocol/openid-connect/token \
-d "grant_type=password" \
-d "client_id=privago-api" \
-d "username=DEINE_EMAIL" \
-d "password=DEIN_PASSWORT" \
| jq -r '.access_token')
echo $TOKENDen Token bei jedem Request als Authorization: Bearer $TOKEN Header mitsenden.
2. Dokument hochladen
POST /api/v1/documents — Multipart-Form mit file Feld. Max. 100 MB und 150 Seiten. Unterstütztes Format: PDF (digital oder gescannt).
curl -s -X POST https://privago.eu/api/v1/documents \
-H "Authorization: Bearer $TOKEN" \
-F "file=@vertrag.pdf" \
| jq .
# Antwort:
# {
# "data": {
# "document_id": "550e8400-e29b-41d4-a716-446655440000",
# "filename": "vertrag.pdf",
# "status": "uploaded"
# }
# }
DOC_ID="550e8400-e29b-41d4-a716-446655440000"3. Verarbeitungsstatus prüfen
GET /api/v1/documents/{id} — Poll alle 2 Sekunden bis status == "ready_for_review".
# Einmalig prüfen
curl -s -H "Authorization: Bearer $TOKEN" \
https://privago.eu/api/v1/documents/$DOC_ID \
| jq '.data.status'
# Poll-Loop (bash)
while true; do
STATUS=$(curl -s -H "Authorization: Bearer $TOKEN" \
https://privago.eu/api/v1/documents/$DOC_ID | jq -r '.data.status')
echo "Status: $STATUS"
[ "$STATUS" = "ready_for_review" ] && break
[ "$STATUS" = "failed" ] && echo "Fehler!" && exit 1
sleep 2
doneStatus-Werte:
uploaded— Hochgeladen, Verarbeitung startetprocessing— KI analysiert das Dokumentready_for_review— Analyse abgeschlossen, bereit zur Prüfungfailed— Verarbeitung fehlgeschlagenexported— PDF wurde geschwärzt und exportiert
4. PII-Entitäten abrufen
GET /api/v1/documents/{id}/entities — gibt alle erkannten PII-Entitäten zurück. Unterstützt Pagination (page, page_size) und Filter (category, min_confidence).
curl -s -H "Authorization: Bearer $TOKEN" \
"https://privago.eu/api/v1/documents/$DOC_ID/entities?page_size=50" \
| jq '.data[] | {id, category, text, confidence, status}'
# Nur Personennamen mit Konfidenz > 80%:
curl -s -H "Authorization: Bearer $TOKEN" \
"https://privago.eu/api/v1/documents/$DOC_ID/entities?category=person_name&min_confidence=0.8" \
| jq .5. Entitäten akzeptieren
PATCH /api/v1/documents/{id}/entities/{entity_id} — Status setzen auf accepted oder rejected.
Für die offenen Vorschläge mehrerer Kategorien auf einmal: PATCH /api/v1/documents/{id}/entities mit from_status, to_status und der Pflichtliste categories. Nur Vorschläge dieser Kategorien ändern sich. Zulässig ist jeder Eintrag (bis 50 Zeichen, höchstens 512 Einträge), der eine bekannte Kategorie ist oder im Dokument offene Vorschläge hat — auch manual. Fehlt die Liste, ist sie leer oder ist ein Eintrag weder bekannt noch offen, antwortet die API mit 422 und ändert nichts. Die Aktion läuft serverseitig über alle Entitäten des Dokuments in diesen Kategorien — anders als eine Schleife über eine abgerufene Seite, die bei 200 Einträgen endet. Welche Kategorien noch offene Vorschläge haben, nennt meta.open_by_category in GET /api/v1/documents/{id}/entities.
ENTITY_ID="abc123..."
# Entität akzeptieren (wird im Export geschwärzt)
curl -s -X PATCH \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"status": "accepted"}' \
https://privago.eu/api/v1/documents/$DOC_ID/entities/$ENTITY_ID \
| jq '.data.status'
# Offene Vorschlaege je Kategorie (nur Zahlen)
curl -s -H "Authorization: Bearer $TOKEN" \
https://privago.eu/api/v1/documents/$DOC_ID/entities \
| jq '.meta.open_by_category'
# Offene Vorschlaege der genannten Kategorien auf einmal entscheiden
curl -s -X PATCH \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"from_status": "proposed", "to_status": "accepted", "categories": ["iban", "person_name"]}' \
https://privago.eu/api/v1/documents/$DOC_ID/entities \
| jq '.data.updated_count'
# Oder: den Rest einer Kategorie ablehnen, nachdem einzelne akzeptiert wurden
curl -s -X PATCH \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"from_status": "proposed", "to_status": "rejected", "categories": ["phone"]}' \
https://privago.eu/api/v1/documents/$DOC_ID/entities \
| jq '.data.updated_count'6. Export auslösen & herunterladen
POST /api/v1/documents/{id}/export — Startet den asynchronen Export-Task. Danach poll auf GET /export/{export_id} bisstatus == "ready".
# Export starten
EXPORT_ID=$(curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
https://privago.eu/api/v1/documents/$DOC_ID/export \
| jq -r '.data.export_id')
# Status pollen
while true; do
RESULT=$(curl -s -H "Authorization: Bearer $TOKEN" \
https://privago.eu/api/v1/documents/$DOC_ID/export/$EXPORT_ID)
STATUS=$(echo $RESULT | jq -r '.data.status')
echo "Export-Status: $STATUS"
if [ "$STATUS" = "ready" ]; then
break
fi
[ "$STATUS" = "failed" ] && echo "Export fehlgeschlagen!" && exit 1
sleep 2
done
# Geschwärztes PDF über den Download-Proxy herunterladen.
# Hinweis: das Feld data.download_url ist ein RELATIVER API-Pfad und
# erfordert denselben Bearer-Token wie alle anderen Endpunkte.
curl -L -H "Authorization: Bearer $TOKEN" \
-o geschwärzt.pdf "https://privago.eu/api/v1/documents/$DOC_ID/export/$EXPORT_ID/download"
echo "✅ Gespeichert als geschwärzt.pdf"7. Kompletter Flow (ein Script)
Alles zusammen: Upload → warten → alle akzeptieren → exportieren → herunterladen.
#!/usr/bin/env bash
set -euo pipefail
API="https://privago.eu/api/v1"
FILE="${1:-dokument.pdf}"
# 1. Token
# HINWEIS: Der Password-Grant (Direct Access Grants) ist im Realm derzeit
# DEAKTIVIERT — dieses Beispiel setzt voraus, dass er fuer API-Zugriffe
# freigeschaltet wurde. Eigene API-Keys existieren noch nicht (Roadmap).
TOKEN=$(curl -s -X POST \
https://privago.eu/auth/realms/privago/protocol/openid-connect/token \
-d "grant_type=password&client_id=privago-api" \
-d "username=$PRIVAGO_EMAIL&password=$PRIVAGO_PASSWORD" \
| jq -r '.access_token')
# 2. Upload
DOC_ID=$(curl -s -X POST "$API/documents" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@$FILE" | jq -r '.data.document_id')
echo "Hochgeladen: $DOC_ID"
# 3. Warten bis ready
until [ "$(curl -s -H "Authorization: Bearer $TOKEN" \
"$API/documents/$DOC_ID" | jq -r '.data.status')" = "ready_for_review" ]; do
sleep 2
done
echo "Analyse abgeschlossen"
# 4. Alle offenen Vorschlaege entscheiden.
# Der Export ist gesperrt, solange auch nur eine Erkennung unbearbeitet ist
# (409 EXPORT_INCOMPLETE_REVIEW mit open_count und open_by_category). Die
# Sammelaktion laeuft serverseitig ueber ALLE Entitaeten der genannten
# Kategorien — eine Schleife ueber ?page_size=200 wuerde bei mehr als 200
# Entitaeten den Rest stehen lassen und der Export bliebe gesperrt.
# categories ist Pflicht: hier alle Kategorien mit offenen Vorschlaegen.
# Ist nichts offen, ist die Liste leer — dann gibt es nichts zu entscheiden
# (eine leere Liste beantwortet die API mit 422).
CATS=$(curl -s -H "Authorization: Bearer $TOKEN" \
"$API/documents/$DOC_ID/entities" | jq -c '.meta.open_by_category | keys')
if [ "$CATS" != "[]" ]; then
curl -s -X PATCH -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"from_status\":\"proposed\",\"to_status\":\"accepted\",\"categories\":$CATS}" \
"$API/documents/$DOC_ID/entities" | jq '.data.updated_count'
fi
echo "Entitäten entschieden"
# 5. Export
EID=$(curl -s -X POST -H "Authorization: Bearer $TOKEN" \
"$API/documents/$DOC_ID/export" | jq -r '.data.export_id')
# Auf "failed" pruefen, nicht nur auf "ready" — sonst pollt das Skript endlos,
# wenn ein Guard im Export-Task greift (z.B. no_redactions, wenn alle
# Vorschlaege abgelehnt wurden und keine Schwaerzung uebrig ist).
while true; do
S=$(curl -s -H "Authorization: Bearer $TOKEN" \
"$API/documents/$DOC_ID/export/$EID" | jq -r '.data.status, .data.error')
case "$(echo "$S" | head -1)" in
ready) break ;;
failed) echo "Export fehlgeschlagen: $(echo "$S" | tail -1)"; exit 1 ;;
esac
sleep 2
done
curl -L -H "Authorization: Bearer $TOKEN" \
-o "geschwärzt_$(basename $FILE)" \
"$API/documents/$DOC_ID/export/$EID/download"
echo "✅ Export fertig: geschwärzt_$(basename $FILE)"8. Fehler-Codes
| HTTP | Code | Beschreibung |
|---|---|---|
| 401 | UNAUTHORIZED | Token fehlt oder abgelaufen |
| 402 | — | Monatliches Seitenkontingent erreicht (Klartextmeldung ohne Fehlercode) |
| 404 | NOT_FOUND | Dokument oder Entität nicht gefunden |
| 409 | EXPORT_INCOMPLETE_REVIEW | Export gesperrt: unbearbeitete Vorschläge vorhanden (open_count nennt die Anzahl, open_by_category die Anzahl je Kategorie) |
| 409 | DOCUMENT_NOT_READY | Dokument ist nicht im Zustand ready_for_review oder exported |
| 409 | OCR_REVIEW_REQUIRED | Scan-Ergebnis muss vor dem Export bestätigt werden |
| 410 | ORIGINAL_PURGED | Original nach Aufbewahrungsfrist entfernt — kein Export mehr möglich |
| 422 | VALIDATION_ERROR | Ungültige Request-Parameter, nicht unterstütztes Format, Datei über 100 MB oder mehr als 150 Seiten |
| 429 | RATE_LIMITED | Zu viele Anfragen (Standard 600/min, Upload 30/min, Export 20/min pro IP; Retry-After-Header beachten) |
| 500 | INTERNAL_ERROR | Interner Serverfehler |
9. Rate Limits
- • 600 Requests/Minute pro Client-IP (Standard, alle Endpunkte)
- • 30 Uploads/Minute und 20 Export-Starts/Minute pro Client-IP
- • Bei Überschreitung: HTTP 429 (Code
RATE_LIMITED) mitRetry-After-Header
Interaktive API-Referenz
Alle Endpunkte mit Schemas und Try-it-out direkt im Browser testen.