Zum Hauptinhalt springen

Anhänge verwalten

Ziel

Du tauschst Dokumente mit der Plattform aus: die Anhänge eines Falls auflisten, einzelne Metadaten lesen, Dateien herunterladen, eigene Dateien hochladen und wieder löschen. Typischer Anwendungsfall einer Kanzlei- oder Werkstatt-Anbindung: Gutachten und Rechnungen abholen, eigene Schriftsätze ablegen.

Voraussetzungen

  • Scopes: attachments:read (Liste, Metadaten, Download), attachments:write (Upload, Löschen). Beide sind als erhöhtes Risiko eingestuft — Anhänge enthalten Vollmachten, Gutachten und Rechnungen.
  • Sichtbarkeit: Der Fall muss im Mandanten des Keys liegen und für die Grant-Person sichtbar sein. Bei den /attachments/{attachmentId}-Pfaden löst der Server zuerst den zugehörigen Fall auf und prüft dessen Standort — erst danach siehst du irgendetwas.
  • Status: Der Upload verlangt einen editierbaren Fall (WORK_IN_PROGRESS, RELEASED, HANDED_OVER_APPRAISER). Lesen, Download und Löschen sind nicht status-beschränkt.
  • Größe: maximal 20 MB pro Datei und Request (globales Multipart-Limit).

1. Anhänge eines Falls auflisten

GET /api/external/v1/cases/{caseId}/attachments (Scope attachments:read)

Antwort ist ein JSON-Array mit den Metadaten:

FeldInhalt
attachmentIdUUID des Anhangs — Schlüssel für Download und Löschen
caseIdUUID des Falls
fileNameOriginaldateiname
tagfachliche Kategorie (AttachmentTag), Default NONE
signabletrue, solange ein generiertes Dokument noch signiert werden kann
createdZeitpunkt des Uploads
signingStatusüber die API immer null — externe Signaturprozesse haben keine externen Endpunkte

Eine Dateigröße enthält das DTO nicht; der Inhalt kommt über einen separaten Aufruf.

Der tag ist für dich das wichtigste Feld: er sagt, was ein Dokument fachlich ist. Die Werte listet das Glossar unter „Anhang-Tag"; die Gates POA_SIGNED, OWN_PROCESSING_POA_SIGNED und EXPERT_OPINION_ORDER_SIGNED entscheiden über Freigabe und Gutachter-Übergabe (siehe Fall freigeben und abschließen).

2. Metadaten eines einzelnen Anhangs

GET /api/external/v1/attachments/{attachmentId} (Scope attachments:read)

Dasselbe DTO wie in der Liste, für genau einen Anhang. Praktisch, wenn du dir nur die attachmentId gemerkt hast.

3. Datei herunterladen

GET /api/external/v1/attachments/{attachmentId}/content (Scope attachments:read)

Liefert die Bytes als erzwungenen Download:

  • Content-Disposition: attachment; filename="…" (der Dateiname ist gegen Header-Injection bereinigt),
  • X-Content-Type-Options: nosniff,
  • Content-Type aus der Dateiendung abgeleitet — SVG und HTML werden immer als application/octet-stream ausgeliefert, damit aktive Inhalte nie inline landen.
curl -sS -o gutachten.pdf \
https://usp.linkki.de/api/external/v1/attachments/$ATTACHMENT_ID/content \
-H "Authorization: Bearer $USP_API_KEY"

Downloads schreiben keinen Historieneintrag und verändern den Fall nicht.

4. Datei hochladen

POST /api/external/v1/cases/{caseId}/attachments (Scope attachments:write)
Content-Type: multipart/form-data, Part-Name: file
curl -sS -X POST https://usp.linkki.de/api/external/v1/cases/$CASE_ID/attachments \
-H "Authorization: Bearer $USP_API_KEY" \
-F "file=@schriftsatz.pdf"

Antwort: 201 Created mit dem AttachmentDTO des neuen Anhangs (tag = NONE, signable = false).

Was der Server prüft und tut:

  • Fall existiert, liegt im Mandanten, ist für die Grant-Person sichtbar — sonst 404.
  • Fall ist editierbar — sonst 409 CONFLICT.
  • Datei ist nicht leer und ihr Name führt nicht aus dem Anhang-Verzeichnis heraus — sonst 400 VALIDATION.
  • Keine Formatbeschränkung: es gibt auf dieser Fläche keine Endungs- oder Content-Type-Allowlist (die existiert nur für Uploads aus dem Kundenportal).
  • Es entsteht ein Fallhistorie-Eintrag — der Fall gilt danach als geändert, siehe unten. Eine Mail löst ein Upload nicht aus.

