참조

REST API

HTTP로 파일 업로드, 컬렉션 생성, 공유 관리가 가능합니다. 모든 응답은 JSON이며, 익명 업로드에는 API 키가 필요하지 않습니다.

기본 URLhttps://storage.to/api
엔드포인트 33개 · JSON

업로드 작동 방식

storage.to API는 CLI, 데스크톱 앱, 웹 업로더은 물론, 여러분이 만들고 싶은 어떤 서드파티 클라이언트에도 동력을 제공합니다. 업로드 흐름은 3단계입니다:

01 · POST /upload/init
초기화
파일을 업로드하고 싶다고 알려주세요. 저희 스토리지 엣지를 가리키는 프리사인드 URL을 하나 이상 반환합니다.
02 · PUT {upload_url}
업로드
PUT 바이트를 프리사인 URL(들)에 직접 전송하세요. 바이트는 저희 서버를 거치지 않습니다.
03 · POST /upload/confirm
확인
업로드가 완료되었다고 알려주세요. File 레코드를 생성하고 공유 가능한 URL을 드립니다.

아래 엔드포인트는 모두 이 기본 경로를 기준으로 합니다. 예: POST /upload/init는 POST https://storage.to/api/upload/init을 의미합니다.

인증

익명 업로드는 인증 없이 작동하지만 제한이 엄격합니다. 키 없는 호출은 기기 또는 IP당 24시간마다 50개 파일로 제한되며, 아래 대역폭 할당량이 추가로 적용되고 파일은 3일 후 만료됩니다.

무료 계정으로 인증하면 다음이 잠금 해제됩니다:

  • 일일 파일 제한 없음
  • 업로드 대역폭 할당량 없음
  • 내 계정에 연결된 업로드( /dashboard 에서 확인 가능 )
  • 프리미엄 기능(영구 파일, 더 큰 저장공간)
  • 방문자 토큰 일치가 필요하지 않은 소유권 기반 변경(삭제, 비밀번호 설정, 만료 변경)

제한 한눈에 보기

토큰 없음(익명)
무료 계정 토큰
유료 계정 토큰
일일 파일 수
50 / 24 시간
무제한
무제한
업로드 대역폭
100 GB / 24 시간 (500 GB IP당)
무제한
무제한
최대 파일 크기
25 GB
25 GB
100 GB
파일 만료
기본 3일, expiry_days 로 최대 7일
기본 3일, expiry_days 로 최대 7일
만료 없음(파일 영구 보관)
저장 공간
없음(파일이 만료됨)
없음(파일이 만료됨)
요금제에 따라 100GB - 1TB 영구 보관
요금제 보기 →

월간 할당량은 없습니다. 모든 제한은 24시간 롤링 윈도우 또는 분당 속도 제한입니다. 무료 요금제에는 고정 저장 공간이 없습니다. 모든 파일이 스스로 만료되므로 할당량에 누적되지 않습니다.

인증하려면 계정에서 개인 API 토큰을 생성한 뒤, 모든 요청에 베어러 토큰으로 전송하세요: 로그인이 필요합니다. 전체 토큰은 생성 시에만 한 번 표시되므로 안전한 곳에 복사해 두세요. 같은 페이지에서 언제든 토큰을 취소(폐기)할 수 있습니다. API 토큰 생성 →
Authorization: Bearer <token>

소유권 증명

소유자 토큰추천
리소스를 생성하는 모든 엔드포인트(/upload/init multipart, /upload/confirm, /file/reserve, /collection)는 응답에 owner_token를 반환합니다. 이 토큰은 IP나 방문자 토큰과 무관하게, 해당 특정 리소스에 연결된 서명된 소유권 증거입니다. 토큰은 리소스가 존재하는 동안만 유지되며, 저장해도 안전하고 독립적으로 만료되지 않습니다. 토큰을 잃어버리면 해당 리소스(파일/컬렉션/업로드)를 제어할 수 없게 됩니다. 로컬 비밀번호처럼 취급하세요.
Authorization: Owner <token>
# 또는 Bearer 세션과 함께
X-Owner-Token: <token>
방문자 토큰
익명 클라이언트는 계정 없이도 자신이 업로드한 파일의 소유권을 증명할 방법이 필요합니다. 우리는 방문자 토큰를 사용합니다. :vt는 클라이언트가 한 번 생성해 재사용하는 랜덤 문자열이에요. 모든 요청에 함께 보내세요: 웹에서는 토큰이 visitor_token 쿠키에 자동으로 저장됩니다. CLI는 이를 ~/.config/storageto/token에 저장합니다( CLI 문서 참조 ).
X-Visitor-Token: <random-string>

