REST API

Envie arquivos, crie coleções e gerencie compartilhamentos via HTTP. Todas as respostas são em JSON; não é necessária uma chave de API para uploads anônimos.

Introdução

A API do storage.to alimenta nosso CLI, app de desktop, enviador web e qualquer cliente de terceiros que você queira criar.

O fluxo de envio tem três etapas:

  1. Iniciar — diga que você quer enviar um arquivo. Nós retornamos uma ou mais URLs presignadas apontando para o Cloudflare R2.
  2. Enviar para o R2 — :coloque seus bytes diretamente na(s) URL(s) pré-assinada(s). Os bytes não passam pelos nossos servidores.
  3. Confirmar — diga que o envio foi concluído. Criamos um registro File e entregamos uma URL compartilhável.

URL base

https://storage.to/api

Todos os endpoints abaixo são relativos a esta base. Exemplo: POST /upload/init significa POST https://storage.to/api/upload/init.

Autenticação

A maioria dos endpoints não exige autenticação. Uploads anônimos são um recurso essencial.

A autenticação é opcional e desbloqueia:

  • Uploads vinculados à sua conta (visível em /dashboard)
  • Recursos premium (arquivos permanentes, mais armazenamento)
  • Mutations baseadas em propriedade (excluir, definir senha, alterar validade) sem precisar do match do visitor-token

Usamos tokens bearer Laravel Sanctum. Emita um token via o handoff do OAuth no desktop ou pelo login web e, em seguida, envie-o como:

Authorization: Bearer <token>

Token de visitante

Clientes anônimos precisam de uma forma de provar a propriedade dos próprios uploads sem ter uma conta. Usamos um visitor token — uma string aleatória que o cliente gera uma vez e reutiliza. Envie com toda requisição:

X-Visitor-Token: <random-string>

No web, o token é armazenado automaticamente no cookie visitor_token. O CLI o armazena em ~/.config/storageto/token (veja Documentação da CLI).

Para endpoints de mutação (delete, definir senha, alterar validade), a propriedade é confirmada se ou o token do visitante corresponder a ou a requisição vier do mesmo IP que criou o arquivo. Ambos podem ser perdidos (cookies apagados, mudanças de rede). O token do proprietário é a prova preferida daqui pra frente.

Token do proprietário

Todo endpoint que cria recursos (/upload/init multipart, /upload/confirm, /upload/reserve, /collection) retorna um owner_token na resposta. O token é uma prova de propriedade assinada, vinculada a esse recurso específico, independente do seu IP ou do token do visitante.

Guarde o token junto com o ID do recurso e envie-o em qualquer mutação como:

Authorization: Owner <token>

Ou, se você já estiver usando Authorization: Bearer para uma sessão autenticada, envie como:

X-Owner-Token: <token>

O servidor aceita o token do proprietário como uma prova válida de propriedade junto com o fallback legado visitor token + IP — clientes que têm o token continuam funcionando após trocar de rede ou limpar cookies, e clientes que não têm continuam funcionando exatamente como antes.

Os tokens duram enquanto o recurso existir, são seguros para persistir e não expiram de forma independente. Um token perdido significa perder o controle desse recurso (arquivo/coleção/upload) — trate-os como senhas locais.

Erros

Os erros seguem um formato consistente:

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

Códigos de status HTTP comuns:

CódigoSignificado
200OK.
201Criado.
400Requisição inválida (por exemplo, limite de tamanho da coleção excedido).
401Senha necessária ou incorreta.
403Não autorizado (não é o proprietário do recurso).
404Recurso não encontrado ou expirado.
422Falha na validação ou restrição de plano/quota.
429Limite de taxa atingido ou cota de upload excedida.
500Erro no servidor. Verifique status.

Limites de taxa

Todos os limites de taxa são por IP. Uma resposta 429 inclui os cabeçalhos padrão Retry-After, X-RateLimit-Limit e X-RateLimit-Remaining.

EscopoLimite
Upload init / confirm / abort60 / minuto
Conclusão multipart500 / minuto
URLs das partes multipart120 / minuto
Batch init / confirm500 / minuto
Consultas de status (arquivo e coleção)120 / minuto
Configurações (senha, validade, max-downloads)30 / minuto
Verificação de senha10 / minuto
Criação de coleção30 / minuto
Gerenciar (ready, delete)60 / minuto
Upload de miniatura120 / minuto
Upload pelo ShareX20 / dia
Analytics do app / erros120 e 60 / minuto

