REST API

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

Introductie

De storage.to API ondersteunt onze CLI, desktop-app, web uploader en elke derde partij client die je wilt bouwen.

De uploadprocedure bestaat uit drie stappen:

  1. Init — geef aan dat je een bestand wilt uploaden. Wij geven één of meerdere vooraf ondertekende URL's terug die naar Cloudflare R2 wijzen.
  2. Upload naar R2PUT je bytes direct naar de presigned URL(s). Bytes gaan niet via onze servers.
  3. Bevestigen — geef aan dat de upload is voltooid. Wij maken een File record aan en geven je een deelbare URL.

Basis-URL

https://storage.to/api

Alle onderstaande endpoints zijn relatief ten opzichte van 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)
  • Premium functies (permanente bestanden, grotere opslag)
  • Mutaties op basis van eigendom (verwijderen, wachtwoord instellen, vervaldatum wijzigen) zonder dat de visitor-token overeenkomt

We gebruiken Laravel Sanctum bearer tokens. Vraag een token aan via de desktop OAuth overdracht of de weblogin, en stuur deze vervolgens als:

Authorization: Bearer <token>

Bezoeker-token

Anonieme clients hebben een manier nodig om eigendom van hun uploads te bewijzen zonder account. We gebruiken een bezoeker-token — een willekeurige tekenreeks die de client één keer genereert en hergebruikt. Stuur deze mee met elk verzoek:

X-Visitor-Token: <random-string>

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

Voor mutatie-endpoints (verwijderen, wachtwoord instellen, vervaldatum wijzigen) wordt eigendom bevestigd als of het bezoeker-token overeenkomt of het verzoek afkomstig is van hetzelfde IP dat het bestand heeft aangemaakt.

Fouten

Fouten volgen een consistent patroon:

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

Veelvoorkomende HTTP-statuscodes:

CodeBetekenis
200OK.
201Aangemaakt.
400Ongeldig verzoek (bijv. limiet voor collectiegrootte overschreden).
401Wachtwoord vereist of onjuist.
403Niet geautoriseerd (geen eigenaar van de bron).
404Bron niet gevonden of verlopen.
422Validatie mislukt, of plan-/quotabeperking.
429Rate limit of uploadquotum bereikt.
500Serverfout. Controleer status.

Snelheidslimieten

Alle snelheidslimieten gelden per IP. Een 429-respons bevat standaard Retry-After, X-RateLimit-Limit en X-RateLimit-Remaining headers.

BereikLimiet
Upload starten / bevestigen / afbreken60 / minuut
Meerdelige voltooiing500 / minuut
URL's van meerdelige onderdelen120 / minuut
Batch starten / bevestigen500 / minuut
Statusopvragingen (bestand & collectie)120 / minuut
Instellingen (wachtwoord, vervaldatum, max downloads)30 / minuut
Wachtwoordverificatie10 / minuut
Collectie aanmaken30 / minuut
Beheren (klaar, verwijderen)60 / minuut
Thumbnail uploaden120 / minuut
ShareX upload20 / dag
App-analyse / fouten120 en 60 / minuut

Uploadquotum: Anonieme clients hebben twee limieten die parallel lopen — 100 GB / 24 uur per bezoeker-token en 500 GB / 24 uur per IP (de IP-limiet vangt verkeer zonder token en gedeelde netwerken op). Wanneer een van beide wordt overschreden, krijg je een 429 met details. Dit is alleen een uploaden quotum — downloads zijn onbeperkt en niet beperkt (worden direct geserveerd vanaf R2 signed URLs).

Uploaden

De drie-stappen uploadflow voor elk bestand, inclusief bestanden groter dan 5 GB (automatisch meerdelig). Als je alleen een snelle screenshot-achtige upload nodig hebt, zie dan ShareX.

POST /upload/init 60/min

Start een upload. Voor bestanden >50 MB bevat de reactie part_urls voor een multipart upload; anders een enkele url.

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, "url": "https://r2.cloudflarestorage.com/...signed...", "r2_key": "uuid-abc123", "upload_id": null, "is_multipart": false }
Response · multipart
{ "success": true, "upload_id": "01HXYZ...", "r2_key": "uuid-abc123", "is_multipart": true, "part_size": 52428800, "part_urls": [ { "partNumber": 1, "url": "https://..." }, { "partNumber": 2, "url": "https://..." } ] }
POST /upload/parts 120/min