변경(mutation) 엔드포인트(삭제, 비밀번호 설정, 만료 변경)의 경우, 둘 중 하나는 방문자 토큰이 일치하거나 또는 요청이 파일을 생성한 것과 동일한 IP에서 온 경우에 소유권이 확인됩니다. 둘 다 사라질 수 있습니다(쿠키 삭제, 네트워크 변경). 앞으로는 소유자 토큰가 선호되는 증거입니다.

에러

에러는 항상 동일한 형태로 제공됩니다: { "success": false, "error": "…" }

200성공.
201생성됨.
400잘못된 요청(예: 컬렉션 크기 제한 초과).
401비밀번호가 필요하거나 비밀번호가 올바르지 않습니다.
403권한 없음(해당 리소스의 소유자가 아닙니다).
404리소스를 찾을 수 없거나 만료되었습니다.
422검증에 실패했거나 플랜/쿼터 제한이 있습니다.
429요청 제한(rate limit) 또는 업로드 쿼터 초과입니다.
500서버 오류입니다. 상태를 확인하세요.

요청 제한

모든 요청 제한은 IP 기준입니다. 429 응답에는 표준 Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining 헤더가 포함됩니다.

업로드 시작(init) / 확인(confirm) / 중단(abort)60 / 분
멀티파트 완료500 / 분
멀티파트 파트 URL120 / 분
배치 시작(init) / 확인(confirm)500 / 분
상태 폴링(파일 & 컬렉션)120 / 분
설정(비밀번호, 만료, 최대 다운로드 횟수)30 / 분
비밀번호 검증10 / 분
컬렉션 생성30 / 분
관리(준비 완료, 삭제)60 / 분
썸네일 업로드120 / 분
ShareX 업로드20 / 일
앱 분석/에러분당 120회 및 60회

업로드 쿼터: 익명 클라이언트에는 동시에 두 가지 한도가 적용됩니다 - 방문자 토큰당 24시간 100GB과 IP당 24시간 500GB( IP 한도는 토큰이 없는 트래픽과 공유 네트워크를 잡습니다 ). 둘 중 하나라도 초과하면 상세 정보가 포함된 429를 받게 됩니다. 이건 업로드 할당량 한도만 해당됩니다 - 다운로드는 무제한이며 속도 제한도 없습니다.

업로드

엔드포인트 8개

5GB를 넘는 파일을 포함한 모든 파일의 3단계 업로드 흐름(자동으로 멀티파트 처리). 빠르게 스크린샷처럼 업로드만 필요하다면 대신 ShareX를 참고하세요.

POST/upload/init60/min

업로드를 시작하세요. 50MB를 초과하는 파일은 멀티파트 업로드 응답(type: "multipart" 필드)이 제공되고, 그 외에는 단일 프리사인 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/parts소유자 전용120/min

진행 중인 멀티파트 업로드에 대해 추가 파트 URL을 요청합니다. /init이 가지고 있는 파트 수보다 URL을 적게 반환했을 때(또는 만료됐을 때) 사용합니다.

요청 본문

필드유형설명
upload_idstring · required/init에서 받은 upload_id.
part_numbersarray<int> · requiredURL을 가져올 파트 번호입니다.
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

모든 파트를 업로드한 뒤 멀티파트 업로드를 완료합니다.

요청 본문

필드유형설명
upload_idstring · required/init에서 받은 upload_id.
partsarray · required각 항목: 파트 업로드 응답의 { partNumber, etag }.
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

멀티파트 업로드를 취소하고 남은 부분 데이터를 정리합니다.

요청 본문

필드유형설명
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/init에서 받은 r2_key.
collection_idstring · optional컬렉션에 첨부하기.
crc32integer · optional무결성 검증을 위한 CRC32 체크섬.
file_idstring(9) · optional이전에 예약됨된 파일 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

바이트가 준비되기 이전 전에 파일 ID와 공유 가능한 URL을 예약합니다. 먼저 링크를 전달해야 하고, 이후에 업로드를 이행해야 할 때 유용합니다. 소유권은 방문자 토큰 + IP에 연결됩니다. 나중에 /upload/init + /upload/confirm으로 업로드를 마무리하고, 확인 시 file_id를 전달하세요.

요청 본문

필드유형설명
filenamestring · optional자리표시자 파일명. 기본값은 "Pending".
content_typestring · optional자리표시자 MIME 유형.
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_..."
}

웹 업로더에 최적화된 /upload/init의 배치 버전입니다. 한 번의 왕복으로 최대 250개 파일을 시작합니다.

웹 업로더에서 내부적으로 사용합니다. 대부분의 클라이언트는 단일 파일 /upload/init을 사용하는 것을 권장합니다.

/upload/confirm의 배치 버전입니다. 한 번의 왕복으로 여러 파일을 확인합니다.

컬렉션

엔드포인트 9개

