Anda dapat melihat halaman ini dalam bahasa Anda.Ganti
Du kannst diese Seite in deiner Sprache ansehen.Wechseln
Puedes ver esta página en tu idioma.Cambiar
Vous pouvez afficher cette page dans votre langue.Changer
Puoi visualizzare questa pagina nella tua lingua.Cambia
Je kunt deze pagina in het Nederlands bekijken.Overschakelen
Możesz wyświetlić tę stronę w swoim języku.Przełącz
Você pode ver esta página no seu idioma.Mudar
Du kan visa den här sidan på ditt språk.Byt
Bu sayfayı kendi dilinde görüntüleyebilirsin.Değiştir
يمكنك عرض هذه الصفحة بلغتك.تبديل
आप यह पृष्ठ अपनी भाषा में देख सकते हैं।बदलें
이 페이지를 한국어로 볼 수 있어요.전환
このページを日本語で表示できます。切り替える

Storage API

Upload, list, download and delete files from your own projects with an API key. Uploaded files also appear on the web and in the sync folder.

Create an API key

Getting started

  1. Create a key under Account → API keys and copy the full key once. Create an API key
  2. Upload your first file:
    curl -X POST "https://cloud104.com/api/v1/files" \
      -H "Authorization: Bearer sk_..." \
      -F "file=@logo.png" \
      -F "path=/apps/blog/logo.png" \
      -F "visibility=public"
  3. The response describes the uploaded file; with visibility=public, url is its permanent CDN URL:
    {
      "ok": true,
      "id": "cm3f8k2x10001",
      "parentId": "cm3f8k2x10000",
      "name": "logo.png",
      "kind": "file",
      "size": 48213,
      "sha256": "9f2c…",
      "mime": "image/png",
      "visibility": "public",
      "url": "https://cdn.cloud104.com/…/logo.png",
      "revision": 1,
      "mtime": "2026-10-28T10:00:00.000Z",
      "source": "api",
      "sourceName": "Blog",
      "starred": false,
      "trashed": false,
      "createdAt": "2026-10-28T10:00:00.000Z",
      "updatedAt": "2026-10-28T10:00:00.000Z",
      "path": "/apps/blog/logo.png"
    }

Authentication

  • Send an Authorization: Bearer sk_… header with every request. Without it you get 401 unauthorized; a wrong or deleted key gets 401 invalid_key.
  • Scope: a files (Files only) key can use the file and folder endpoints; sharing, “shared with me” and trash endpoints need all (Full account), otherwise 403 insufficient_scope.
  • Folder lock: a key locked to a folder only sees and writes under that folder; anything outside is 403 folder_not_allowed. Requests without a folder work in the locked folder; path is still written from the account root.
  • Use the key on the server only: never embed it in a browser, a mobile app or a public repository. For browser uploads, issue an upload token (below).

Endpoints

All endpoints live under https://cloud104.com/api/v1. Requests with a body send JSON (Content-Type: application/json); successful responses carry "ok": true. :id is the id field from list and upload responses.

Upload a file

POST/api/v1/files

Uploads a file into a folder. Accepts a multipart form (multipart/form-data, up to 100 MB) or a raw body; with a raw body the parameters go in the query and Content-Length is required. Returns 201 for a new file and 200 for a new version of an existing one.

Parameters

NameInTypeRequiredDescription
fileformfileyesThe file itself (with a raw body, the whole body).
pathformstringnoTarget path including the file name (/apps/blog/logo.png), from the account root; missing folders are created.
folderIdformstringnoTarget folder ID (instead of path). Without either, the root or the key’s locked folder.
namequerystringnoFile name (with folderId or a raw body); defaults to the uploaded file’s own name.
visibilityformstringnopublic or private (default).
onConflictformstringnoIf a file with the same name exists: rename (default, numbered name), replace (new version) or fail (409).

Example request

curl -X POST "https://cloud104.com/api/v1/files" \
  -H "Authorization: Bearer sk_..." \
  -F "file=@logo.png" \
  -F "path=/apps/blog/logo.png" \
  -F "visibility=public"
