REST API
Sube archivos, crea colecciones y gestiona compartidos mediante HTTP. Todas las respuestas son JSON; no se requiere una clave de API para subidas anónimas.
Introducción
La API de storage.to impulsa nuestro CLI, app de escritorio, cargador web y cualquier cliente de terceros que quieras crear.
El flujo de subida tiene tres pasos:
- Iniciar — dinos que quieres subir un archivo. Te devolvemos una o más URL prefirmadas que apuntan a Cloudflare R2.
- Subir a R2 —
PUTtus bytes directamente a las URL(s) prefirmadas. Los bytes no pasan por nuestros servidores. - Confirmar — avísanos cuando la subida haya terminado. Creamos un registro de
Filey te damos una URL compartible.
URL base
https://storage.to/api
Todos los endpoints de abajo son relativos a esta base. Ejemplo: POST /upload/init significa POST https://storage.to/api/upload/init.
Autenticación
La mayoría de los endpoints no requieren autenticación. Las subidas anónimas son una función clave.
La autenticación es opcional y desbloquea:
- Subidas vinculadas a tu cuenta (visibles en /dashboard)
- Funciones premium (archivos permanentes, más almacenamiento)
- Mutaciones basadas en la propiedad (eliminar, establecer contraseña, cambiar caducidad) sin necesidad de que coincida el visitor-token
Usamos tokens bearer de Laravel Sanctum. Emite un token mediante el traspaso OAuth del escritorio o el inicio de sesión web, y luego envíalo como:
Authorization: Bearer <token>
Token de visitante
Los clientes anónimos necesitan una forma de demostrar la propiedad de sus propias subidas sin tener una cuenta. Usamos un visitor token: una cadena aleatoria que el cliente genera una vez y reutiliza. Envíala con cada solicitud:
X-Visitor-Token: <random-string>
En la web, el token se guarda automáticamente en la cookie visitor_token. La CLI lo guarda en ~/.config/storageto/token (ver Documentación de la CLI).
Para los endpoints de mutación (borrar, establecer contraseña, cambiar la caducidad), la propiedad se confirma si o el token del visitante coincide o la solicitud proviene de la misma IP que creó el archivo. Ambas cosas pueden perderse (cookies borradas, cambios de red). El token del propietario es la prueba preferida a partir de ahora.
Token de propietario
Cada endpoint que crea recursos (/upload/init multipart, /upload/confirm, /upload/reserve, /collection) devuelve un owner_token en su respuesta. El token es una prueba firmada de propiedad vinculada a ese recurso específico, independiente de tu IP o del token del visitante.
Guarda el token junto con el ID del recurso y envíalo en cualquier mutación como:
Authorization: Owner <token>
O, si ya estás usando Authorization: Bearer para una sesión autenticada, envíalo como:
X-Owner-Token: <token>
El servidor acepta el token del propietario como prueba válida de propiedad junto con el respaldo heredado visitor token + IP: los clientes que tienen el token siguen funcionando después de cambiar de red o borrar cookies, y los clientes que no lo tienen siguen funcionando exactamente como antes.
Los tokens viven mientras lo haga el recurso, son seguros para persistir y no caducan de forma independiente. Perder un token significa perder el control de ese recurso (archivo/colección/subida): trátalos como contraseñas locales.
Errores
Los errores siguen una estructura consistente:
{
"success": false,
"error": "Human-readable message"
}
Códigos de estado HTTP comunes:
| Código | Significado |
|---|---|
200 | Correcto. |
201 | Creado. |
400 | Solicitud incorrecta (p. ej., se superó el límite de tamaño de la colección). |
401 | Se requiere contraseña o es incorrecta. |
403 | No autorizado (no eres el propietario del recurso). |
404 | Recurso no encontrado o caducado. |
422 | Falló la validación o hay una restricción de plan/cuota. |
429 | Se alcanzó el límite de velocidad o la cuota de subida. |
500 | Error del servidor. Revisa estado. |
Límites de velocidad
Todos los límites de velocidad son por IP. Una respuesta 429 incluye los encabezados estándar Retry-After, X-RateLimit-Limit y X-RateLimit-Remaining.
| Ámbito | Límite |
|---|---|
| Inicio / confirmación / cancelación de subida | 60 / minuto |
| Finalización multipart | 500 / minuto |
| URLs de las partes multipart | 120 / minuto |
| Inicio / confirmación en lote | 500 / minuto |
| Consultas de estado (archivo y colección) | 120 / minuto |
| Ajustes (contraseña, caducidad, descargas máximas) | 30 / minuto |
| Verificación de contraseña | 10 / minuto |
| Creación de colección | 30 / minuto |
| Gestionar (listo, borrar) | 60 / minuto |
| Subida de miniatura | 120 / minuto |
| Subida con ShareX | 20 / día |
| Analítica de la app / errores | 120 y 60 / minuto |
Cuota de subida: los clientes anónimos tienen dos límites en paralelo: 100 GB / 24 h por visitor token e 500 GB / 24 h por IP (el límite de IP detecta el tráfico sin token y redes compartidas). Cuando se supera cualquiera, recibirás un 429 con detalles. Esto es solo una subida cuota: las descargas son ilimitadas y sin limitación (se sirven directamente desde URL(s) firmadas de R2).
Subir
El flujo de subida en tres pasos para cualquier archivo, incluidos los de más de 5 GB (multipart automáticamente). Si solo necesitas una subida rápida tipo captura de pantalla, mira ShareX.
/upload/init
60/min
Inicia una subida. Para archivos >50 MB, la respuesta es una subida multipart (campo type: "multipart"); de lo contrario, un único PUT prefirmado.
Cuerpo de la solicitud
| Campo | Tipo | Descripción |
|---|---|---|
filename | string · required | Nombre de archivo original. Máx. 255 caracteres. |
content_type | string · required | Tipo MIME. |
size | integer · required | Tamaño del archivo en bytes. Mín. 1. |
/upload/parts
Owner only
120/min
Solicita URLs adicionales de partes para una carga multipart en progreso. Se usa cuando /init devolvió menos URLs de las que tienes partes (o cuando expiraron).
Cuerpo de la solicitud
| Campo | Tipo | Descripción |
|---|---|---|
upload_id | string · required | El upload_id de /init. |
part_numbers | array<int> · required | Números de partes para los que obtener URLs. |
/upload/complete-multipart
Owner only
500/min
Finaliza una carga multipart en R2 una vez que todas las partes estén subidas.
Cuerpo de la solicitud
| Campo | Tipo | Descripción |
|---|---|---|
upload_id | string · required | El upload_id de /init. |
parts | array · required | Cada entrada: { partNumber, etag } de la respuesta de R2. |
/upload/abort
Owner only
60/min
Cancela una carga multipart y limpia cualquier dato parcial en R2.
Cuerpo de la solicitud
| Campo | Tipo | Descripción |
|---|---|---|
upload_id | string · required | La carga que se debe cancelar. |
/upload/confirm
60/min
Confirma que la carga está completa. Es cuando creamos el registro File y devolvemos la URL compartible.
Cuerpo de la solicitud
| Campo | Tipo | Descripción |
|---|---|---|
filename | string · required | Nombre de archivo original. |
size | integer · required | Tamaño del archivo en bytes. |
content_type | string · required | Tipo MIME. |
r2_key | string · required | El r2_key de /init. |
collection_id | string · optional | Adjuntar a una colección. |
crc32 | integer · optional | Suma de verificación CRC32 para la verificación de integridad. |
file_id | string(9) · optional | Completa un ID de archivo previamente reservado. |
/file/reserve
60/min
Reserva un ID de archivo y una URL compartible antes de que los bytes estén listos. Útil cuando necesitas entregar un enlace primero y completar la carga después. La propiedad está vinculada a tu token de visitante + IP. Termina la carga más tarde con /upload/init + /upload/confirm, pasando file_id para confirmar.
Cuerpo de la solicitud
| Campo | Tipo | Descripción |
|---|---|---|
filename | string · optional | Nombre de archivo de ejemplo. Por defecto es "Pending". |
content_type | string · optional | Tipo MIME de ejemplo. |
/upload/init-batch
500/min
Equivalente en lote de /upload/init, optimizado para el cargador web. Inicia hasta 250 archivos en un solo viaje.
Usado internamente por el cargador web. La mayoría de los clientes deberían preferir /upload/init para un solo archivo.
/upload/confirm-batch
500/min
Equivalente en lote de /upload/confirm. Confirma muchos archivos en un solo viaje.
Colecciones
Una colección agrupa varios archivos bajo una única URL de compartición (/c/{id}). Hasta 10.000 archivos y 25 GB en total.
/collection
30/min
Crea una nueva colección. Adjunta archivos después pasando collection_id en /upload/confirm.
Cuerpo de la solicitud
| Campo | Tipo | Descripción |
|---|---|---|
expected_file_count | integer · optional | Pista para marcar automáticamente la colección como lista una vez que todos los archivos esperados hayan confirmado. |
/collection/{id}/status
120/min
Consulta el estado de una colección. También la marca automáticamente como lista si todos los archivos esperados han confirmado.
/collection/{id}/ready
Owner only
60/min
Marca la colección como lista para descargar. Normalmente no hace falta: las colecciones se ponen listas automáticamente cuando se alcanza expected_file_count.
/collection/{id}
Owner only
60/min
Elimina una colección y todos sus archivos.
/collection/{id}/password
Owner only
30/min
Establece una contraseña en la colección. Requiere 4–100 caracteres.
Cuerpo de la solicitud
| Campo | Tipo | Descripción |
|---|---|---|
password | string · required | 4–100 caracteres. |
/collection/{id}/password
Owner only
30/min
Quita la contraseña de una colección.
/collection/{id}/verify-password
10/min
Comprueba una contraseña. Devuelve 200 si es correcta y 401 si es incorrecta.
Cuerpo de la solicitud
| Campo | Tipo | Descripción |
|---|---|---|
password | string · required |
/collection/{id}/expiry
Owner only
30/min
Cambia la caducidad de una colección.
Cuerpo de la solicitud
| Campo | Tipo | Descripción |
|---|---|---|
days | integer · optional | Entre 1 y 7 días a partir de ahora. Omite o null para que sea permanente (solo premium). |
/collection/{id}/max-downloads
Owner only
30/min
Establece un límite de descargas (burn-after-N-downloads). La colección se elimina automáticamente cuando se alcanza.
Cuerpo de la solicitud
| Campo | Tipo | Descripción |
|---|---|---|
max_downloads | integer · optional | 1–1000. Debe superar el número actual de descargas. null para quitar el límite. |
Archivos
Todas las configuraciones a nivel de archivo (contraseña, caducidad, max-downloads) reflejan los endpoints de la colección. Solo el propietario.
/file/{id}/status
120/min
Comprueba si un archivo aún está pendiente de su carga.
/file/{id}
Owner only
60/min
Elimina un archivo inmediatamente.
/file/{id}/thumbnail
Owner only
120/min
Sube una imagen de miniatura para un archivo de video o imagen (se usa en la página de descarga). Máx. 2 MB.
Cuerpo de la solicitud
| Campo | Tipo | Descripción |
|---|---|---|
thumbnail | image · required | Carga multipart. Máx. 2 MB. |
/file/{id}/password
Owner only
30/min
Establece una contraseña en un archivo. Requiere 4–100 caracteres.
/file/{id}/password
Owner only
30/min
Quita la contraseña de un archivo.
/file/{id}/verify-password
10/min
Verifica la contraseña de un archivo.
/file/{id}/expiry
Owner only
30/min
Cambia la caducidad de un archivo.
Cuerpo de la solicitud
| Campo | Tipo | Descripción |
|---|---|---|
days | integer · optional | Entre 1 y 7 días a partir de ahora. Omite o null para que sea permanente (solo premium). |
/file/{id}/max-downloads
Owner only
30/min
Limita el número total de descargas de un archivo. Se elimina automáticamente cuando se alcanza el límite.
Subida con ShareX
Endpoint de carga de una sola vez: envía un archivo multipart y recibe una URL compartible. Sin el baile de init/confirm. Ideal para herramientas de capturas de pantalla. Guía completa de configuración en /es/docs/sharex.
Autenticación de escritorio
Para clientes autenticados (por ejemplo, la app de escritorio) que tengan un token de Sanctum.
/user
Bearer token
Devuelve el usuario autenticado.
/auth/logout
Bearer token
Revoca el token de acceso actual.
Varios
/health
Comprobación de estado. Envía un ping a la base de datos, al almacenamiento R2 y a la caché de Redis. Devuelve 200 si todo está en verde; 503 en caso contrario.
/activity
Flujo de actividad en vivo para el globo de la portada. Se guarda en caché en el borde de Cloudflare.
/bandwidth/status
60/min
Uso actual de la cuota de carga para quien llama: lo usan la CLI y la app de escritorio para mostrar la capacidad restante. La estructura de la respuesta cambia para usuarios autenticados. A pesar del nombre de la URL, esto solo registra subida bytes; las descargas no se cuentan.
/app-analytics
120/min
Envía un evento de uso desde la CLI o la app de escritorio.
Cuerpo de la solicitud
| Campo | Tipo | Descripción |
|---|---|---|
app | string · required | desktop, cli o web. |
version | string · optional | Versión del cliente. |
event | string · required | Nombre del evento, por ejemplo upload_complete. |
context | object · optional | Metadatos adicionales. |
/app-errors
60/min
Envía un informe de error desde la CLI o la app de escritorio. Dedupe en el servidor: máximo 10 del mismo error por hora.
Cuerpo de la solicitud
| Campo | Tipo | Descripción |
|---|---|---|
app | string · required | desktop, cli o web. |
type | string · required | Clase/tipo de error. |
message | string · required | Mensaje de error. |
stack | string · optional | Traza de la pila. |
version, os, os_version, arch, context | various · optional | Metadatos de diagnóstico. |