REST API

Carica file, crea collezioni e gestisci condivisioni via HTTP. Tutte le risposte sono in JSON; non serve una API key per upload anonimi.

Introduzione

L’API di storage.to alimenta il nostro CLI, app desktop, uploader web e qualsiasi client di terze parti tu voglia creare.

Il flusso di upload è in tre passaggi:

  1. Inizio — dicci che vuoi caricare un file. Ti restituiamo uno o più URL presigned che puntano a Cloudflare R2.
  2. Carica su R2PUT i tuoi byte direttamente agli URL presigned. I byte non passano dai nostri server.
  3. Conferma — dicci che l’upload è terminato. Creiamo un record File e ti forniamo un URL condivisibile.

URL base

https://storage.to/api

Tutti gli endpoint qui sotto sono relativi a questa base. Esempio: POST /upload/init significa POST https://storage.to/api/upload/init.

Autenticazione

La maggior parte degli endpoint non richiede autenticazione. Gli upload anonimi sono una funzionalità fondamentale.

L’autenticazione è opzionale e sblocca:

  • Upload collegati al tuo account (visibili su /dashboard)
  • Funzionalità premium (file permanenti, spazio maggiore)
  • Modifiche basate sulla proprietà (elimina, imposta password, cambia scadenza) senza bisogno di corrispondenza con il visitor-token

Usiamo token bearer Laravel Sanctum. Ottieni un token tramite il passaggio OAuth desktop o il login web, poi invialo come:

Authorization: Bearer <token>

Token visitatore

I client anonimi hanno bisogno di un modo per dimostrare la proprietà dei propri upload senza un account. Usiamo un token visitatore — una stringa casuale che il client genera una volta e riutilizza. Inviala con ogni richiesta:

X-Visitor-Token: <random-string>

Sul web, il token viene salvato automaticamente nel cookie visitor_token. La CLI lo memorizza in ~/.config/storageto/token (vedi Documentazione CLI).

Per gli endpoint di modifica (elimina, imposta password, cambia scadenza), la proprietà è confermata se oppure il token visitatore corrisponde o la richiesta proviene dallo stesso IP che ha creato il file.

Errori

Gli errori seguono una struttura coerente:

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

Codici di stato HTTP comuni:

CodiceSignificato
200OK.
201Creato.
400Richiesta errata (es. superamento limite dimensione collezione).
401Password richiesta o errata.
403Non autorizzato (non proprietario della risorsa).
404Risorsa non trovata o scaduta.
422Validazione fallita, o restrizione piano/quota.
429Limite di velocità o quota upload raggiunta.
500Errore server. Controlla stato.

Limiti di velocità

Tutti i limiti di velocità sono per IP. Una risposta 429 include gli header standard Retry-After, X-RateLimit-Limit e X-RateLimit-Remaining.

AmbitoLimite
Inizializza / conferma / annulla upload60 / minuto
Completamento multipart500 / minuto
URL delle parti multipart120 / minuto
Inizializza / conferma batch500 / minuto
Controlli di stato (file e raccolta)120 / minuto
Impostazioni (password, scadenza, download max)30 / minuto
Verifica password10 / minuto
Crea raccolta30 / minuto
Gestisci (pronto, elimina)60 / minuto
Upload miniatura120 / minuto
Upload ShareX20 / giorno
Analisi app / errori120 e 60 / minuto

Quota upload: I client anonimi hanno due limiti in parallelo — 100 GB / 24 h per token visitatore e 500 GB / 24 h per IP (il limite IP cattura traffico senza token e reti condivise). Se uno dei due è superato riceverai un 429 con dettagli. Questo è solo un limite upload — i download sono illimitati e senza throttling (serviti direttamente da URL firmati R2).

Carica

Il flusso di upload in tre fasi per qualsiasi file, inclusi quelli oltre i 5 GB (automaticamente multipart). Se ti serve solo un upload rapido in stile screenshot, usa invece ShareX.

POST /upload/init 60/min

Avvia un upload. Per file >50 MB la risposta include part_urls per un upload multipart; altrimenti un singolo url.

Corpo della richiesta

CampoTipoDescrizione
filenamestring · requiredNome file originale. Max 255 caratteri.
content_typestring · requiredTipo MIME.
sizeinteger · requiredDimensione file in byte. Min 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

Richiedi URL aggiuntivi per le parti di un upload multipart in corso. Usato quando /init ha restituito meno URL delle parti che hai (o sono scaduti).

Corpo della richiesta

CampoTipoDescrizione
upload_idstring · requiredupload_id da /init.
part_numbersarray<int> · requiredNumeri delle parti per cui ottenere URL.
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

Finalizza un upload multipart su R2 una volta che tutte le parti sono caricate.

Corpo della richiesta

CampoTipoDescrizione
upload_idstring · requiredupload_id da /init.
partsarray · requiredOgni voce: { partNumber, etag } dalla risposta di R2.
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

Annulla un upload multipart e pulisci eventuali dati parziali su R2.

Corpo della richiesta

CampoTipoDescrizione
upload_idstring · requiredL'upload da annullare.
Request
curl -X POST https://storage.to/api/upload/abort \ -H "Content-Type: application/json" \ -d '{ "upload_id": "01HXYZ..." }'
POST /upload/confirm 60/min

Conferma che l'upload è completo. Qui creiamo il record File e restituiamo l'URL condivisibile.

Corpo della richiesta