curl -X POST "https://cloud104.com/api/v1/files?path=/yedek/db.sql.gz" \
  -H "Authorization: Bearer sk_..." \
  -H "Content-Type: application/octet-stream" \
  --data-binary @db.sql.gz

Example response

{
  "ok": true,
  "id": "cm3f8k2x10001",
  "parentId": "cm3f8k2x10000",
  "name": "logo.png",
  "kind": "file",
  "size": 48213,
  "sha256": "9f2c…",
  "mime": "image/png",
  "visibility": "public",
  "url": "https://cdn.cloud104.com/…/logo.png",
  "revision": 1,
  "mtime": "2026-10-28T10:00:00.000Z",
  "source": "api",
  "sourceName": "Blog",
  "starred": false,
  "trashed": false,
  "createdAt": "2026-10-28T10:00:00.000Z",
  "updatedAt": "2026-10-28T10:00:00.000Z",
  "path": "/apps/blog/logo.png"
}

List a folder

GET/api/v1/files

Returns the folder’s contents, folders first, then by name. Paginated: when nextCursor is set, send it as cursor for the next page.

Parameters

NameInTypeRequiredDescription
folderIdquerystringnoFolder ID.
pathquerystringnoFolder path (/apps/blog). Without either, the root or the key’s locked folder.
cursorquerystringnoThe nextCursor value of the previous response.
limitqueryintegernoPage size; 50 by default, at most 500.

Example request

curl "https://cloud104.com/api/v1/files?path=/apps/blog&limit=50" \
  -H "Authorization: Bearer sk_..."

Example response

{
  "ok": true,
  "folderId": "cm3f8k2x10000",
  "items": [
    {
      "id": "cm3f8k2x10001",
      "parentId": "cm3f8k2x10000",
      "name": "logo.png",
      "kind": "file",
      "size": 48213,
      "sha256": "9f2c…",
      "mime": "image/png",
      "visibility": "public",
      "url": "https://cdn.cloud104.com/…/logo.png",
      "revision": 1,
      "mtime": "2026-10-28T10:00:00.000Z",
      "source": "api",
      "sourceName": "Blog",
      "starred": false,
      "trashed": false,
      "createdAt": "2026-10-28T10:00:00.000Z",
      "updatedAt": "2026-10-28T10:00:00.000Z"
    }
  ],
  "nextCursor": null
}

File or folder metadata

GET/api/v1/files/:id

Returns the item’s fields, your role (owner, editor, viewer) and the location chain from the root to the item (path).

Parameters

NameInTypeRequiredDescription
idpathstringyesFile or folder ID.

Example request

curl "https://cloud104.com/api/v1/files/cm3f8k2x10001" \
  -H "Authorization: Bearer sk_..."

Example response

{
  "ok": true,
  "id": "cm3f8k2x10001",
  "parentId": "cm3f8k2x10000",
  "name": "logo.png",
  "kind": "file",
  "size": 48213,
  "sha256": "9f2c…",
  "mime": "image/png",
  "visibility": "public",
  "url": "https://cdn.cloud104.com/…/logo.png",
  "revision": 1,
  "mtime": "2026-10-28T10:00:00.000Z",
  "source": "api",
  "sourceName": "Blog",
  "starred": false,
  "trashed": false,
  "createdAt": "2026-10-28T10:00:00.000Z",
  "updatedAt": "2026-10-28T10:00:00.000Z",
  "role": "owner",
  "path": [
    {
      "id": "cm3f8k2x0zzzz",
      "name": ""
    },
    {
      "id": "cm3f8k2x10000",
      "name": "blog"
    },
    {
      "id": "cm3f8k2x10001",
      "name": "logo.png"
    }
  ]
}

Possible error codes

Download a file

GET/api/v1/files/:id/content

Redirects with 302: to a 60-second signed storage URL for private files (supports Range), to the permanent CDN URL for public ones. Your client must follow redirects (-L in curl).

Parameters

NameInTypeRequiredDescription
idpathstringyesFile ID.
versionquerystringnoID of an older version (see version history).
inlinequerystringnoWith 1 the file opens as a browser preview (ignored for types that can run in a browser).

Example request

curl -L -o logo.png "https://cloud104.com/api/v1/files/cm3f8k2x10001/content" \
  -H "Authorization: Bearer sk_..."