Vraag extra onderdeel-URL's aan voor een lopende meerdelige upload. Wordt gebruikt wanneer /init minder URL's teruggaf dan het aantal onderdelen (of ze zijn verlopen).

Request body

VeldTypeBeschrijving
upload_idstring · requiredDe upload_id van /init.
part_numbersarray<int> · requiredOnderdelennummers waarvoor URL's worden opgevraagd.
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 500/min

Rond een meerdelige upload op R2 af zodra alle onderdelen zijn geüpload.

Request body

VeldTypeBeschrijving
upload_idstring · requiredDe upload_id van /init.
partsarray · requiredElke invoer: { 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 60/min

Annuleer een meerdelige upload en ruim eventuele gedeeltelijke data op R2 op.

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 voltooid is. 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 van /init.
collection_idstring · optionalKoppelen aan een collectie.
crc32integer · optionalCRC32-checksum voor integriteitscontrole.
file_idstring(9) · optionalVervul een eerder gereserveerd bestand-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" } }
POST /file/reserve 60/min

Reserveer een bestand-ID en deelbare URL voor de bytes klaar zijn. Handig als je eerst een link wilt delen en de upload later wilt voltooien. Eigendom is gekoppeld aan je bezoekerstoken + IP. Maak de upload later af met /upload/init + /upload/confirm, waarbij je file_id doorgeeft ter bevestiging.

Request body

VeldTypeBeschrijving
filenamestring · optionalTijdelijke bestandsnaam. Standaard "Pending".
content_typestring · optionalTijdelijk 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" } }
POST /upload/init-batch 500/min

Batch-equivalent van /upload/init, geoptimaliseerd voor de web uploader. Initieert tot 250 bestanden in één enkele ronde.

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

POST /upload/confirm-batch 500/min

Batch-equivalent van /upload/confirm. Bevestigt meerdere bestanden in één enkele ronde.

Collecties

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

POST /collection 30/min

Maak een nieuwe collectie aan. Voeg daarna bestanden toe door collection_id te gebruiken op /upload/confirm.

Request body

VeldTypeBeschrijving
expected_file_countinteger · optionalHint om de collectie automatisch als klaar te markeren zodra alle verwachte bestanden bevestigd zijn.
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" } }
GET /collection/{id}/status 120/min

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

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 voor download. 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 zijn 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 van een collectie.

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

Controleer een wachtwoord. Geeft 200 bij succes, 401 bij 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. Weglaten of null voor permanent (alleen premium).
POST /collection/{id}/max-downloads Owner only 30/min

Stel een downloadlimiet in (verwijder na N downloads). Collectie wordt automatisch verwijderd wanneer 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 eigenaar.

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

Controleer of een bestand nog wacht op 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 miniatuurafbeelding voor een video- of afbeeldingsbestand (gebruikt op de downloadpagina). Maximaal 2 MB.

Request body

VeldTypeBeschrijving
thumbnailimage · requiredMultipart upload. Maximaal 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

Verifieer 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. Weglaten of null voor permanent (alleen premium).
POST /file/{id}/max-downloads Owner only 30/min

Beperk het totaal aantal downloads van een bestand. Verwijdert automatisch wanneer bereikt.

ShareX upload

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

POST /sharex/upload 20/day

Upload direct een afbeelding of bestand (multipart form, file veld). Maximaal 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 desktop app) 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.

Diversen

GET /health

Health check. Pingt de database, R2 opslag en Redis cache. Geeft 200 als alles in orde is, anders 503.

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

Live activiteitenstroom voor de homepage globe. Gecached aan de Cloudflare edge.

GET /bandwidth/status 60/min

Huidig uploadquotum gebruik voor de aanroeper — gebruikt door de CLI en desktop app om resterende capaciteit te tonen. Responsvorm verschilt voor geauthenticeerde gebruikers. Ondanks de URL-naam wordt hier alleen uploaden bytes geteld; downloads worden niet meegeteld.

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

Dien een gebruiksgebeurtenis in vanuit de CLI of desktop app.

Request body

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

Dien een foutmelding in vanuit de CLI of desktop app. Server-side gededupliceerd — max 10 dezelfde fouten 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.