API-Referenz

Dateiverwaltung

Ordner

{ "id": 4, "parent_id": null, "name": "Produktbilder" }
Endpunkt Zugriff Beschreibung
GET /folders 🔑 Alle Ordner (flach, über parent_id verschachtelt)
POST /folders ✏️ Body { "name": "…", "parent_id": null } → 201
PUT /folders/{id} ✏️ Umbenennen { "name": "…" } und/oder Verschieben { "move": true, "parent_id": 4 } (null = Hauptordner; 400 folder.cycle bei Verschieben in sich selbst oder einen Unterordner, 404 bei unbekanntem Ordner) → 204
DELETE /folders/{id} ✏️ Löscht Ordner und Unterordner; enthaltene Dateien wandern in den Hauptordner (folder_id: null) → 204

Dateien

Datei-Objekt

{
  "id": 7,
  "folder_id": 4,
  "name": "sneaker.jpg",
  "path": "2026/10/sneaker-1a2b3c4d.jpg",
  "mime": "image/jpeg",
  "size": 482113,
  "width": 2400,
  "height": 1600,
  "alt": "Weißer Sneaker auf Holzboden",
  "variants": [
    { "width": 320,  "height": 213,  "path": "2026/10/sneaker-1a2b3c4d-320w.jpg" },
    { "width": 640,  "height": 426,  "path": "2026/10/sneaker-1a2b3c4d-640w.jpg" },
    { "width": 960,  "height": 640,  "path": "2026/10/sneaker-1a2b3c4d-960w.jpg" },
    { "width": 1280, "height": 853,  "path": "2026/10/sneaker-1a2b3c4d-1280w.jpg" },
    { "width": 1920, "height": 1280, "path": "2026/10/sneaker-1a2b3c4d-1920w.jpg" }
  ],
  "created_at": 1791191677,
  "private": false,
  "url": "/media/2026/10/sneaker-1a2b3c4d.jpg",
  "srcset": "/media/2026/10/sneaker-1a2b3c4d-320w.jpg 320w, …, /media/2026/10/sneaker-1a2b3c4d.jpg 2400w",
  "tag": "<img src=\"/media/…\" srcset=\"…\" sizes=\"100vw\" width=\"2400\" height=\"1600\" alt=\"…\" loading=\"lazy\" decoding=\"async\">"
}
Feld Beschreibung
name Anzeigename (Original-Dateiname, änderbar)
path Speicherpfad unter /media/ (nicht änderbar)
width, height Pixelmaße bei Rastergrafiken (JPEG, PNG, GIF, WebP), sonst 0
variants Automatisch erzeugte verkleinerte Fassungen für srcset – nur für JPEG und PNG, nur für Breiten kleiner als das Original (320, 640, 960, 1280, 1920 px)
url Öffentliche URL des Originals
srcset Fertiges srcset-Attribut (Varianten + Original); leer ohne Varianten
tag Fertiges responsives <img>-Element (nur bei Bildern)
private Private Datei: /media/… liefert sie (samt Varianten und WebP-Fassungen) nur angemeldet oder mit signiertem Link, sonst 404 – siehe Handbuch

GET /files 🔑

Query Beschreibung
folder Ordner-ID oder root (Standard: Hauptordner)
all=1 Dateien aus allen Ordnern
q Suche in Name und Alt-Text
type MIME-Hauptklasse, z. B. image, video, application

Sortierung: neueste zuerst.

curl -H "Authorization: Bearer $TOKEN" "https://example.com/api/v1/files?all=1&type=image&q=sneaker"

GET /files/{id} 🔑

Einzelne Datei.

POST /files ✏️

Upload als multipart/form-data. Beliebig viele Felder file, optional ein Feld folder_id und ein Feld private (1/true = als private Datei anlegen) – beide müssen vor den Dateien stehen.

curl -H "Authorization: Bearer $TOKEN" \
     -F folder_id=4 \
     -F file=@sneaker.jpg \
     -F file=@datenblatt.pdf \
     https://example.com/api/v1/files

Antwort 201: Array der angelegten Datei-Objekte.

Limits: 64 MB pro Datei, 256 MB pro Request. Dateinamen werden bereinigt (Kleinbuchstaben, nur a-z0-9._-) und mit einem Zufallssuffix versehen; Uploads landen in media/JJJJ/MM/.

