API REST

Téléversez des fichiers, créez des collections et gérez les partages via HTTP. Toutes les réponses sont en JSON ; aucune clé API n’est requise pour les téléversements anonymes.

Introduction

L’API storage.to alimente notre CLI, application bureau, téléverseur web, ainsi que tout client tiers que vous souhaitez créer.

Le processus de téléversement se fait en trois étapes :

  1. Initialisation — indiquez que vous souhaitez téléverser un fichier. Nous renvoyons une ou plusieurs URL pré-signées pointant vers Cloudflare R2.
  2. Téléversement vers R2PUT vos octets directement aux URL(s) pré-signées. Les octets ne transitent pas par nos serveurs.
  3. Confirmation — indiquez que le téléversement est terminé. Nous créons un enregistrement File et vous fournissons une URL partageable.

URL de base

https://storage.to/api

Tous les points d’accès ci-dessous sont relatifs à cette base. Exemple : POST /upload/init signifie POST https://storage.to/api/upload/init.

Authentification

La plupart des points de terminaison ne nécessitent pas d'authentification. Les téléversements anonymes sont une fonctionnalité clé.

L’authentification est optionnelle et débloque :

  • Téléversements liés à votre compte (visibles dans /dashboard)
  • Fonctionnalités premium (fichiers permanents, stockage plus important)
  • Modifications basées sur la propriété (suppression, définition de mot de passe, changement d’expiration) sans besoin de correspondance du token visiteur

Nous utilisons des tokens bearer Laravel Sanctum. Générez un token via le transfert OAuth du bureau ou la connexion web, puis envoyez-le comme :

Authorization: Bearer <token>

Token visiteur

Les clients anonymes ont besoin d’un moyen de prouver la propriété de leurs téléversements sans compte. Nous utilisons un token visiteur — une chaîne aléatoire que le client génère une fois et réutilise. Envoyez-le à chaque requête :

X-Visitor-Token: <random-string>

Sur le web, le token est automatiquement stocké dans le cookie visitor_token. Le CLI le stocke à ~/.config/storageto/token (voir Docs CLI).

Pour les points d’accès de modification (suppression, définition de mot de passe, changement d’expiration), la propriété est confirmée si soit le token visiteur correspond ou la requête provient de la même IP qui a créé le fichier.

Erreurs

Les erreurs suivent un format cohérent :

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

Codes d’état HTTP courants :

CodeSignification
200OK.
201Créé.
400Mauvaise requête (ex. limite de taille de collection dépassée).
401Mot de passe requis ou incorrect.
403Non autorisé (pas le propriétaire de la ressource).
404Ressource non trouvée ou expirée.
422Échec de validation, ou restriction de forfait/quota.
429Limite de fréquence ou quota de téléversement atteint.
500Erreur serveur. Vérifiez statut.

Limites de débit

Toutes les limites de débit sont par IP. Une réponse 429 inclut les en-têtes standards Retry-After, X-RateLimit-Limit, et X-RateLimit-Remaining.

PortéeLimite
Initialisation / confirmation / annulation du téléchargement60 / minute
Finalisation multipart500 / minute
URLs des parties multipart120 / minute
Initialisation / confirmation du lot500 / minute
Requêtes d’état (fichier & collection)120 / minute
Paramètres (mot de passe, expiration, max de téléchargements)30 / minute
Vérification du mot de passe10 / minute
Création de collection30 / minute
Gestion (prêt, suppression)60 / minute
Upload de vignette120 / minute
Upload ShareX20 / jour
Analyses / erreurs de l’application120 et 60 / minute

Quota d’upload : Les clients anonymes ont deux plafonds en parallèle — 100 Go / 24 h par token visiteur et 500 Go / 24 h par IP (le plafond IP capte le trafic sans token et les réseaux partagés). Lorsqu'un plafond est dépassé, vous recevrez un 429 avec les détails. C'est uniquement un quota upload — les téléchargements sont illimités et sans restriction (servis directement depuis les URL signées R2).