Example response

HTTP/1.1 302 Found
Location: https://…  (60 s)

Rename, move, visibility, star

PATCH/api/v1/files/:id

Changes only the fields you send. If both name and folder are given, the item is moved first, then renamed.

Parameters

NameInTypeRequiredDescription
idpathstringyesFile or folder ID.
namebodystringnoNew name.
folderIdbodystringnoID of the folder to move into.
visibilitybodystringnopublic or private.
starredbodybooleannoWhether the item is starred.
expectedRevisionbodyintegernoIf given and the item is not at this revision, 409 revision_conflict.

Example request

curl -X PATCH "https://cloud104.com/api/v1/files/cm3f8k2x10001" \
  -H "Authorization: Bearer sk_..." \
  -H "Content-Type: application/json" \
  -d '{"name":"logo-2026.png","visibility":"private"}'

Example response

{
  "ok": true,
  "id": "cm3f8k2x10001",
  "parentId": "cm3f8k2x10000",
  "name": "logo-2026.png",
  "kind": "file",
  "size": 48213,
  "sha256": "9f2c…",
  "mime": "image/png",
  "visibility": "private",
  "url": null,
  "revision": 1,
  "mtime": "2026-10-28T10:00:00.000Z",
  "source": "api",
  "sourceName": "Blog",
  "starred": false,
  "trashed": false,
  "createdAt": "2026-10-28T10:00:00.000Z",
  "updatedAt": "2026-10-28T10:00:00.000Z"
}

Delete

DELETE/api/v1/files/:id

Moves the item to the trash; a folder goes with its contents. permanent=true deletes permanently (also for items already in the trash). Responds 204.

Parameters

NameInTypeRequiredDescription
idpathstringyesFile or folder ID.
permanentquerybooleannoWith true, delete permanently.

Example request

curl -X DELETE "https://cloud104.com/api/v1/files/cm3f8k2x10001" \
  -H "Authorization: Bearer sk_..."

Example response

HTTP/1.1 204 No Content

Possible error codes

Restore from trash

POST/api/v1/files/:id/restore

Puts the item back where it was; into the root if that folder no longer exists, with a numbered name if the name is taken.

Parameters

NameInTypeRequiredDescription
idpathstringyesID of the trashed item.

Example request

curl -X POST "https://cloud104.com/api/v1/files/cm3f8k2x10001/restore" \
  -H "Authorization: Bearer sk_..."

Example response

{
  "ok": true,
  "id": "cm3f8k2x10001",
  "parentId": "cm3f8k2x10000",
  "name": "logo.png",
  "kind": "file",
  "size": 48213,
  "sha256": "9f2c…",
  "mime": "image/png",
  "visibility": "public",
  "url": "https://cdn.cloud104.com/…/logo.png",
  "revision": 1,
  "mtime": "2026-10-28T10:00:00.000Z",
  "source": "api",
  "sourceName": "Blog",
  "starred": false,
  "trashed": false,
  "createdAt": "2026-10-28T10:00:00.000Z",
  "updatedAt": "2026-10-28T10:00:00.000Z"
}

Possible error codes

Version history

GET/api/v1/files/:id/versions

Returns the file’s versions, newest first (at most 200); the current one has current: true.

Parameters

NameInTypeRequiredDescription
idpathstringyesFile ID.

Example request

curl "https://cloud104.com/api/v1/files/cm3f8k2x10001/versions" \
  -H "Authorization: Bearer sk_..."

Example response

{
  "ok": true,
  "items": [
    {
      "id": "cm3f9v0000002",
      "nodeId": "cm3f8k2x10001",
      "sha256": "9f2c…",
      "size": 48213,
      "source": "api",
      "sourceName": "Blog",
      "deviceId": null,
      "apiKeyId": "cm3a…",
      "createdAt": "2026-10-28T10:00:00.000Z",
      "current": true
    },
    {
      "id": "cm3f9v0000001",
      "nodeId": "cm3f8k2x10001",
      "sha256": "41ab…",
      "size": 51007,
      "source": "web",
      "sourceName": null,
      "deviceId": null,
      "apiKeyId": null,
      "createdAt": "2026-10-20T08:12:00.000Z",
      "current": false
    }
  ]
}