PUT /files/{id} ✏️

{ "name": "sneaker-weiss.jpg", "alt": "Weißer Sneaker", "move": true, "folder_id": null }
Feld Beschreibung
name Neuer Anzeigename (leer = unverändert)
alt Alt-Text
move + folder_id Nur wenn move: true, wird folder_id übernommen (null = Hauptordner)
private true/false schaltet die Datei privat bzw. öffentlich – wirkt sofort auf /media/…. Ohne Feld unverändert

POST /files/{id}/signed-url 🔑

Erzeugt einen signierten Link auf die Datei – für private Dateien gedacht, für öffentliche harmlos. Body optional:

{ "ttl": 604800 }

ttl = Gültigkeit in Sekunden, Standard 86400 (1 Tag), erlaubt 60 bis 2592000 (30 Tage), sonst 400 (file.ttlInvalid). Antwort:

{ "url": "/media/2026/10/angebot-1a2b3c4d.pdf?exp=1791796477&sig=Q2x…", "expires_at": 1791796477 }

url ist relativ zur Instanz. Die Signatur (HMAC-SHA256 über Pfad und Ablaufzeit, Geheimnis je Instanz, nicht im Bundle) gilt für das Original samt Varianten und WebP-Fassungen, auch mit ?w=/?format= dahinter, und lässt sich weder verlängern noch auf andere Dateien übertragen. Einzelne Links lassen sich nicht widerrufen. Leert den Seiten-Cache nicht.

DELETE /files/{id} ✏️

Löscht Datenbankeintrag, Original und alle Varianten. 204. Mit ?if_unused=1 nur, wenn die Datei nirgends verwendet wird (Prüfung unmittelbar vor dem Löschen, siehe POST /files/usage); sonst 409 file.inUse mit refs und more.

POST /files/{id}/replace ✏️

Ersetzt den Inhalt einer Datei an Ort und Stelle: ID, Pfad und damit alle Verwendungen bleiben, Typ, Größe, Maße und Bildvarianten (auch die WebP-Fassungen) werden neu berechnet, die alten Varianten entfallen. multipart/form-data mit einem Feld file (bis 64 MB). Die Dateiendung muss gleich bleiben (400 file.replaceTypeMismatch, params.ext). Antwort 200 mit dem Datei-Objekt. Löst das Ereignis content.changed (file/updated) aus.

POST /files/usage 🔑

Wo werden Dateien verwendet? Body { "ids": [31, 32] } (höchstens 200, sonst 400 file.tooManyIDs). Antwort { "usage": { "31": { "used": true, "refs": [{ "kind": "page", "id": 1, "title": "Start", "path": "/" }], "more": 0 }, "32": { "used": false, "refs": [], "more": 0 } } }. Unbekannte IDs fehlen im Ergebnis.

used ist maßgeblich und folgt derselben vorsichtigen Prüfung wie das Aufräumen (im Zweifel verwendet). refs sind die gefundenen Stellen (höchstens 10, weitere zählt more): kind = page, item (mit collection = Slug), global, snippet, collection, redirect, source, workflow, pen. Das sind Auskünfte für Menschen – bei Verweisen, die sich keiner Stelle zuordnen lassen, kann refs trotz used: true leer sein. Lesend (leert den Seiten-Cache nicht).

GET /cleanup ✏️ · POST /cleanup ✏️

Aufräumen: GET listet ungenutzte Dateien und CSS/JS-Assets (Kriterien im Handbuch).

{
  "files": [{ "id": 31, "name": "altes-foto.png", "path": "2026/10/altes-foto-1a2b.png", "url": "/media/2026/10/altes-foto-1a2b.png", "mime": "image/png", "size": 3512, "width": 1200, "height": 630, "folder_id": null, "imported": false }],
  "files_bytes": 3512,
  "assets": [{ "id": 7, "name": "webflow-alt", "kind": "css", "size": 13, "imported": true }]
}

POST mit { "files": [31], "assets": [7] } löscht die angegebenen – aber nur, was bei einer erneuten Prüfung immer noch ungenutzt ist. Antwort { "files": 1, "assets": 1, "bytes": 3512, "skipped": 0 } (skipped: inzwischen verwendet oder nicht gefunden).