Der Upload ist nicht idempotent: ein Retry nach Timeout kann dieselbe Datei ein zweites Mal anlegen. Prüfe im Zweifel erst die Liste, bevor du erneut hochlädst.

5. Anhang klassifizieren (Tag setzen)

curl -sS -X PUT "$USP_BASE/attachments/$ATT_ID/tag" \
-H "Authorization: Bearer $USP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"tag":"INVOICE_REPAIR"}' | jq '{attachmentId, tag, fileName}'

Scope attachments:write. Setzt den Anhang-Tag und schreibt einen Fallhistorie-Eintrag (bewegt lastModifiedDate des Falls). Der Aufruf ist idempotent — derselbe Tag noch einmal ist ein No-op; NONE entfernt die Klassifizierung. Der Fallstatus spielt keine Rolle (auch CLOSED/CANCELLED, wie beim Löschen).

Die *_SIGNED-Tags sind bewusst setzbar — der gedachte Fall ist ein auf Papier signiertes, gescanntes Dokument: hochladen, dann POA_SIGNED (bzw. OWN_PROCESSING_POA_SIGNED, EXPERT_OPINION_ORDER_SIGNED) setzen. Beachte, dass sie Workflow-Gates schalten: Freigabe bzw. Gutachter-Übergabe werden dadurch möglich.

6. Anhang löschen

DELETE /api/external/v1/attachments/{attachmentId} (Scope attachments:write)

Antwort 204 No Content. Es ist ein Hard-Delete: Datenbankzeile und Datei auf der Platte sind weg, es gibt keinen Papierkorb und keine Wiederherstellung. Auch signierte Vollmachten und Gutachtenaufträge sind löschbar — damit kann ein Löschvorgang die Freigabe-Voraussetzung eines Falls zerstören.

Es gibt hier kein Status-Gate: auch Anhänge geschlossener Fälle lassen sich löschen. Ein Historieneintrag wird geschrieben.

Achtung: Optimistic Lock

Jeder Upload und jedes Löschen schreibt einen Fallhistorie-Eintrag und schiebt damit das lastModifiedDate des Falls vor. Ein danach abgesetztes PUT /cases/{caseId} mit dem alten Zeitstempel scheitert mit 400 ALREADY_MODIFIED.

Zwei saubere Reihenfolgen:

  1. erst PUT /cases/{caseId}, danach die Anhänge — oder
  2. erst die Anhänge, danach GET /cases/{caseId} und mit dem frischen Zeitstempel schreiben.

Details unter Übersicht und Bearbeitung.

Noch nicht verfügbar

FähigkeitStand
Vollmacht/RKÜ, Gutachtenauftrag, Reparaturablaufplan erzeugenexistiert extern nicht
Dokumente signieren oder PDF-Formulare ausfüllenexistiert extern nicht
Dokument per Mail an die Kund_in sendenexistiert extern nicht
Externen Signaturprozess starten oder abfragenexistiert extern nicht (signingStatus bleibt null)

Was kann schiefgehen?

HTTPcodeWannWas tun
400VALIDATIONleere Datei oder Dateiname mit Pfad-TraversalDatei mit Inhalt und normalem Namen hochladen
403ACCESS_DENIEDKey ohne attachments:read bzw. attachments:writeKey-Scopes prüfen
404NOT_FOUNDFall oder Anhang unbekannt, fremder Mandant oder außerhalb der Sichtbarkeit — bewusst ununterscheidbarIDs prüfen; Liste neu laden (der Anhang kann gelöscht worden sein)
409CONFLICTUpload auf einen nicht editierbaren Fall (CLOSED, CANCELLED, WAITING_FOR_CUSTOMER)Fallstatus prüfen
413(kein code)Datei größer als das 20-MB-Multipart-LimitDatei verkleinern oder aufteilen
415(kein code)Request nicht als multipart/form-data gesendetContent-Type und Part-Namen file prüfen
429RATE_LIMITED / API_RATE_LIMITEDRate-Limit erreicht — Downloads zählen wie jeder andere RequestRetry-After abwarten, Downloads drosseln
500INTERNAL_ERRORIO-Fehler beim Speichern, oder die Datei fehlt im Anhang-VerzeichniserrorId an den Support geben

Sequenzdiagramm