REST API

Upload bestanden, maak collecties en beheer shares via HTTP. Alle antwoorden zijn JSON; voor anonieme uploads is geen API-sleutel vereist.

Introductie

De storage.to API vormt de basis voor onze CLI, desktopapp, web-uploader en elke third-party client die je wilt bouwen.

Het uploadproces bestaat uit drie stappen:

  1. Init — laat ons weten dat je een bestand wilt uploaden. We retourneren één of meer presigned URL's die naar Cloudflare R2 wijzen.
  2. Upload naar R2 — :stuur je bytes direct naar de presigned URL(s). Bytes gaan niet via onze servers.
  3. Bevestigen — laat ons weten dat de upload klaar is. We maken een File-record en geven je een deelbare URL.

Basis-URL

https://storage.to/api

Alle endpoints hieronder zijn relatief aan deze basis. Voorbeeld: POST /upload/init betekent POST https://storage.to/api/upload/init.

Authenticatie

De meeste endpoints vereisen geen authenticatie. Anonieme uploads zijn een kernfunctie.

Authenticatie is optioneel en ontgrendelt:

  • Uploads gekoppeld aan je account (zichtbaar op /dashboard)
  • Premiumfuncties (permanente bestanden, meer opslag)
  • Mutaties op basis van eigendom (verwijderen, wachtwoord instellen, vervaldatum wijzigen) zonder dat je de visitor-token match nodig hebt

We gebruiken Laravel Sanctum bearer tokens. Vraag een token aan via de desktop OAuth-overdracht of via de web-login en stuur het vervolgens als:

Authorization: Bearer <token>

Bezoekerstoken

Anonieme clients hebben een manier nodig om eigendom van hun eigen uploads te bewijzen zonder een account. We gebruiken een visitor token — een willekeurige string die de client één keer genereert en daarna hergebruikt. Stuur het mee met elke request:

X-Visitor-Token: <random-string>

Op het web wordt de token automatisch opgeslagen in de visitor_token-cookie. De CLI slaat deze op op ~/.config/storageto/token (zie CLI-documentatie).

Voor mutatie-endpoints (verwijderen, wachtwoord instellen, vervaldatum wijzigen) wordt eigendom bevestigd als of de bezoeker-token overeenkomt met of het verzoek afkomstig is van hetzelfde IP dat het bestand heeft aangemaakt. Beide kunnen verloren gaan (cookies gewist, netwerkwijzigingen). De owner-token is het voorkeursbewijs voor de toekomst.

Eigenaars-token

Elk endpoint dat een resource aanmaakt (/upload/init multipart, /upload/confirm, /upload/reserve, /collection) retourneert een owner_token in zijn antwoord. De token is een ondertekend bewijs van eigendom dat gekoppeld is aan die specifieke resource, onafhankelijk van je IP of bezoeker-token.

Bewaar de token samen met de resource-ID en stuur deze bij elke mutatie als:

Authorization: Owner <token>

Of, als je al Authorization: Bearer gebruikt voor een geauthenticeerde sessie, stuur het dan als:

X-Owner-Token: <token>

De server accepteert de owner-token als geldig bewijs van eigendom naast de legacy visitor token + IP-fallback — clients die de token hebben blijven werken na het wisselen van netwerk of het wissen van cookies, en clients die de token niet hebben werken nog steeds precies zoals voorheen.

Tokens blijven bestaan zolang de resource bestaat, zijn veilig om op te slaan en verlopen niet onafhankelijk. Een verloren token betekent dat je de controle over die resource verliest (bestand/collectie/upload) — behandel ze als lokale wachtwoorden.

Fouten

Fouten volgen een consistent patroon:

{
  "success": false,
  "error": "Human-readable message"
}

Veelvoorkomende HTTP-statuscodes:

CodeBetekenis
200OK.
201Aangemaakt.
400Slecht verzoek (bijv. limiet voor collectiegrootte overschreden).
401Wachtwoord vereist of onjuist.
403Niet geautoriseerd (niet de eigenaar van de resource).
404Resource niet gevonden of verlopen.
422Validatie mislukt, of beperking door abonnement/quota.
429Snelheidslimiet bereikt of uploadquota overschreden.
500Serverfout. Controleer status.

Snelheidslimieten

Alle snelheidslimieten zijn per IP. Een 429-antwoord bevat de standaard Retry-After-, X-RateLimit-Limit- en X-RateLimit-Remaining-headers.

