REST API

Загружайте файлы, создавайте коллекции и управляйте доступами по HTTP. Все ответы — в формате JSON; для анонимных загрузок ключ API не требуется.

Введение

API storage.to работает для нашего CLI, приложение для рабочего стола, веб-загрузчик и любых сторонних клиентов, которые вы захотите создать.

Процесс загрузки состоит из трёх шагов:

  1. Инициализация - сообщите, что хотите загрузить файл. Мы вернём один или несколько предподписанных URL-адресов, указывающих на Cloudflare R2.
  2. Загрузка в R2 - PUT ваши байты напрямую на presigned URL(ы). Байты не проходят через наши серверы.
  3. Подтвердить - сообщите, что загрузка завершена. Мы создадим запись File и дадим вам URL-адрес для общего доступа.

Базовый URL

https://storage.to/api

Все конечные точки ниже указаны относительно этого базового адреса. Пример: POST /upload/init означает POST https://storage.to/api/upload/init.

Аутентификация

Анонимные загрузки работают без аутентификации, но с жесткими ограничениями. Вызовы без ключа ограничены 50 файлами за скользящие 24 часа на устройство или IP, плюс квоты трафика ниже, а файлы истекают через 3 дня.

Аутентификация с бесплатным аккаунтом открывает:

  • Без дневного лимита файлов
  • Без квоты на объём загрузки
  • Загрузки, привязанные к вашей учётной записи (видны в /dashboard)
  • Премиум-функции (постоянные файлы, больше места)
  • Изменения на основе владения (удаление, установка пароля, изменение срока действия) без необходимости совпадения visitor-token

Лимиты вкратце

ЛимитБез токена (анонимно)Токен бесплатного аккаунтаТокен платного аккаунта
Файлов в день50 / 24 часаБез ограниченийБез ограничений
Объём загрузки100 GB / 24 часа
(500 GB на IP)
Без ограниченийБез ограничений
Максимальный размер файла25 GB25 GB100 GB
Срок хранения файлаПо умолчанию 3 дня, до 7 через expiry_daysПо умолчанию 3 дня, до 7 через expiry_daysНикогда (файлы хранятся постоянно)
ХранилищеНет (файлы удаляются по сроку)Нет (файлы удаляются по сроку)100 ГБ - 1 ТБ постоянного хранения, по тарифу

Месячных квот нет: все лимиты - скользящие 24-часовые окна или ограничения в минуту. На бесплатном тарифе нет фиксированного хранилища: каждый файл удаляется по своему сроку, поэтому квота не накапливается.

Чтобы пройти аутентификацию, сгенерируйте персональный API-токен в своём аккаунте и отправляйте его как bearer-токен в каждом запросе:

Authorization: Bearer <token>

Сгенерировать API-токен

Вам нужно войти в аккаунт. Полный токен показывается только один раз при создании, поэтому сохраните его в надёжном месте. Токен можно отозвать в любое время на этой же странице.

Токен посетителя

Анонимным клиентам нужен способ доказать, что именно они владеют своими загрузками, без аккаунта. Мы используем visitor token — случайную строку, которую клиент генерирует один раз и затем повторно использует. Отправляйте её с каждым запросом:

X-Visitor-Token: <random-string>

В веб-версии токен автоматически сохраняется в cookie visitor_token. В CLI он хранится по адресу ~/.config/storageto/token (см. Документация для CLI).

Для мутационных endpoint’ов (удаление, установка пароля, изменение срока действия) владение подтверждается, если либо токен посетителя совпадает или запрос приходит с того же IP, с которого был создан файл. Оба варианта могут быть потеряны (очищенные cookies, смена сети). В дальнейшем предпочтительным доказательством является owner token.

Токен владельца

Каждый endpoint, создающий ресурс (/upload/init multipart, /upload/confirm, /file/reserve, /collection), возвращает в ответе owner_token. Токен — это подписанное доказательство владения, привязанное к конкретному ресурсу, и не зависит от вашего IP или токена посетителя.