Possible error codes

Restore a version

POST/api/v1/files/:id/versions

Makes the chosen version current. It is added as a new version; no version is deleted.

Parameters

NameInTypeRequiredDescription
idpathstringyesFile ID.
versionIdbodystringyesThe id from the version history.

Example request

curl -X POST "https://cloud104.com/api/v1/files/cm3f8k2x10001/versions" \
  -H "Authorization: Bearer sk_..." \
  -H "Content-Type: application/json" \
  -d '{"versionId":"cm3f9v0000001"}'

Example response

{
  "ok": true,
  "id": "cm3f8k2x10001",
  "parentId": "cm3f8k2x10000",
  "name": "logo.png",
  "kind": "file",
  "size": 51007,
  "sha256": "9f2c…",
  "mime": "image/png",
  "visibility": "public",
  "url": "https://cdn.cloud104.com/…/logo.png",
  "revision": 3,
  "mtime": "2026-10-28T10:00:00.000Z",
  "source": "api",
  "sourceName": "Blog",
  "starred": false,
  "trashed": false,
  "createdAt": "2026-10-28T10:00:00.000Z",
  "updatedAt": "2026-10-28T10:00:00.000Z"
}

Read the public link

GET/api/v1/files/:id/link

Returns the item’s public share link, or link: null. Only the owner can read it.

Parameters

NameInTypeRequiredDescription
idpathstringyesFile or folder ID.

Example request

curl "https://cloud104.com/api/v1/files/cm3f8k2x10001/link" \
  -H "Authorization: Bearer sk_..."

Example response

{
  "ok": true,
  "link": {
    "url": "https://cloud104.com/s/Xk29…",
    "expiresAt": null,
    "allowDownload": true,
    "protected": false,
    "createdAt": "2026-10-28T10:00:00.000Z"
  }
}

Possible error codes

Create or change the public link

PUT/api/v1/files/:id/link

Creates the link if there is none, otherwise changes its settings. Password and expiry are Pro features; on the Free plan 402 needs_pro.

Parameters

NameInTypeRequiredDescription
idpathstringyesFile or folder ID.
passwordbodystring | nullnoPassword, at most 128 characters; null removes it.
expiresAtbodystring | nullnoISO date in the future; null removes the expiry.
allowDownloadbodybooleannoWhether the link allows downloading.

Example request

curl -X PUT "https://cloud104.com/api/v1/files/cm3f8k2x10001/link" \
  -H "Authorization: Bearer sk_..." \
  -H "Content-Type: application/json" \
  -d '{"allowDownload":false}'

Example response

{
  "ok": true,
  "link": {
    "url": "https://cloud104.com/s/Xk29…",
    "expiresAt": null,
    "allowDownload": false,
    "protected": false,
    "createdAt": "2026-10-28T10:00:00.000Z"
  }
}

Close the public link

DELETE/api/v1/files/:id/link

Closes the link; the old URL returns 404 right away. Responds 204.

Parameters

NameInTypeRequiredDescription
idpathstringyesFile or folder ID.

Example request

curl -X DELETE "https://cloud104.com/api/v1/files/cm3f8k2x10001/link" \
  -H "Authorization: Bearer sk_..."

Example response

HTTP/1.1 204 No Content

Possible error codes

People with access

GET/api/v1/files/:id/sharesNeeds the all scope

Returns the people the item is shared with, their roles and whether they accepted the invitation.

Parameters

NameInTypeRequiredDescription
idpathstringyesFile or folder ID.

Example request

curl "https://cloud104.com/api/v1/files/cm3f8k2x10000/shares" \
  -H "Authorization: Bearer sk_..."

Example response

{
  "ok": true,
  "items": [
    {
      "id": "cm3s1h0000001",
      "email": "ayse@example.com",
      "role": "editor",
      "accepted": true,
      "name": "Ayşe",
      "createdAt": "2026-10-28T10:00:00.000Z"
    }
  ]
}

Share with a person

POST/api/v1/files/:id/sharesNeeds the all scope

Grants an email address access as viewer or editor and sends one invitation email. Invitations are also limited to 30 per hour.