Cota de upload: clientes anônimos têm dois limites em paralelo — 100 GB / 24 h por visitor token e 500 GB / 24 h por IP (o limite de IP captura tráfego sem token e redes compartilhadas). Quando qualquer um for excedido, você recebe um 429 com detalhes. Isso é apenas uma upload cota — downloads são ilimitados e sem limitação (servidos diretamente das URLs assinadas do R2).

Upload

O fluxo de upload em três etapas para qualquer arquivo, incluindo arquivos acima de 5 GB (multipart automático). Se você só precisa de um upload rápido no estilo de captura de tela, veja ShareX.

POST /upload/init 60/min

Inicie um upload. Para arquivos >50 MB, a resposta é um upload multipart (campo type: "multipart"); caso contrário, um único PUT presignado.

Corpo da requisição

CampoTipoDescrição
filenamestring · requiredNome original do arquivo. Máx. 255 caracteres.
content_typestring · requiredTipo MIME.
sizeinteger · requiredTamanho do arquivo em bytes. Mín. 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/parts Owner only 120/min

Solicita URLs adicionais das partes para um upload multipart em andamento. Usado quando /init retornou menos URLs do que você tem partes (ou elas expiraram).

Corpo da requisição

CampoTipoDescrição
upload_idstring · requiredO upload_id de /init.
part_numbersarray<int> · requiredNúmeros das partes para obter 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 Owner only 500/min

Finaliza um upload multipart no R2 assim que todas as partes forem enviadas.

Corpo da requisição

CampoTipoDescrição
upload_idstring · requiredO upload_id de /init.
partsarray · requiredCada entrada: { partNumber, etag } da resposta do 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 Owner only 60/min

Cancele um upload multipart e limpe qualquer dado parcial no R2.

Corpo da requisição

CampoTipoDescrição
upload_idstring · requiredO upload a ser interrompido.
Request
curl -X POST https://storage.to/api/upload/abort \ -H "Content-Type: application/json" \ -d '{ "upload_id": "01HXYZ..." }'
POST /upload/confirm 60/min

Confirme que o upload foi concluído. É quando criamos o registro File e retornamos a URL compartilhável.

Corpo da requisição

CampoTipoDescrição
filenamestring · requiredNome original do arquivo.
sizeinteger · requiredTamanho do arquivo em bytes.
content_typestring · requiredTipo MIME.
r2_keystring · requiredO r2_key de /init.
collection_idstring · optionalAnexar a uma coleção.
crc32integer · optionalSoma de verificação CRC32 para verificação de integridade.
file_idstring(9) · optionalConcluir um ID de arquivo reservado previamente.
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" }, "owner_token": "owner_v1_..." }
POST /file/reserve 60/min

Reserve um ID de arquivo e uma URL compartilhável antes os bytes ficarem prontos. Útil quando você precisa entregar um link primeiro e concluir o upload depois. A propriedade fica vinculada ao seu token de visitante + IP. Finalize o upload mais tarde com /upload/init + /upload/confirm, passando file_id para confirmar.

Corpo da requisição

CampoTipoDescrição
filenamestring · optionalNome de arquivo de exemplo. Padrão: "Pending".
content_typestring · optionalTipo MIME de exemplo.
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" }, "owner_token": "owner_v1_..." }
POST /upload/init-batch 500/min

Equivalente em lote de /upload/init, otimizado para o uploader web. Inicia até 250 arquivos em uma única ida e volta.

Usado internamente pelo uploader web. A maioria dos clientes deve preferir o /upload/init de arquivo único.

POST /upload/confirm-batch 500/min

Equivalente em lote de /upload/confirm. Confirma muitos arquivos em uma única ida e volta.

Coleções

Uma coleção agrupa vários arquivos sob uma única URL de compartilhamento (/c/{id}). Até 10.000 arquivos e 25 GB no total.

POST /collection 30/min

Crie uma nova coleção. Anexe arquivos depois passando collection_id em /upload/confirm.

Corpo da requisição

CampoTipoDescrição
expected_file_countinteger · optionalDica para marcar automaticamente a coleção como pronta assim que todos os arquivos esperados forem confirmados.
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}/status 120/min

Verifica o estado de uma coleção. Também marca automaticamente a coleção como pronta se todos os arquivos esperados tiverem sido confirmados.

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