CampoTipoDescrizione
filenamestring · requiredNome file originale.
sizeinteger · requiredDimensione file in byte.
content_typestring · requiredTipo MIME.
r2_keystring · requiredr2_key da /init.
collection_idstring · optionalAllega a una raccolta.
crc32integer · optionalChecksum CRC32 per verifica integrità.
file_idstring(9) · optionalCompleta un ID file riservato precedentemente riservato.
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

Riserva un ID file e un URL condivisibile prima che i byte siano pronti. Utile quando devi fornire prima un link e completare l’upload dopo. La proprietà è legata al tuo token visitatore + IP. Completa l’upload più tardi con /upload/init + /upload/confirm, passando file_id per confermare.

Corpo della richiesta

CampoTipoDescrizione
filenamestring · optionalNome file segnaposto. Default a "Pending".
content_typestring · optionalTipo MIME segnaposto.
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

Equivalente batch di /upload/init, ottimizzato per l'upload web. Inizia fino a 250 file in un solo giro.

Usato internamente dall'upload web. La maggior parte dei client dovrebbe preferire /upload/init per singolo file.

POST /upload/confirm-batch 500/min

Equivalente batch di /upload/confirm. Conferma molti file in un solo giro.

Collezioni

Una raccolta raggruppa più file sotto un unico URL condivisibile (/c/{id}). Fino a 10.000 file e 25 GB totali.

POST /collection 30/min

Crea una nuova raccolta. Allegare i file successivamente passando collection_id su /upload/confirm.

Corpo della richiesta

CampoTipoDescrizione
expected_file_countinteger · optionalSuggerimento per marcare automaticamente la raccolta come pronta una volta che tutti i file previsti sono stati confermati.
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

Interroga lo stato di una raccolta. Marca automaticamente la raccolta come pronta se tutti i file previsti sono stati confermati.

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

Marca la raccolta come pronta per il download. Di solito non necessario — le raccolte si marcano automaticamente pronte una volta raggiunto expected_file_count.

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

Elimina una raccolta e tutti i suoi file.

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

Imposta una password sulla raccolta. Richiede da 4 a 100 caratteri.

Corpo della richiesta

CampoTipoDescrizione
passwordstring · requiredDa 4 a 100 caratteri.
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

Rimuovi la password da una raccolta.

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

Verifica una password. Restituisce 200 se corretta, 401 se errata.

Corpo della richiesta

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

Modifica la scadenza di una raccolta.

Corpo della richiesta

CampoTipoDescrizione
daysinteger · optionalDa 1 a 7 giorni da ora. Omesso o null per permanente (solo premium).
POST /collection/{id}/max-downloads Owner only 30/min

Imposta un limite di download (elimina dopo N download). La raccolta si auto-elimina al raggiungimento.

Corpo della richiesta

CampoTipoDescrizione
max_downloadsinteger · optionalDa 1 a 1000. Deve superare il conteggio attuale dei download. null per rimuovere il limite.

File

Tutte le impostazioni a livello di file (password, scadenza, max download) rispecchiano quelle della raccolta. Solo proprietario.

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

Verifica se un file è ancora in attesa di upload.

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

Elimina un file immediatamente.

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

Carica un'immagine miniatura per un video o file immagine (usata nella pagina di download). Max 2 MB.

Corpo della richiesta

CampoTipoDescrizione
thumbnailimage · requiredUpload multipart. Max 2 MB.
Response
{ "success": true, "thumbnail_url": "https://..." }
POST /file/{id}/password Owner only 30/min

Imposta una password su un file. Richiede da 4 a 100 caratteri.

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

Rimuovi la password da un file.

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

Verifica la password di un file.

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

Modifica la scadenza di un file.

Corpo della richiesta

CampoTipoDescrizione
daysinteger · optionalDa 1 a 7 giorni da ora. Omesso o null per permanente (solo premium).
POST /file/{id}/max-downloads Owner only 30/min

Limita il totale download di un file. Si auto-elimina al raggiungimento.

Upload ShareX

Endpoint upload one-shot — invia un file multipart, ricevi un URL condivisibile. Niente danza init/confirm. Ideale per strumenti di screenshot. Guida completa all’installazione su /it/docs/sharex.

POST /sharex/upload 20/day

Carica direttamente un'immagine o file (form multipart, campo file). 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" }

Autenticazione desktop

Per client autenticati (es. app desktop) con token Sanctum.

GET /user Bearer token

Restituisce l'utente autenticato.

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

Revoca il token di accesso corrente.

Varie

GET /health

Controllo di integrità. Ping al database, storage R2 e cache Redis. Restituisce 200 se tutto è verde, 503 altrimenti.

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

Stream attività live per il globo della homepage. Cache ai bordi di Cloudflare.

GET /bandwidth/status 60/min

Uso attuale della quota upload per il chiamante — usato da CLI e app desktop per mostrare la capacità residua. La risposta differisce per utenti autenticati. Nonostante il nome URL, traccia solo byte upload; i download non sono conteggiati.

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

Invia un evento di utilizzo da CLI o app desktop.

Corpo della richiesta

CampoTipoDescrizione
appstring · requireddesktop, cli o web.
versionstring · optionalVersione client.
eventstring · requiredNome evento, es. upload_complete.
contextobject · optionalMetadati extra.
POST /app-errors 60/min

Invia un report di errore da CLI o app desktop. Deduplicato lato server — max 10 errori uguali all'ora.

Corpo della richiesta

CampoTipoDescrizione
appstring · requireddesktop, cli o web.
typestring · requiredClasse/tipo di errore.
messagestring · requiredMessaggio di errore.
stackstring · optionalStack trace.
version, os, os_version, arch, contextvarious · optionalMetadati diagnostici.