Téléverser

Le processus d’upload en trois étapes pour tout fichier, y compris ceux de plus de 5 Go (multipart automatique). Si vous avez juste besoin d’un upload rapide façon capture d’écran, utilisez plutôt ShareX.

POST /upload/init 60/min

Initiez un upload. Pour les fichiers >50 Mo, la réponse inclut part_urls pour un upload multipart ; sinon une seule url.

Corps de la requête

ChampTypeDescription
filenamestring · requiredNom de fichier original. Max 255 caractères.
content_typestring · requiredType MIME.
sizeinteger · requiredTaille du fichier en octets. 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

Demandez des URLs supplémentaires pour un upload multipart en cours. Utilisé quand /init a retourné moins d’URLs que le nombre de parties (ou qu’elles ont expiré).

Corps de la requête

ChampTypeDescription
upload_idstring · requiredLe upload_id de /init.
part_numbersarray<int> · requiredNuméros des parties pour lesquelles obtenir des URLs.
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

Finalisez un upload multipart sur R2 une fois toutes les parties uploadées.

Corps de la requête

ChampTypeDescription
upload_idstring · requiredLe upload_id de /init.
partsarray · requiredChaque entrée : { partNumber, etag } de la réponse 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

Annulez un upload multipart et nettoyez les données partielles sur R2.

Corps de la requête

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

Confirmez que l’upload est terminé. C’est à ce moment que nous créons l’enregistrement File et retournons l’URL partageable.

Corps de la requête

ChampTypeDescription
filenamestring · requiredNom de fichier original.
sizeinteger · requiredTaille du fichier en octets.
content_typestring · requiredType MIME.
r2_keystring · requiredLe r2_key de /init.
collection_idstring · optionalAttacher à une collection.
crc32integer · optionalChecksum CRC32 pour vérification d’intégrité.
file_idstring(9) · optionalValidez un ID de fichier réservé précédemment réservé.
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

Réservez un ID de fichier et une URL partageable avant que les octets soient prêts. Utile quand vous devez distribuer un lien avant et compléter l’upload ensuite. La propriété est liée à votre token visiteur + IP. Terminez l’upload plus tard avec /upload/init + /upload/confirm, en passant file_id pour confirmer.

Corps de la requête

ChampTypeDescription
filenamestring · optionalNom de fichier par défaut. Par défaut "Pending".
content_typestring · optionalType MIME par défaut.
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

Équivalent batch de /upload/init, optimisé pour l'uploadeur web. Initialise jusqu'à 250 fichiers en un aller-retour.

Utilisé en interne par l'uploadeur web. La plupart des clients devraient préférer /upload/init pour un seul fichier.

POST /upload/confirm-batch 500/min

Équivalent batch de /upload/confirm. Confirme plusieurs fichiers en un aller-retour.

Collections

Une collection regroupe plusieurs fichiers sous une seule URL de partage (/c/{id}). Jusqu'à 10 000 fichiers et 25 Go au total.

POST /collection 30/min

Créez une nouvelle collection. Ajoutez des fichiers ensuite en passant collection_id sur /upload/confirm.

Corps de la requête

ChampTypeDescription
expected_file_countinteger · optionalAstuce pour marquer automatiquement la collection comme prête une fois que tous les fichiers attendus ont été confirmés.
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

Interrogez l'état d'une collection. Marque aussi automatiquement la collection comme prête si tous les fichiers attendus ont été confirmés.

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

Marquer la collection comme prête au téléchargement. Généralement inutile — les collections se marquent prêtes automatiquement une fois que expected_file_count est atteint.

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

Supprimer une collection et tous ses fichiers.

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

Définir un mot de passe sur la collection. Nécessite 4 à 100 caractères.

Corps de la requête

ChampTypeDescription
passwordstring · required4 à 100 caractères.
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

Supprimer le mot de passe d'une collection.

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