Parameters

NameInTypeRequiredDescription
idpathstringyesFile or folder ID.
emailbodystringyesEmail address to invite.
rolebodystringnoviewer (default) or editor.

Example request

curl -X POST "https://cloud104.com/api/v1/files/cm3f8k2x10000/shares" \
  -H "Authorization: Bearer sk_..." \
  -H "Content-Type: application/json" \
  -d '{"email":"ayse@example.com","role":"editor"}'

Example response

{
  "ok": true,
  "id": "cm3s1h0000001",
  "email": "ayse@example.com",
  "role": "editor"
}

Remove a share

DELETE/api/v1/files/:id/sharesNeeds the all scope

Removes the person’s access. Responds 204.

Parameters

NameInTypeRequiredDescription
idpathstringyesFile or folder ID.
shareIdquerystringyesThe id from the people list.

Example request

curl -X DELETE "https://cloud104.com/api/v1/files/cm3f8k2x10000/shares?shareId=cm3s1h0000001" \
  -H "Authorization: Bearer sk_..."

Example response

HTTP/1.1 204 No Content

Create a folder

POST/api/v1/folders

Creates a folder; if a folder with that name already exists it is returned, so re-running a script is safe.

Parameters

NameInTypeRequiredDescription
pathbodystringnoFull path from the account root; intermediate folders are created too.
parentIdbodystringnoParent folder ID (with name); defaults to the root or the key’s locked folder.
namebodystringnoFolder name; required when path is not given.

Example request

curl -X POST "https://cloud104.com/api/v1/folders" \
  -H "Authorization: Bearer sk_..." \
  -H "Content-Type: application/json" \
  -d '{"path":"/apps/blog"}'

Example response

{
  "ok": true,
  "id": "cm3f8k2x10000",
  "parentId": "cm3f8k2x0zzzz",
  "name": "blog",
  "kind": "folder",
  "size": 0,
  "sha256": null,
  "mime": null,
  "visibility": "private",
  "url": null,
  "revision": 1,
  "mtime": "2026-10-28T10:00:00.000Z",
  "source": "api",
  "sourceName": "Blog",
  "starred": false,
  "trashed": false,
  "createdAt": "2026-10-28T10:00:00.000Z",
  "updatedAt": "2026-10-28T10:00:00.000Z"
}

Download as zip

GET/api/v1/zip

Streams the chosen files and folders (folders with their contents) as a single zip; files are stored without compression.

Parameters

NameInTypeRequiredDescription
idsquerystringyesComma-separated IDs, at most 200.

Example request

curl -L -o files.zip "https://cloud104.com/api/v1/zip?ids=cm3f8k2x10001,cm3f8k2x10000" \
  -H "Authorization: Bearer sk_..."

Example response

HTTP/1.1 200 OK
Content-Type: application/zip
Content-Disposition: attachment; filename="cloud104-2026-10-28.zip"

Usage and limits

GET/api/v1/usage

Returns the plan, storage used, quota, the largest file you can upload right now (maxFileSize: the smaller of the plan limit and the space left), the file count and the per-minute request limit. Sizes are in bytes.

Parameters

No parameters.

Example request

curl "https://cloud104.com/api/v1/usage" \
  -H "Authorization: Bearer sk_..."

Example response

{
  "ok": true,
  "plan": "pro",
  "extraGb": 0,
  "used": 52428800,
  "limit": 1073741824,
  "maxFileSize": 1021313024,
  "files": 128,
  "rateLimit": 600,
  "retentionDays": 30
}

Create an upload token

POST/api/v1/upload-tokens

A ten-minute, single-use token for direct browser uploads. Can only be called with an API key; with a session, 403 api_key_required.

Parameters

NameInTypeRequiredDescription
pathbodystringnoFolder path for the upload. Defaults to the key’s locked folder; with an unlocked key the token is not bound to a folder.
maxSizebodyintegernoLargest file size in bytes; cannot exceed the plan limit.
visibilitybodystringnopublic or private (default).

Example request

curl -X POST "https://cloud104.com/api/v1/upload-tokens" \
  -H "Authorization: Bearer sk_..." \
  -H "Content-Type: application/json" \
  -d '{"path":"/apps/blog","maxSize":5000000,"visibility":"public"}'