컬렉션은 단일 공유 URL(/c/{id}) 아래에 여러 파일을 묶습니다. 최대 10,000개 파일, 총 25GB까지 가능합니다.

POST/collection30/min

새 컬렉션을 생성합니다. 이후 /upload/confirm에서 collection_id를 전달해 파일을 첨부하세요.

요청 본문

필드유형설명
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_..."
}

컬렉션의 상태를 확인합니다. 또한 예상된 모든 파일이 확인되면 컬렉션을 자동으로 '준비됨' 처리합니다.

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소유자 전용60/min

컬렉션을 다운로드 준비됨으로 표시하세요. 보통은 필요하지 않습니다. expected_file_count에 도달하면 컬렉션이 자동으로 준비됩니다.

DELETE/collection/{id}소유자 전용60/min

컬렉션과 그 안의 모든 파일을 삭제합니다.

POST/collection/{id}/password소유자 전용30/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}/password소유자 전용30/min

컬렉션에서 비밀번호를 제거합니다.

비밀번호를 확인합니다. 성공하면 200, 비밀번호가 틀리면 401를 반환합니다.

요청 본문

필드유형설명
passwordstring · required
POST/collection/{id}/expiry소유자 전용영구 보관: 유료30/min

컬렉션의 만료 시간을 변경합니다.

요청 본문

필드유형설명
daysinteger · optional지금부터 1~7일 후. 단, 업로드 후 7일(현재 만료일이 더 늦다면 그 날짜)보다 늦을 수는 없습니다. 생략하거나 null 이면 영구 보관(프리미엄 전용).
POST/collection/{id}/max-downloads소유자 전용30/min

다운로드 한도 설정(다운로드 N회 후 삭제). 한도에 도달하면 컬렉션이 자동으로 삭제됩니다.

요청 본문

필드유형설명
max_downloadsinteger · optional1–1000. 현재 다운로드 횟수를 초과해야 합니다. 한도 제거는 null.

파일

엔드포인트 8개

파일 단위 설정(비밀번호, 만료, 최대 다운로드)은 컬렉션 엔드포인트를 그대로 따릅니다. 소유자만 가능합니다.

파일이 업로드를 아직 대기 중인지 확인합니다.

Response
{ "pending": false }
DELETE/file/{id}소유자 전용60/min

파일을 즉시 삭제합니다.

POST/file/{id}/thumbnail소유자 전용120/min

동영상 또는 이미지 파일의 썸네일 이미지를 업로드합니다(다운로드 페이지에서 사용). 최대 2MB.

요청 본문

필드유형설명
thumbnailimage · required멀티파트 업로드. 최대 2MB.
Response
{
  "success": true,
  "thumbnail_url": "https://..."
}
POST/file/{id}/password소유자 전용30/min

파일에 비밀번호를 설정합니다. 4–100자 필요합니다.

DELETE/file/{id}/password소유자 전용30/min

파일의 비밀번호를 제거합니다.

파일의 비밀번호를 확인합니다.

POST/file/{id}/expiry소유자 전용영구 보관: 유료30/min

파일의 만료 시간을 변경합니다.

요청 본문

필드유형설명
daysinteger · optional지금부터 1~7일 후. 단, 업로드 후 7일(현재 만료일이 더 늦다면 그 날짜)보다 늦을 수는 없습니다. 생략하거나 null 이면 영구 보관(프리미엄 전용).
POST/file/{id}/max-downloads소유자 전용30/min

파일의 총 다운로드 횟수를 제한합니다. 한도에 도달하면 자동으로 삭제됩니다.

ShareX 업로드

엔드포인트 1개

원샷 업로드 엔드포인트 - multipart 파일을 보내면 공유 가능한 URL을 다시 받습니다. 초기화/확인 절차가 필요 없어요. 스크린샷 도구에 딱입니다. 전체 설정 가이드는 /docs/sharex에서 확인하세요.

POST/sharex/upload20/day

이미지 또는 파일을 직접 업로드합니다(멀티파트 폼, file 필드). 최대 25MB.

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

데스크톱 인증

엔드포인트 2개

데스크톱 앱처럼 Bearer 토큰을 가진 로그인된 클라이언트용입니다.

GET/userBearer 토큰

인증된 사용자를 반환합니다.

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 토큰

현재 액세스 토큰을 폐기합니다.

기타

엔드포인트 5개

상태, 할당량, 클라이언트 텔레메트리.

활성 상태 확인. API 워커가 정상 동작 중이면 200 와 { "status": "ok" } 를 반환합니다.

Response
{ "status": "ok" }

홈페이지 글로브용 실시간 활동 스트림. 엣지에 캐시됩니다.

호출자의 현재 업로드 할당량 사용량 - 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 또는 데스크톱 앱에서 사용 이벤트를 전송하세요.

요청 본문

필드유형설명
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진단 메타데이터입니다.