Freeshka

Documentation

Everything the API does, on one page. The base URL is https://app.freeshka.org/v1.

Authentication

All requests take a bearer token. Tokens are created per project and can be scoped to a single bucket or to a key prefix.

curl https://app.freeshka.org/v1/buckets \
  -H "Authorization: Bearer $FREESHKA_TOKEN"

A token that is missing, malformed or expired returns 401. A valid token that lacks permission for the target key returns 403.

Buckets

MethodPathDescription
GET/v1/bucketsList buckets in the project.
POST/v1/bucketsCreate a bucket. Body takes name and region.
GET/v1/buckets/{bucket}Bucket metadata: size, object count, region, visibility.
DELETE/v1/buckets/{bucket}Delete an empty bucket.

Bucket names are 3–48 characters, lowercase letters, digits and hyphens. Region is ams or fra and cannot be changed later.

Objects

MethodPathDescription
PUT/v1/buckets/{bucket}/{key}Upload or replace an object.
GET/v1/buckets/{bucket}/{key}Download an object. Supports Range.
HEAD/v1/buckets/{bucket}/{key}Metadata only: size, content type, etag.
DELETE/v1/buckets/{bucket}/{key}Delete an object or a specific version.
GET/v1/buckets/{bucket}?prefix=List keys, paginated with cursor.

Multipart uploads

Files above 64 MB should be uploaded in parts. Start a session, send the parts in any order, then commit.

POST /v1/buckets/assets/video.mp4?uploads
  -> { "upload_id": "u_7Rk2ZP" }

PUT  /v1/buckets/assets/video.mp4?upload_id=u_7Rk2ZP&part=1
PUT  /v1/buckets/assets/video.mp4?upload_id=u_7Rk2ZP&part=2

POST /v1/buckets/assets/video.mp4?upload_id=u_7Rk2ZP&commit
  -> { "etag": "b1946ac92492d2347c6235b4d2611184", "parts": 2 }

Parts are 5 MB minimum except the last one. An upload session that is not committed within 24 hours is discarded and its parts are billed to nobody.

Signed URLs

Private objects can be shared with a time-limited link. The signature covers the method, the key and the expiry.

POST /v1/buckets/assets/report.pdf?sign
Content-Type: application/json

{ "expires_in": 3600, "method": "GET" }

{
  "url": "https://cdn.freeshka.org/assets/report.pdf?exp=1789531200&sig=KqvP...",
  "expires_at": "2026-09-21T11:20:00Z"
}

Optional fields: ip pins the link to one address, referrer restricts it to a hostname. Expired links return 410.

S3 compatibility

The same buckets are reachable over the S3 protocol at https://s3.freeshka.org with signature v4. Set the region to the bucket region and disable virtual-host addressing.

aws --endpoint-url https://s3.freeshka.org \
    --region ams \
    s3 cp ./report.pdf s3://assets/report.pdf

Supported: bucket and object CRUD, multipart, list v2, copy, conditional headers. Not supported: ACLs, bucket policies, lifecycle rules, website hosting, requester-pays.

Errors

StatusCodeMeaning
400invalid_requestMalformed body, bad bucket name or unsupported parameter.
401unauthorizedToken missing, malformed or expired.
403forbiddenToken is valid but not scoped to this key.
404not_foundBucket or key does not exist.
409conflictBucket name taken, or delete attempted on a non-empty bucket.
413too_largeSingle-request upload above 64 MB. Use multipart.
429slow_downBurst limit reached. Retry after the Retry-After header.
503unavailableRegion is failing over. Retries are safe.

Errors are returned as JSON with code, message and a request_id. Quote the request id when reporting a problem.

Limits