Example response

{
  "ok": true,
  "token": "ut_…",
  "expiresAt": "2026-10-28T10:10:00.000Z"
}

Trash

GET/api/v1/trashNeeds the all scope

Returns the items that were moved to the trash directly.

Parameters

No parameters.

Example request

curl "https://cloud104.com/api/v1/trash" \
  -H "Authorization: Bearer sk_..."

Example response

{
  "ok": true,
  "items": [
    {
      "id": "cm3f8k2x10001",
      "parentId": "cm3f8k2x10000",
      "name": "logo.png",
      "kind": "file",
      "size": 48213,
      "sha256": "9f2c…",
      "mime": "image/png",
      "visibility": "public",
      "url": "https://cdn.cloud104.com/…/logo.png",
      "revision": 1,
      "mtime": "2026-10-28T10:00:00.000Z",
      "source": "api",
      "sourceName": "Blog",
      "starred": false,
      "trashed": true,
      "createdAt": "2026-10-28T10:00:00.000Z",
      "updatedAt": "2026-10-28T10:00:00.000Z"
    }
  ]
}

Possible error codes

Empty the trash

DELETE/api/v1/trashNeeds the all scope

Permanently deletes everything in the trash; returns the number of deleted items (count) and the space freed (freed, bytes).

Parameters

No parameters.

Example request

curl -X DELETE "https://cloud104.com/api/v1/trash" \
  -H "Authorization: Bearer sk_..."

Example response

{
  "ok": true,
  "count": 12,
  "freed": 3145728
}

Possible error codes

Shared with me

GET/api/v1/sharedNeeds the all scope

Items others shared with you; invitations not yet accepted have accepted: false.

Parameters

No parameters.

Example request

curl "https://cloud104.com/api/v1/shared" \
  -H "Authorization: Bearer sk_..."

Example response

{
  "ok": true,
  "items": [
    {
      "id": "cm3s1h0000002",
      "role": "viewer",
      "accepted": false,
      "owner": "Mehmet",
      "createdAt": "2026-10-28T10:00:00.000Z",
      "node": {
        "id": "cm3f8k2x10000",
        "parentId": "cm3f8k2x0zzzz",
        "name": "blog",
        "kind": "folder",
        "size": 0,
        "sha256": null,
        "mime": null,
        "visibility": "private",
        "url": null,
        "revision": 1,
        "mtime": "2026-10-28T10:00:00.000Z",
        "source": "api",
        "sourceName": "Blog",
        "starred": false,
        "trashed": false,
        "createdAt": "2026-10-28T10:00:00.000Z",
        "updatedAt": "2026-10-28T10:00:00.000Z"
      }
    }
  ]
}

Possible error codes

Accept an invitation

POST/api/v1/shared/:idNeeds the all scope

Accepts a pending share invitation.

Parameters

NameInTypeRequiredDescription
idpathstringyesShare ID (the id from the list).

Example request

curl -X POST "https://cloud104.com/api/v1/shared/cm3s1h0000002" \
  -H "Authorization: Bearer sk_..."

Example response

{
  "ok": true
}

Possible error codes

Add to or remove from My files

PATCH/api/v1/shared/:idNeeds the all scope

added: true shows the share in your own root and syncs it to the desktop; false undoes it.

Parameters

NameInTypeRequiredDescription
idpathstringyesShare ID (the id from the list).
addedbodybooleanyesWhether to add it to your files.

Example request

curl -X PATCH "https://cloud104.com/api/v1/shared/cm3s1h0000002" \
  -H "Authorization: Bearer sk_..." \
  -H "Content-Type: application/json" \
  -d '{"added":true}'

Example response

{
  "ok": true,
  "added": true
}

Decline or leave a share

DELETE/api/v1/shared/:idNeeds the all scope

Removes the share on your side. Responds 204.

Parameters

NameInTypeRequiredDescription
idpathstringyesShare ID (the id from the list).

Example request

curl -X DELETE "https://cloud104.com/api/v1/shared/cm3s1h0000002" \
  -H "Authorization: Bearer sk_..."

Example response

HTTP/1.1 204 No Content