Сохраните токен вместе с ID ресурса и отправляйте его в любом запросе на изменение как:

Authorization: Owner <token>

Или, если вы уже используете Authorization: Bearer для аутентифицированной сессии, отправляйте его так:

X-Owner-Token: <token>

Сервер принимает owner token как действительное доказательство владения вместе с устаревшим вариантом visitor token + запасной IP — клиенты, у которых есть токен, продолжают работать после смены сети или очистки cookies, а клиенты без токена продолжают работать ровно как раньше.

Токены живут столько же, сколько существует ресурс, безопасны для хранения и не истекают независимо. Потеря токена означает потерю контроля над этим ресурсом (файл/коллекция/загрузка) — относитесь к ним как к локальным паролям.

Ошибки

Ошибки имеют единый формат:

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

Частые HTTP-коды состояния:

КодЗначение
200ОК.
201Создано.
400Неверный запрос (например, превышен лимит размера коллекции).
401Требуется пароль или он неверный.
403Нет прав (вы не владелец ресурса).
404Ресурс не найден или срок действия истёк.
422Ошибка валидации или ограничение тарифа/квоты.
429Превышен лимит частоты или квота на загрузки.
500Ошибка сервера. Проверьте статус.

Ограничения по частоте запросов

Все лимиты частоты считаются по IP. В ответе 429 присутствуют стандартные заголовки Retry-After, X-RateLimit-Limit и X-RateLimit-Remaining.

ОбластьЛимит
Инициализация / подтверждение / отмена загрузки60 / минута
Завершение multipart500 / минута
URL частей multipart120 / минута
Пакетная инициализация / подтверждение500 / минута
Проверки статуса (файл и коллекция)120 / минута
Настройки (пароль, срок действия, максимум скачиваний)30 / минута
Проверка пароля10 / минута
Создание коллекции30 / минута
Управление (готово, удалить)60 / минута
Загрузка превью120 / минута
Загрузка из ShareX20 / день
Аналитика приложения / ошибки120 и 60 / мин

Квота на загрузки: У анонимных клиентов параллельно работают два лимита — 100 ГБ / 24 ч на visitor token и 500 ГБ / 24 ч на IP (лимит по IP ловит трафик без токена и общие сети). Если превысить любой из них, вы получите 429 с подробностями. Это только лимит по загрузка — скачивания неограничены и без ограничений по скорости (отдаются напрямую по подписанным URL из R2).

Загрузить

Трёхшаговый процесс загрузки для любых файлов, включая файлы больше 5 ГБ (автоматически multipart). Если вам нужна только быстрая загрузка в стиле скриншота — вместо этого смотрите ShareX.

POST/upload/init60/min

Инициируйте загрузку. Для файлов >50 МБ ответ будет multipart-загрузкой (поле type: "multipart"); иначе — один presigned PUT.

Тело запроса

ПолеТипОписание
filenamestring · requiredОригинальное имя файла. Макс. 255 символов.
content_typestring · requiredMIME-тип.
sizeinteger · requiredРазмер файла в байтах. Мин. 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/partsOwner only120/min

Запросить дополнительные URL-адреса частей для выполняющейся multipart-загрузки. Используется, когда /init вернул меньше URL, чем у вас частей (или они истекли).

Тело запроса

ПолеТипОписание
upload_idstring · requiredЗначение upload_id из /init.
part_numbersarray<int> · requiredНомера частей, для которых нужно получить 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-multipartOwner only500/min

Завершить multipart-загрузку на R2 после загрузки всех частей.

Тело запроса

ПолеТипОписание
upload_idstring · requiredЗначение upload_id из /init.
partsarray · requiredКаждая запись: { partNumber, etag } из ответа 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/abortOwner only60/min

Отменить multipart-загрузку и очистить любые частичные данные на R2.

Тело запроса