Vérifier un mot de passe. Retourne 200 si réussi, 401 si mot de passe incorrect.

Corps de la requête

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

Modifier l'expiration d'une collection.

Corps de la requête

ChampTypeDescription
daysinteger · optionalDe 1 à 7 jours à partir de maintenant. Omettre ou null pour permanent (premium uniquement).
POST /collection/{id}/max-downloads Owner only 30/min

Définir un plafond de téléchargements (auto-destruction après N téléchargements). La collection se supprime automatiquement une fois atteint.

Corps de la requête

ChampTypeDescription
max_downloadsinteger · optionalDe 1 à 1000. Doit dépasser le nombre actuel de téléchargements. null pour supprimer le plafond.

Fichiers

Tous les paramètres au niveau fichier (mot de passe, expiration, max téléchargements) reflètent ceux de la collection. Réservé au propriétaire.

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

Vérifier si un fichier est encore en attente de téléchargement.

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

Supprimer un fichier immédiatement.

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

Télécharger une image miniature pour une vidéo ou un fichier image (utilisée sur la page de téléchargement). Max 2 Mo.

Corps de la requête

ChampTypeDescription
thumbnailimage · requiredTéléversement multipart. Max 2 Mo.
Response
{ "success": true, "thumbnail_url": "https://..." }
POST /file/{id}/password Owner only 30/min

Définir un mot de passe sur un fichier. Nécessite 4 à 100 caractères.

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

Supprimer le mot de passe d'un fichier.

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

Vérifier le mot de passe d'un fichier.

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

Modifier l'expiration d'un fichier.

Corps de la requête

ChampTypeDescription
daysinteger · optionalDe 1 à 7 jours à partir de maintenant. Omettre ou null pour permanent (premium uniquement).
POST /file/{id}/max-downloads Owner only 30/min

Limiter le nombre total de téléchargements d'un fichier. Suppression automatique une fois atteint.

Upload ShareX

Point de terminaison de téléchargement unique — envoyez un fichier multipart, recevez une URL partageable. Pas de danse d'initiation/confirmation. Idéal pour les outils de capture d’écran. Guide complet d’installation sur /fr/docs/sharex.

POST /sharex/upload 20/day

Téléchargez une image ou un fichier directement (formulaire multipart, champ file). Max 25 Mo.

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" }

Authentification bureau

Pour les clients authentifiés (ex. l'application desktop) disposant d'un token Sanctum.

GET /user Bearer token

Retourner l'utilisateur authentifié.

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

Révoquer le token d'accès actuel.

Divers

GET /health

Vérification de santé. Ping la base de données, le stockage R2 et le cache Redis. Retourne 200 si tout est bon, 503 sinon.

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

Flux d'activité en direct pour le globe de la page d'accueil. Mis en cache au niveau de Cloudflare.

GET /bandwidth/status 60/min

Utilisation actuelle du quota d'upload pour l'appelant — utilisé par le CLI et l'application desktop pour afficher la capacité restante. La forme de la réponse diffère pour les utilisateurs authentifiés. Malgré le nom de l'URL, cela suit uniquement les octets upload ; les téléchargements ne sont pas comptés.

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

Soumettre un événement d'utilisation depuis le CLI ou l'application desktop.

Corps de la requête

ChampTypeDescription
appstring · requireddesktop, cli, ou web.
versionstring · optionalVersion du client.
eventstring · requiredNom de l'événement, ex. upload_complete.
contextobject · optionalMétadonnées supplémentaires.
POST /app-errors 60/min

Soumettre un rapport d'erreur depuis le CLI ou l'application desktop. Dédupliqué côté serveur — max 10 erreurs identiques par heure.

Corps de la requête

ChampTypeDescription
appstring · requireddesktop, cli, ou web.
typestring · requiredClasse/type d’erreur.
messagestring · requiredMessage d'erreur.
stackstring · optionalTrace de la pile.
version, os, os_version, arch, contextvarious · optionalMétadonnées diagnostiques.