Marque a coleção como pronta para download. Normalmente não é necessário — as coleções ficam prontas automaticamente quando expected_file_count é atingido.

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

Exclua uma coleção e todos os seus arquivos.

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

Defina uma senha na coleção. Requer 4–100 caracteres.

Corpo da requisição

CampoTipoDescrição
passwordstring · required4–100 caracteres.
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

Remover a senha de uma coleção.

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

Verifique uma senha. Retorna 200 em caso de sucesso, 401 em caso de senha incorreta.

Corpo da requisição

CampoTipoDescrição
passwordstring · required
POST /collection/{id}/expiry Owner only 30/min

Altere a expiração de uma coleção.

Corpo da requisição

CampoTipoDescrição
daysinteger · optionalDe 1 a 7 dias a partir de agora. Omitir ou null para permanente (apenas premium).
POST /collection/{id}/max-downloads Owner only 30/min

Defina um limite de downloads (burn-after-N-downloads). A coleção é excluída automaticamente quando atingir o limite.

Corpo da requisição

CampoTipoDescrição
max_downloadsinteger · optional1–1000. Deve exceder a contagem atual de downloads. null para remover o limite.

Arquivos

Todas as configurações no nível do arquivo (senha, expiração, max-downloads) espelham os endpoints da coleção. Apenas o proprietário.

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

Verifique se um arquivo ainda está aguardando o upload.

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

Exclua um arquivo imediatamente.

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

Envie uma imagem de miniatura para um arquivo de vídeo ou imagem (usada na página de download). Máx. 2 MB.

Corpo da requisição

CampoTipoDescrição
thumbnailimage · requiredUpload multipart. Máx. 2 MB.
Response
{ "success": true, "thumbnail_url": "https://..." }
POST /file/{id}/password Owner only 30/min

Defina uma senha em um arquivo. Requer 4–100 caracteres.

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

Remova a senha de um arquivo.

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

Verifique a senha de um arquivo.

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

Altere a expiração de um arquivo.

Corpo da requisição

CampoTipoDescrição
daysinteger · optionalDe 1 a 7 dias a partir de agora. Omitir ou null para permanente (apenas premium).
POST /file/{id}/max-downloads Owner only 30/min

Limite o total de downloads de um arquivo. Apaga automaticamente quando atingir o limite.

Upload pelo ShareX

Endpoint de upload em uma única etapa — envie um arquivo multipart e receba uma URL compartilhável de volta. Sem a dança de init/confirm. Ideal para ferramentas de captura de tela. Guia completo de configuração em /pt/docs/sharex.

POST /sharex/upload 20/day

Envie uma imagem ou arquivo diretamente (formulário multipart, campo file). Máx. 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" }

Autenticação no desktop

Para clientes autenticados (por exemplo, o app de desktop) que tenham um token Sanctum.

GET /user Bearer token

Retorne o usuário autenticado.

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

Revogue o token de acesso atual.

Diversos

GET /health

Verificação de saúde. Faz ping no banco de dados, no armazenamento R2 e no cache Redis. Retorna 200 se tudo estiver verde; 503 caso contrário.

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

Stream ao vivo de atividades para o globo da página inicial. Armazenado em cache na borda da Cloudflare.

GET /bandwidth/status 60/min

Uso atual da cota de upload do solicitante — usado pela CLI e pelo app de desktop para mostrar a capacidade restante. A estrutura da resposta muda para usuários autenticados. Apesar do nome da URL, isso rastreia apenas upload bytes; downloads não são contabilizados.

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

Envie um evento de uso pela CLI ou pelo app de desktop.

Corpo da requisição

CampoTipoDescrição
appstring · requireddesktop, cli ou web.
versionstring · optionalVersão do cliente.
eventstring · requiredNome do evento, por exemplo upload_complete.
contextobject · optionalMetadados extras.
POST /app-errors 60/min

Envie um relatório de erro pela CLI ou pelo app de desktop. Deduplicado no servidor — no máximo 10 do mesmo erro por hora.

Corpo da requisição

CampoTipoDescrição
appstring · requireddesktop, cli ou web.
typestring · requiredClasse/tipo do erro.
messagestring · requiredMensagem do erro.
stackstring · optionalRastreamento (stack trace).
version, os, os_version, arch, contextvarious · optionalMetadados de diagnóstico.