ПолеТипОписание
upload_idstring · requiredЗагрузка, которую нужно прервать.
Request
curl -X POST https://storage.to/api/upload/abort \ -H "Content-Type: application/json" \ -d '{ "upload_id": "01HXYZ..." }'
POST/upload/confirm60/min

Подтвердить, что загрузка завершена. Именно тогда мы создаём запись File и возвращаем общий URL.

Тело запроса

ПолеТипОписание
filenamestring · requiredОригинальное имя файла.
sizeinteger · requiredРазмер файла в байтах.
content_typestring · requiredMIME-тип.
r2_keystring · requiredЗначение r2_key из /init.
collection_idstring · optionalДобавить в коллекцию.
crc32integer · optionalКонтрольная сумма CRC32 для проверки целостности.
file_idstring(9) · optionalВыполнить (fulfil) ранее выданный reserved 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", "filename": "report.pdf", "size": 2202009, "human_size": "2.1 MB", "expires_at": "2026-04-15T12:00:00Z" }, "owner_token": "owner_v1_..." }
POST/file/reserve60/min

Зарезервируйте file ID и общий URL до того, как будут готовы байты. Удобно, когда нужно сначала выдать ссылку, а затем выполнить загрузку. Владение привязано к вашему visitor token + IP. Завершите загрузку позже с /upload/init + /upload/confirm, передав file_id для подтверждения.

Тело запроса

ПолеТипОписание
filenamestring · optionalИмя файла-заглушка. По умолчанию: "Pending".
content_typestring · optionalMIME-тип-заглушка.
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", "expires_at": "2026-04-12T18:00:00Z" }, "owner_token": "owner_v1_..." }
POST/upload/init-batch500/min

Пакетный аналог /upload/init, оптимизированный для веб-загрузчика. Запускает до 250 файлов за один обмен.

Используется внутри веб-загрузчиком. Большинству клиентов лучше использовать одиночный /upload/init.

POST/upload/confirm-batch500/min

Пакетный аналог /upload/confirm. Подтверждает много файлов за один обмен.

Коллекции

Коллекция объединяет несколько файлов под одним общим URL (/c/{id}). До 10 000 файлов и 25 ГБ суммарно.

POST/collection30/min

Создать новую коллекцию. Затем добавьте файлы, передав collection_id на /upload/confirm.

Тело запроса

ПолеТипОписание
expected_file_countinteger · optionalПодсказка для автоматической отметки коллекции как готовой, когда подтвердятся все ожидаемые файлы.
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}/status120/min

Проверять состояние коллекции. Также автоматически помечает коллекцию как готовую, если подтвердятся все ожидаемые файлы.

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}/readyOwner only60/min

Отметьте коллекцию как готовую к скачиванию. Обычно это не нужно — коллекции автоматически становятся готовыми, как только достигнут expected_file_count.

DELETE/collection/{id}Owner only60/min

Удалить коллекцию и все её файлы.

POST/collection/{id}/passwordOwner only30/min

Установить пароль для коллекции. Требуется 4–100 символов.

Тело запроса

ПолеТипОписание
passwordstring · required4–100 символов.
Request
curl -X POST https://storage.to/api/collection/ABC123xyz/password \ -H "X-Visitor-Token: abc123" \ -d '{ "password": "hunter22" }'
DELETE/collection/{id}/passwordOwner only30/min

Удалить пароль из коллекции.

POST/collection/{id}/verify-password10/min

Проверить пароль. Возвращает 200 при успехе и 401 при неверном пароле.

Тело запроса

ПолеТипОписание
passwordstring · required
POST/collection/{id}/expiryOwner only30/min

Изменить срок действия коллекции.

Тело запроса

ПолеТипОписание
daysinteger · optionalВ течение 1–7 дней с текущего момента. Пропустите или укажите null для постоянного (только premium).
POST/collection/{id}/max-downloadsOwner only30/min

Установить лимит скачиваний (burn-after-N-downloads). Коллекция автоматически удалится, когда лимит будет достигнут.