Possible error codes

Public files and CDN URLs

  • A file uploaded with visibility=public, or switched later with PATCH and "visibility": "public", gets a permanent URL under https://cdn.cloud104.com/…. The URL is in the response’s url field; opening it needs no key or session.
  • A private file has url: null; its content is downloaded through GET /api/v1/files/:id/content from a 60-second signed URL.
  • Types that can run in a browser, such as HTML, SVG and JavaScript, are downloaded from the CDN, not opened.

Uploading from the browser

The key never reaches the browser. Your server issues a ten-minute, single-use token; the browser uses it to upload the file straight to cloud104.

Upload token flow
Your server
Browser
cloud104
  1. Your servercloud104Calls POST /api/v1/upload-tokens with the key.
  2. cloud104Your serverReturns { token, expiresAt }.
  3. Your serverBrowserPuts the token in the page or in its own API response.
  4. Browsercloud104Uploads to POST /api/v1/files with Authorization: Upload <token>.

The token’s folder, maximum size and visibility are fixed when it is issued; the browser cannot go beyond them. Token uploads are open to CORS (Access-Control-Allow-Origin: *) and limited to 120 uploads per minute per key.

// Your server:
const r = await fetch('https://cloud104.com/api/v1/upload-tokens', {
  method: 'POST',
  headers: { Authorization: 'Bearer sk_...', 'Content-Type': 'application/json' },
  body: JSON.stringify({ path: '/apps/blog', maxSize: 5_000_000 }),
})
const { token } = await r.json()

// Browser:
await fetch('https://cloud104.com/api/v1/files?name=' + encodeURIComponent(file.name), {
  method: 'POST',
  headers: { Authorization: 'Upload ' + token },
  body: file,
})

Quota and limits

Free: 1 MB total, 1 MB per file, 60 requests per minute. Pro: 1 GB + extra GB, up to 5 GB per file, 600 requests per minute. Requests over the limit get 429 with a Retry-After header.

  • When storage is full you get 413 quota_exceeded; your files are not deleted, only new uploads stop.
  • A multipart form is limited to 100 MB; upload larger files with a raw body (Content-Type: application/octet-stream).
  • For current values, call GET /api/v1/usage.
Compare plans

Rate limit headers

The limit is counted per key over a one-minute window. Every response to a keyed request carries the headers below; over the limit you get 429 rate_limited and Retry-After.

HeaderDescription
X-RateLimit-LimitYour plan’s requests per minute.
X-RateLimit-RemainingRequests left in this window.
X-RateLimit-ResetWhen the window resets (Unix time, seconds).
Retry-AfterOnly on 429: seconds to wait before retrying.

Error codes

Errors come back as { "error": { "code": "<code>", "message": "…" } }; some codes carry extra fields (field, limit, used). code is stable, so branch on it; message is English or Turkish by Accept-Language.

CodeHTTPMeaning
invalid_request400Missing or malformed parameter; the response names it in field.
invalid_name400The name cannot be used (\ / : * ? " < > |, a trailing dot or space, reserved names).
invalid_move400A folder cannot be moved into itself.
not_a_folder400The target, or an item on the path, is not a folder.
not_a_file400The operation only works on files.
unauthorized401No Authorization header.
invalid_key401The key is wrong or deleted.
invalid_upload_token401Upload token is invalid, used or expired.
needs_pro402The feature is on the Pro plan (e.g. a password-protected or expiring link).
insufficient_scope403The key’s scope is not enough; sharing, “shared with me” and trash endpoints need all.
folder_not_allowed403Outside the folder the key is locked to.
forbidden403Not allowed (e.g. writing with a viewer role, deleting the root folder).
api_key_required403The endpoint can only be called with an API key.
not_found404No such item, or no access.
name_conflict409An item with this name exists (onConflict=fail).
revision_conflict409The item is not at the expected revision; read it again and retry.
length_required411Raw body without Content-Length.
file_too_large413The file exceeds the plan’s or the token’s file limit; the response carries limit.
quota_exceeded413Storage is full; the response carries used and limit.
rate_limited429Rate limit exceeded; wait for Retry-After.
storage_unavailable503Storage is unavailable right now; retry a bit later.