BereikLimiet
Upload initialiseren / bevestigen / afbreken60 / minuut
Multipart voltooiing500 / minuut
Multipart part-URL's120 / minuut
Batch initialiseren / bevestigen500 / minuut
Status-polls (bestand & collectie)120 / minuut
Instellingen (wachtwoord, vervaldatum, max-downloads)30 / minuut
Wachtwoordverificatie10 / minuut
Collectie aanmaken30 / minuut
Beheren (klaarzetten, verwijderen)60 / minuut
Thumbnail uploaden120 / minuut
ShareX uploaden20 / dag
App-analytics / fouten120 en 60 / minuut

Uploadquota: anonieme clients hebben twee limieten die parallel lopen — 100 GB / 24 u per visitor token en 500 GB / 24 u per IP (de IP-limiet vangt verkeer zonder token en gedeelde netwerken). Als één van beide wordt overschreden, krijg je een 429 met details. Dit is alleen een upload quotum — downloads zijn onbeperkt en niet vertraagd (geleverd direct via R2-gesigneerde URL's).

Upload

De uploadflow in drie stappen voor elk bestand, inclusief bestanden groter dan 5 GB (automatisch multipart). Als je alleen een snelle upload in screenshot-stijl nodig hebt, kijk dan in plaats daarvan naar ShareX.

POST /upload/init 60/min

Start een upload. Voor bestanden >50 MB is het antwoord een multipart-upload (type: "multipart"-veld); anders een enkele presigned PUT.

Request body

VeldTypeBeschrijving
filenamestring · requiredOriginele bestandsnaam. Maximaal 255 tekens.
content_typestring · requiredMIME-type.
sizeinteger · requiredBestandsgrootte in bytes. Minimaal 1.
Request
curl -X POST https://storage.to/api/upload/init \ -H "Content-Type: application/json" \ -H "X-Visitor-Token: abc123" \ -d '{ "filename": "report.pdf", "content_type": "application/pdf", "size": 2202009 }'
Response · single upload
{ "success": true, "type": "single", "upload_url": "https://r2.cloudflarestorage.com/...signed...", "headers": { "Host": ["..."] }, "r2_key": "uuid-abc123" }
Response · multipart
{ "success": true, "type": "multipart", "upload_id": "01HXYZ...", "r2_key": "uuid-abc123", "part_size": 33554432, "total_parts": 4, "initial_urls": { "1": "https://...", "2": "https://..." }, "owner_token": "owner_v1_..." }
POST /upload/parts Owner only 120/min

Vraag extra URL's op voor een multipart-upload die nog bezig is. Wordt gebruikt wanneer /init minder URL's teruggeeft dan je hebt (of wanneer ze zijn verlopen).

Request body

VeldTypeBeschrijving
upload_idstring · requiredDe upload_id uit /init.
part_numbersarray<int> · requiredPartijnummers waarvoor je URL's wilt ophalen.
Request
curl -X POST https://storage.to/api/upload/parts \ -H "Content-Type: application/json" \ -d '{ "upload_id": "01HXYZ...", "part_numbers": [3, 4] }'
Response
{ "success": true, "part_urls": [ { "partNumber": 3, "url": "https://..." }, { "partNumber": 4, "url": "https://..." } ] }
POST /upload/complete-multipart Owner only 500/min

Rond een multipart-upload op R2 af zodra alle delen zijn geüpload.

Request body

VeldTypeBeschrijving
upload_idstring · requiredDe upload_id uit /init.
partsarray · requiredElke entry: { partNumber, etag } uit de R2-respons.
Request
curl -X POST https://storage.to/api/upload/complete-multipart \ -H "Content-Type: application/json" \ -d '{ "upload_id": "01HXYZ...", "parts": [ { "partNumber": 1, "etag": "\"abc...\"" }, { "partNumber": 2, "etag": "\"def...\"" } ] }'
Response
{ "success": true }
POST /upload/abort Owner only 60/min

Annuleer een multipart-upload en ruim eventuele gedeeltelijke data op op R2.

Request body

VeldTypeBeschrijving
upload_idstring · requiredDe upload die moet worden afgebroken.
Request
curl -X POST https://storage.to/api/upload/abort \ -H "Content-Type: application/json" \ -d '{ "upload_id": "01HXYZ..." }'
POST /upload/confirm 60/min

Bevestig dat de upload is voltooid. Dit is wanneer we het File-record aanmaken en de deelbare URL teruggeven.

Request body

VeldTypeBeschrijving
filenamestring · requiredOriginele bestandsnaam.
sizeinteger · requiredBestandsgrootte in bytes.
content_typestring · requiredMIME-type.
r2_keystring · requiredDe r2_key uit /init.
collection_idstring · optionalKoppel aan een collectie.
crc32integer · optionalCRC32-checksum voor integriteitscontrole.
file_idstring(9) · optionalVoldoe een eerder gereserveerd file-ID.
Request
curl -X POST https://storage.to/api/upload/confirm \ -H "Content-Type: application/json" \ -H "X-Visitor-Token: abc123" \ -d '{ "filename": "report.pdf", "size": 2202009, "content_type": "application/pdf", "r2_key": "uuid-abc123" }'
Response
{ "success": true, "file": { "id": "FQxyz1234", "url": "https://storage.to/FQxyz1234", "raw_url": "https://storage.to/r/FQxyz1234", "filename": "report.pdf", "size": 2202009, "human_size": "2.1 MB", "expires_at": "2026-04-15T12:00:00Z" }, "owner_token": "owner_v1_..." }
POST /file/reserve 60/min

Reserveer een file-ID en deelbare URL voor de bytes klaar zijn. Handig wanneer je eerst een link wilt doorgeven en de upload daarna wilt afronden. Eigendom is gekoppeld aan je visitor-token + IP. Rond de upload later af met /upload/init + /upload/confirm en geef file_id door om te bevestigen.

Request body

VeldTypeBeschrijving
filenamestring · optionalPlaceholder-bestandsnaam. Standaard: "Pending".
content_typestring · optionalPlaceholder MIME-type.
Request
curl -X POST https://storage.to/api/file/reserve \ -H "X-Visitor-Token: abc123"
Response
{ "success": true, "file": { "id": "FQxyz1234", "url": "https://storage.to/FQxyz1234", "raw_url": "https://storage.to/r/FQxyz1234", "expires_at": "2026-04-12T18:00:00Z" }, "owner_token": "owner_v1_..." }
POST /upload/init-batch 500/min

Batch-equivalent van /upload/init, geoptimaliseerd voor de web-uploader. Start tot 250 bestanden in één round-trip.

Wordt intern gebruikt door de web-uploader. De meeste clients moeten de voorkeur geven aan single-file /upload/init.

POST /upload/confirm-batch 500/min

Batch-equivalent van /upload/confirm. Bevestigt veel bestanden in één round-trip.

Collecties

Een collectie groepeert meerdere bestanden onder één deelbare URL (/c/{id}). Tot 10.000 bestanden en 25 GB totaal.

POST /collection 30/min

Maak een nieuwe collectie. Koppel bestanden achteraf door collection_id door te geven op /upload/confirm.

Request body

VeldTypeBeschrijving
expected_file_countinteger · optionalTip voor automatisch markeren van de collectie als klaar zodra alle verwachte bestanden zijn bevestigd.
Request
curl -X POST https://storage.to/api/collection \ -H "Content-Type: application/json" \ -H "X-Visitor-Token: abc123" \ -d '{ "expected_file_count": 3 }'
Response
{ "success": true, "collection": { "id": "ABC123xyz", "url": "https://storage.to/c/ABC123xyz", "expires_at": "2026-04-15T12:00:00Z" }, "owner_token": "owner_v1_..." }
GET /collection/{id}/status 120/min

Controleer de status van een collectie. Markeert de collectie ook automatisch als klaar als alle verwachte bestanden zijn bevestigd.

Request
curl https://storage.to/api/collection/ABC123xyz/status
Response
{ "success": true, "files": [ /* file objects: id, url, filename, size, ... */ ], "is_uploading": false, "file_count": 3, "expected_file_count": 3, "total_size": 6291456, "human_total_size": "6 MB" }
POST /collection/{id}/ready Owner only 60/min

Markeer de collectie als klaar om te downloaden. Meestal niet nodig — collecties worden automatisch klaar zodra expected_file_count is bereikt.

DELETE /collection/{id} Owner only 60/min

Verwijder een collectie en al haar bestanden.

POST /collection/{id}/password Owner only 30/min

Stel een wachtwoord in voor de collectie. Vereist 4–100 tekens.

Request body

VeldTypeBeschrijving
passwordstring · required4–100 tekens.
Request
curl -X POST https://storage.to/api/collection/ABC123xyz/password \ -H "X-Visitor-Token: abc123" \ -d '{ "password": "hunter22" }'
DELETE /collection/{id}/password Owner only 30/min

Verwijder het wachtwoord uit een collectie.

POST /collection/{id}/verify-password 10/min

Controleer een wachtwoord. Geeft 200 terug bij succes, 401 bij een onjuist wachtwoord.

Request body

VeldTypeBeschrijving
passwordstring · required
POST /collection/{id}/expiry Owner only 30/min

Wijzig de vervaldatum van een collectie.

Request body

VeldTypeBeschrijving
daysinteger · optional1–7 dagen vanaf nu. Laat weg of gebruik null voor permanent (alleen premium).
POST /collection/{id}/max-downloads Owner only 30/min

Stel een downloadlimiet in (burn-after-N-downloads). De collectie wordt automatisch verwijderd zodra de limiet is bereikt.

Request body

VeldTypeBeschrijving
max_downloadsinteger · optional1–1000. Moet hoger zijn dan het huidige aantal downloads. null om de limiet te verwijderen.

Bestanden

Alle instellingen op bestandsniveau (wachtwoord, vervaldatum, max-downloads) spiegelen de collectie-endpoints. Alleen voor de eigenaar.

GET /file/{id}/status 120/min

Controleer of een bestand nog wacht op de upload.

Response
{ "pending": false }
DELETE /file/{id} Owner only 60/min

Verwijder een bestand direct.

POST /file/{id}/thumbnail Owner only 120/min

Upload een thumbnail-afbeelding voor een video- of afbeeldingsbestand (wordt gebruikt op de downloadpagina). Max 2 MB.

Request body

VeldTypeBeschrijving
thumbnailimage · requiredMultipart-upload. Max 2 MB.
Response
{ "success": true, "thumbnail_url": "https://..." }
POST /file/{id}/password Owner only 30/min

Stel een wachtwoord in voor een bestand. Vereist 4–100 tekens.

DELETE /file/{id}/password Owner only 30/min

Verwijder het wachtwoord van een bestand.

POST /file/{id}/verify-password 10/min

Controleer het wachtwoord van een bestand.

POST /file/{id}/expiry Owner only 30/min

Wijzig de vervaldatum van een bestand.

Request body

VeldTypeBeschrijving
daysinteger · optional1–7 dagen vanaf nu. Laat weg of gebruik null voor permanent (alleen premium).
POST /file/{id}/max-downloads Owner only 30/min

Beperk het totale aantal downloads van een bestand. Wordt automatisch verwijderd zodra de limiet is bereikt.

ShareX uploaden

One-shot upload-endpoint — stuur een multipart-bestand en ontvang een deelbare URL terug. Geen init/confirm-dans. Ideaal voor screenshot-tools. Volledige setup-gids op /nl/docs/sharex.

POST /sharex/upload 20/day

Upload een afbeelding of bestand direct (multipart-formulier, file-veld). Max 25 MB.

Request
curl -X POST https://storage.to/api/sharex/upload \ -F "[email protected]"
Response
{ "success": true, "url": "https://storage.to/FQxyz1234", "raw_url": "https://storage.to/r/FQxyz1234", "filename": "screenshot.png", "expires_at": "2026-04-15T12:00:00Z" }

Desktop-authenticatie

Voor geauthenticeerde clients (bijv. de desktopapp) met een Sanctum-token.

GET /user Bearer token

Geef de geauthenticeerde gebruiker terug.

Request
curl https://storage.to/api/user \ -H "Authorization: Bearer <token>"
Response
{ "id": 42, "name": "Ada", "email": "[email protected]", "is_premium": true }
POST /auth/logout Bearer token

Intrek het huidige toegangstoken.

Overig

GET /health

Health check. Stuurt een ping naar de database, R2-opslag en de Redis-cache. Geeft 200 terug als alles groen is, anders 503.

Response
{ "status": "healthy", "checks": { "database": "ok", "storage": "ok", "cache": "ok" }, "timestamp": "2026-04-12T12:00:00Z" }
GET /activity

Live activiteitenstream voor de homepageglobe. Gecachet op de Cloudflare-edge.

GET /bandwidth/status 60/min

Huidig quotumverbruik voor uploads van de aanroeper — gebruikt door de CLI en desktopapp om de resterende capaciteit te tonen. De responsevorm verschilt voor geauthenticeerde gebruikers. Ondanks de naam van de URL volgt dit alleen upload bytes; downloads worden niet meegerekend.

Response · anonymous
{ "success": true, "authenticated": false, "has_token": true, "limit_bytes": 107374182400, "limit_gb": 100, "used_bytes": 12345678, "used_gb": 0.01, "remaining_bytes": 107361836722, "remaining_gb": 99.99, "window_hours": 24 }
Response · authenticated
{ "success": true, "authenticated": true, "plan": "premium" }
POST /app-analytics 120/min

Verstuur een gebruiksgebeurtenis vanuit de CLI of desktopapp.

Request body

VeldTypeBeschrijving
appstring · requireddesktop, cli of web.
versionstring · optionalClientversie.
eventstring · requiredGebeurtenisnaam, bijvoorbeeld upload_complete.
contextobject · optionalExtra metadata.
POST /app-errors 60/min

Verstuur een foutrapport vanuit de CLI of desktopapp. Server-side gededupliceerd — maximaal 10 van dezelfde fout per uur.

Request body

VeldTypeBeschrijving
appstring · requireddesktop, cli of web.
typestring · requiredFoutklasse/type.
messagestring · requiredFoutmelding.
stackstring · optionalStack trace.
version, os, os_version, arch, contextvarious · optionalDiagnostische metadata.