Тело запроса

ПолеТипОписание
max_downloadsinteger · optional1–1000. Должно быть больше текущего количества скачиваний. null — чтобы убрать лимит.

Файлы

Все настройки на уровне файла (пароль, срок действия, max-downloads) повторяют параметры коллекции. Только владелец.

GET/file/{id}/status120/min

Проверить, ожидает ли файл завершения загрузки.

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

Немедленно удалить файл.

POST/file/{id}/thumbnailOwner only120/min

Загрузить миниатюру для видео или изображения (используется на странице скачивания). Макс. 2 МБ.

Тело запроса

ПолеТипОписание
thumbnailimage · requiredMultipart-загрузка. Макс. 2 МБ.
Response
{ "success": true, "thumbnail_url": "https://..." }
POST/file/{id}/passwordOwner only30/min

Установить пароль для файла. Требуется 4–100 символов.

DELETE/file/{id}/passwordOwner only30/min

Убрать пароль у файла.

POST/file/{id}/verify-password10/min

Проверить пароль файла.

POST/file/{id}/expiryOwner only30/min

Изменить срок действия файла.

Тело запроса

ПолеТипОписание
daysinteger · optionalВ течение 1–7 дней с текущего момента. Пропустите или укажите null для постоянного (только premium).
POST/file/{id}/max-downloadsOwner only30/min

Ограничить общее число скачиваний файла. Автоматически удаляется, когда лимит достигнут.

Загрузка из ShareX

Одноразовая точка загрузки — отправьте multipart-файл и получите обратно URL, которым можно делиться. Никаких инициализаций/подтверждений. Идеально для инструментов скриншотов. Полная инструкция по настройке: /docs/sharex.

POST/sharex/upload20/day

Загрузить изображение или файл напрямую (multipart form, поле file). Макс. 25 МБ.

Request
curl -X POST https://storage.to/api/sharex/upload \ -F "file=@screenshot.png"
Response
{ "success": true, "url": "https://storage.to/FQxyz1234", "filename": "screenshot.png", "expires_at": "2026-04-15T12:00:00Z" }

Аутентификация для десктопа

Для аутентифицированных клиентов (например, desktop-приложения), у которых есть Sanctum token.

GET/userBearer token

Верните аутентифицированного пользователя.

Request
curl https://storage.to/api/user \ -H "Authorization: Bearer <token>"
Response
{ "id": 42, "name": "Ada", "email": "ada@example.com", "is_premium": true }
POST/auth/logoutBearer token

Отзовите текущий access token.

Разное

GET/health

Проверка доступности. Возвращает 200 с { "status": "ok" }, когда воркер API обслуживает запросы.

Response
{ "status": "ok" }
GET/activity

Живой поток активности для «глобуса» на главной странице. Кэшируется на edge у Cloudflare.

GET/bandwidth/status60/min

Текущее использование лимита загрузок для вызывающего — используется CLI и десктоп-приложением, чтобы показать оставшуюся ёмкость. Формат ответа отличается для авторизованных пользователей. Несмотря на название URL, учитываются только байты загрузка; скачивания не считаются.

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-analytics120/min

Отправьте событие использования из CLI или desktop-приложения.

Тело запроса

ПолеТипОписание
appstring · requireddesktop, cli или web.
versionstring · optionalВерсия клиента.
eventstring · requiredИмя события, например upload_complete.
contextobject · optionalДополнительные метаданные.
POST/app-errors60/min

Отправляйте отчёт об ошибке из CLI или десктоп-приложения. Дедупликация выполняется на сервере — максимум 10 одинаковых ошибок в час.

Тело запроса

ПолеТипОписание
appstring · requireddesktop, cli или web.
typestring · requiredКласс/тип ошибки.
messagestring · requiredСообщение об ошибке.
stackstring · optionalСтек вызовов.
version, os, os_version, arch, contextvarious · optionalДиагностические метаданные.