REST-API
Dateien hochladen, Sammlungen erstellen und Freigaben per HTTP verwalten. Alle Antworten sind JSON; für anonyme Uploads ist kein API-Schlüssel erforderlich.
Einführung
Die storage.to-API treibt unsere CLI, Desktop-App, Web-Uploader und alle Drittanbieter-Clients, die du bauen möchtest.
Der Upload-Ablauf besteht aus drei Schritten:
- Initialisieren — Sag uns, dass du eine Datei hochladen möchtest. Wir geben dir eine oder mehrere vorab signierte URLs zurück, die auf Cloudflare R2 zeigen.
- In R2 hochladen — :Lege deine Bytes direkt in die vorab signierten URL(s). Die Bytes laufen nicht über unsere Server.
- Bestätigen — Sag uns, dass der Upload fertig ist. Wir erstellen einen
File-Eintrag und geben dir eine teilbare URL.
Basis-URL
https://storage.to/api
Alle Endpoints unten sind relativ zu dieser Basis. Beispiel: POST /upload/init bedeutet POST https://storage.to/api/upload/init.
Authentifizierung
Die meisten Endpunkte erfordern keine Authentifizierung. Anonyme Uploads sind eine Kernfunktion.
Authentifizierung ist optional und ermöglicht:
- Uploads, die mit deinem Konto verknüpft sind (sichtbar unter /dashboard)
- Premium-Funktionen (dauerhafte Dateien, mehr Speicherplatz)
- Mutationen basierend auf Eigentum (löschen, Passwort setzen, Ablauf ändern), ohne dass der visitor-token-Abgleich nötig ist
Wir verwenden Laravel Sanctum-Bearer-Tokens. Erstelle ein Token über den Desktop-OAuth-Übergang oder die Web-Anmeldung und sende es dann als:
Authorization: Bearer <token>
Besuchertoken
Anonyme Clients brauchen eine Möglichkeit, die Inhaberschaft ihrer eigenen Uploads ohne Konto nachzuweisen. Wir verwenden ein visitor-token — eine zufällige Zeichenkette, die der Client einmal erzeugt und wiederverwendet. Sende es mit jeder Anfrage:
X-Visitor-Token: <random-string>
Im Web wird das Token automatisch im visitor_token-cookie gespeichert. Die CLI speichert es unter ~/.config/storageto/token (siehe CLI-Dokumentation).
Bei Mutation-Endpunkten (löschen, Passwort setzen, Ablauf ändern) ist die Inhaberschaft bestätigt, wenn entweder das Visitor-Token übereinstimmt oder die Anfrage von derselben IP kommt, die die Datei erstellt hat. Beides kann verloren gehen (gelöschte Cookies, Netzwerkwechsel). Das Owner-Token ist der bevorzugte Nachweis für die Zukunft.
Owner-Token
Jeder Endpunkt zum Erstellen von Ressourcen (/upload/init multipart, /upload/confirm, /upload/reserve, /collection) gibt in seiner Antwort ein owner_token zurück. Das Token ist ein signierter Nachweis der Inhaberschaft, der an diese spezielle Ressource gebunden ist—unabhängig von deiner IP oder deinem Visitor-Token.
Speichere das Token zusammen mit der Ressourcen-ID und sende es bei jeder Mutation als:
Authorization: Owner <token>
Oder, wenn du bereits Authorization: Bearer für eine authentifizierte Session verwendest, sende es so:
X-Owner-Token: <token>
Der Server akzeptiert das Owner-Token als gültigen Nachweis der Inhaberschaft zusammen mit dem alten Fallback visitor-token + IP—Clients, die das Token haben, funktionieren auch nach dem Wechsel des Netzwerks oder dem Löschen von Cookies weiter, und Clients ohne Token funktionieren weiterhin genau wie zuvor.
Tokens leben so lange wie die Ressource, sind sicher zum Speichern und laufen nicht unabhängig ab. Ein verlorenes Token bedeutet, die Kontrolle über diese Ressource zu verlieren (Datei/Sammlung/Upload)—behandle sie wie lokale Passwörter.
Fehler
Fehler folgen einem einheitlichen Schema:
{
"success": false,
"error": "Human-readable message"
}
Häufige HTTP-Statuscodes:
| Code | Bedeutung |
|---|---|
200 | OK. |
201 | Erstellt. |
400 | Ungültige Anfrage (z. B. Größenlimit der Sammlung überschritten). |
401 | Passwort erforderlich oder falsch. |
403 | Nicht autorisiert (nicht der Besitzer der Ressource). |
404 | Ressource nicht gefunden oder abgelaufen. |
422 | Validierung fehlgeschlagen oder Einschränkung durch Tarif/Kontingent. |
429 | Ratelimit oder Upload-Kontingent erreicht. |
500 | Serverfehler. Prüfe Status. |
Ratenbegrenzungen
Alle Ratelimits gelten pro IP. Eine 429-Antwort enthält die Standard-Header Retry-After, X-RateLimit-Limit und X-RateLimit-Remaining.
| Geltungsbereich | Limit |
|---|---|
| Upload initialisieren / bestätigen / abbrechen | 60 / Minute |
| Multipart-Abschluss | 500 / Minute |
| Multipart-Teil-URLs | 120 / Minute |
| Batch-Initialisierung / -Bestätigung | 500 / Minute |
| Statusabfragen (Datei & Sammlung) | 120 / Minute |
| Einstellungen (Passwort, Ablauf, max. Downloads) | 30 / Minute |
| Passwortüberprüfung | 10 / Minute |
| Sammlung erstellen | 30 / Minute |
| Verwalten (bereit, löschen) | 60 / Minute |
| Thumbnail-Upload | 120 / Minute |
| ShareX-Upload | 20 / Tag |
| App-Analytics / Fehler | 120 und 60 / Minute |
Upload-Kontingent: Anonyme Clients haben zwei parallele Limits — 100 GB / 24 h pro visitor-token und 500 GB / 24 h pro IP (das IP-Limit fängt tokenlosen Traffic und geteilte Netzwerke ab). Wenn eines davon überschritten wird, bekommst du einen 429 mit Details. Das ist nur ein Upload Kontingent — Downloads sind unbegrenzt und ungedrosselt (werden direkt über R2-signierte URLs bereitgestellt).
Upload
Der Drei-Schritte-Upload-Flow für jede Datei—inklusive Dateien über 5 GB (automatisch multipart). Wenn du nur einen schnellen Upload im Screenshot-Stil brauchst, schau stattdessen bei ShareX vorbei.
/upload/init
60/min
Starte einen Upload. Bei Dateien >50 MB ist die Antwort ein Multipart-Upload (Feld type: "multipart"); ansonsten ein einzelnes presigned PUT.
Request-Body
| Feld | Typ | Beschreibung |
|---|---|---|
filename | string · required | Ursprünglicher Dateiname. Max. 255 Zeichen. |
content_type | string · required | MIME-Typ. |
size | integer · required | Dateigröße in Bytes. Min. 1. |
/upload/parts
Owner only
120/min
Fordert zusätzliche Part-URLs für einen laufenden Multipart-Upload an. Wird verwendet, wenn /init weniger URLs zurückgegeben hat als du Parts hast (oder sie abgelaufen sind).
Request-Body
| Feld | Typ | Beschreibung |
|---|---|---|
upload_id | string · required | Die upload_id von /init. |
part_numbers | array<int> · required | Part-Nummern, für die URLs abgerufen werden sollen. |
/upload/complete-multipart
Owner only
500/min
Schließt einen Multipart-Upload auf R2 ab, sobald alle Parts hochgeladen sind.
Request-Body
| Feld | Typ | Beschreibung |
|---|---|---|
upload_id | string · required | Die upload_id von /init. |
parts | array · required | Jeder Eintrag: { partNumber, etag } aus der R2-Antwort. |
/upload/abort
Owner only
60/min
Bricht einen Multipart-Upload ab und räumt alle unvollständigen Daten auf R2 auf.
Request-Body
| Feld | Typ | Beschreibung |
|---|---|---|
upload_id | string · required | Der Upload, der abgebrochen werden soll. |
/upload/confirm
60/min
Bestätige, dass der Upload abgeschlossen ist. In diesem Schritt erstellen wir den File-Eintrag und geben die freigabefähige URL zurück.
Request-Body
| Feld | Typ | Beschreibung |
|---|---|---|
filename | string · required | Ursprünglicher Dateiname. |
size | integer · required | Dateigröße in Bytes. |
content_type | string · required | MIME-Typ. |
r2_key | string · required | Die r2_key von /init. |
collection_id | string · optional | An eine Sammlung anhängen. |
crc32 | integer · optional | CRC32-Checksumme zur Integritätsprüfung. |
file_id | string(9) · optional | Erfülle eine zuvor reserviert-Datei-ID. |
/file/reserve
60/min
Reserviere eine Date-ID und eine freigabefähige URL vor die Bytes bereit sind. Praktisch, wenn du zuerst einen Link weitergeben und den Upload danach erfüllen musst. Die Berechtigung ist an dein Visitor-Token + deine IP gebunden. Schließe den Upload später mit /upload/init + /upload/confirm ab und übergib dabei file_id zur Bestätigung.
Request-Body
| Feld | Typ | Beschreibung |
|---|---|---|
filename | string · optional | Platzhalter-Dateiname. Standard: "Pending". |
content_type | string · optional | Platzhalter-MIME-Typ. |
/upload/init-batch
500/min
Batch-Äquivalent von /upload/init, optimiert für den Web-Uploader. Startet bis zu 250 Dateien in einem einzigen Round-Trip.
Wird intern vom Web-Uploader verwendet. Die meisten Clients sollten lieber single-file /upload/init verwenden.
/upload/confirm-batch
500/min
Batch-Äquivalent von /upload/confirm. Bestätigt viele Dateien in einem einzigen Round-Trip.
Sammlungen
Eine Sammlung gruppiert mehrere Dateien unter einer einzigen Freigabe-URL (/c/{id}). Bis zu 10.000 Dateien und insgesamt 25 GB.
/collection
30/min
Erstelle eine neue Sammlung. Hänge Dateien danach an, indem du collection_id an /upload/confirm übergibst.
Request-Body
| Feld | Typ | Beschreibung |
|---|---|---|
expected_file_count | integer · optional | Hinweis für die automatische Markierung der Sammlung als bereit, sobald alle erwarteten Dateien bestätigt wurden. |
/collection/{id}/status
120/min
Frage den Status einer Sammlung ab. Markiert die Sammlung außerdem automatisch als bereit, wenn alle erwarteten Dateien bestätigt wurden.
/collection/{id}/ready
Owner only
60/min
Markiere die Sammlung als bereit zum Download. Normalerweise nicht nötig — Sammlungen werden automatisch bereit, sobald expected_file_count erreicht ist.
/collection/{id}
Owner only
60/min
Lösche eine Sammlung und alle ihre Dateien.
/collection/{id}/password
Owner only
30/min
Setze ein Passwort für die Sammlung. Erfordert 4–100 Zeichen.
Request-Body
| Feld | Typ | Beschreibung |
|---|---|---|
password | string · required | 4–100 Zeichen. |
/collection/{id}/password
Owner only
30/min
Entferne das Passwort aus der Sammlung.
/collection/{id}/verify-password
10/min
Prüfe ein Passwort. Gibt 200 bei Erfolg zurück, 401 bei falschem Passwort.
Request-Body
| Feld | Typ | Beschreibung |
|---|---|---|
password | string · required |
/collection/{id}/expiry
Owner only
30/min
Ändere die Ablaufzeit einer Sammlung.
Request-Body
| Feld | Typ | Beschreibung |
|---|---|---|
days | integer · optional | In 1–7 Tagen. Weglassen oder null für dauerhaft (nur Premium). |
/collection/{id}/max-downloads
Owner only
30/min
Setze ein Download-Limit (burn-after-N-downloads). Die Sammlung wird automatisch gelöscht, sobald es erreicht ist.
Request-Body
| Feld | Typ | Beschreibung |
|---|---|---|
max_downloads | integer · optional | 1–1000. Muss den aktuellen Download-Zähler übersteigen. null, um das Limit zu entfernen. |
Dateien
Alle Einstellungen auf Dateiebene (Passwort, Ablauf, max-downloads) spiegeln die Collection-Endpunkte wider. Nur für den Owner.
/file/{id}/status
120/min
Prüfe, ob eine Datei noch auf ihren Upload wartet.
/file/{id}
Owner only
60/min
Lösche eine Datei sofort.
/file/{id}/thumbnail
Owner only
120/min
Lade ein Vorschaubild für eine Video- oder Bilddatei hoch (wird auf der Download-Seite verwendet). Max. 2 MB.
Request-Body
| Feld | Typ | Beschreibung |
|---|---|---|
thumbnail | image · required | Multipart-Upload. Max. 2 MB. |
/file/{id}/password
Owner only
30/min
Setze ein Passwort für eine Datei. Erfordert 4–100 Zeichen.
/file/{id}/password
Owner only
30/min
Entferne das Passwort einer Datei.
/file/{id}/verify-password
10/min
Überprüfe das Passwort einer Datei.
/file/{id}/expiry
Owner only
30/min
Ändere die Ablaufzeit einer Datei.
Request-Body
| Feld | Typ | Beschreibung |
|---|---|---|
days | integer · optional | In 1–7 Tagen. Weglassen oder null für dauerhaft (nur Premium). |
/file/{id}/max-downloads
Owner only
30/min
Begrenze die Gesamtzahl der Downloads einer Datei. Wird automatisch gelöscht, wenn das Limit erreicht ist.
ShareX-Upload
One-shot-Upload-Endpunkt — sende eine Multipart-Datei und erhalte eine freigabefähige URL zurück. Kein init/confirm-Tanz. Ideal für Screenshot-Tools. Vollständige Anleitung unter /de/docs/sharex.
Desktop-Authentifizierung
Für authentifizierte Clients (z. B. die Desktop-App), die einen Sanctum-Token besitzen.
/user
Bearer token
Gibt den authentifizierten Benutzer zurück.
/auth/logout
Bearer token
Widerruft das aktuelle Zugriffstoken.
Verschiedenes
/health
Health-Check. Sendet Pings an die Datenbank, den R2-Speicher und den Redis-Cache. Gibt 200 zurück, wenn alles grün ist, sonst 503.
/activity
Live-Aktivitätsstream für den Globus auf der Startseite. Im Edge-Cache von Cloudflare gespeichert.
/bandwidth/status
60/min
Aktuelle Upload-Kontingentnutzung für den Aufrufer — wird von der CLI und der Desktop-App genutzt, um die verbleibende Kapazität anzuzeigen. Das Antwortformat unterscheidet sich für authentifizierte Nutzer. Trotz des URL-Namens werden hier nur Upload Bytes erfasst; Downloads werden nicht mitgezählt.
/app-analytics
120/min
Sende ein Nutzungsereignis über die CLI oder die Desktop-App.
Request-Body
| Feld | Typ | Beschreibung |
|---|---|---|
app | string · required | desktop, cli oder web. |
version | string · optional | Client-Version. |
event | string · required | Ereignisname, z. B. upload_complete. |
context | object · optional | Zusätzliche Metadaten. |
/app-errors
60/min
Sende einen Fehlerbericht über die CLI oder die Desktop-App. Serverseitig dedupliziert — max. 10 vom gleichen Fehler pro Stunde.
Request-Body
| Feld | Typ | Beschreibung |
|---|---|---|
app | string · required | desktop, cli oder web. |
type | string · required | Fehlerklasse/-typ. |
message | string · required | Fehlermeldung. |
stack | string · optional | Stacktrace. |
version, os, os_version, arch, context | various · optional | Diagnose-Metadaten. |