API reference
Every request goes to https://gateway.kuberns.cloud and carries your credential as HTTP Basic authentication. See Use buckets from your application for the basics.
The examples use cURL with two environment variables:
export KUBERNS_ACCESS_KEY_ID="KBS..."
export KUBERNS_SECRET="your-secret-access-key"and a bucket identifier:
export BUCKET="kb-product-assets-3f9a1c2b7d4e"Endpoints
| What | Method and path | Needs |
|---|---|---|
| List buckets | GET /buckets |
Read |
| Create a bucket | POST /buckets |
Read & write |
| Get a bucket | GET /buckets/{bucket} |
Read |
| Delete a bucket | DELETE /buckets/{bucket} |
Read & write |
| Create a folder | POST /buckets/{bucket}/folders |
Read & write |
| Upload a file | PUT /{bucket}/{key} |
Read & write |
| Download a file | GET /{bucket}/{key} |
Read |
| Get a file's details | HEAD /{bucket}/{key} |
Read |
| Delete a file | DELETE /{bucket}/{key} |
Read & write |
| List files | GET /{bucket}/ |
Read |
| Get visibility | GET /buckets/{bucket}/visibility |
Read |
| Set visibility | PUT /buckets/{bucket}/visibility |
Read & write |
| Get a link | POST /buckets/{bucket}/url |
Read |
Needs is the access level the credential must have. {bucket} is the bucket identifier, and {key} is the file's name, such as reports/2026/summary.pdf.
Managing buckets
These endpoints take and return JSON. A successful answer has this shape, and the result is under data:
{
"message": "Bucket created successfully.",
"status": 201,
"data": {}
}List buckets
GET /buckets
Returns every bucket you own, with a summary of your storage.
curl -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" https://gateway.kuberns.cloud/buckets{
"message": "Buckets fetched successfully.",
"status": 200,
"data": {
"buckets": [
{
"bucket": "kb-product-assets-3f9a1c2b7d4e",
"public_id": "05f8ebb3-5e3d-494f-b251-4ef2937f49c9",
"name": "product-assets",
"aws_region": "ap-south-1",
"status": "ACTIVE",
"status_message": null,
"size_bytes": 5242880,
"object_count": 12,
"usage_synced_at": "2026-10-17T07:54:12.778541Z",
"created_at": "2026-10-17T07:54:09.901564Z"
}
],
"summary": {
"used_bytes": 5242880,
"limit_bytes": null,
"bucket_count": 1,
"bucket_limit": 50,
"max_object_size_bytes": 1073741824,
"create_blocked_reason": null
}
}
}| Field | Meaning |
|---|---|
bucket |
The identifier. Use it in every other request. |
name |
The name you chose, as shown in the dashboard. |
status |
ACTIVE when the bucket is ready to use. |
size_bytes, object_count |
Total size and number of files. These are refreshed periodically, so they can lag a recent upload. |
summary.used_bytes |
Total size of all your files. |
summary.limit_bytes |
null, because there is no cap on total storage. |
summary.bucket_count, summary.bucket_limit |
How many buckets you have, and the most you can have. |
summary.max_object_size_bytes |
The largest file the dashboard accepts. |
summary.create_blocked_reason |
null when you can create a bucket. Otherwise the reason you cannot, such as needing a running service. |
Create a bucket
POST /buckets
Creates a bucket. Requires read & write.
| Body field | Description |
|---|---|
name |
3 to 40 characters: lowercase letters, numbers, and hyphens, starting and ending with a letter or number. Must be unique among your buckets. |
curl -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
-X POST https://gateway.kuberns.cloud/buckets \
-H "Content-Type: application/json" \
-d '{"name": "product-assets"}'Answers 201 Created with the bucket under data:
{
"message": "Bucket created successfully.",
"status": 201,
"data": {
"bucket": "kb-product-assets-3f9a1c2b7d4e",
"public_id": "05f8ebb3-5e3d-494f-b251-4ef2937f49c9",
"name": "product-assets",
"aws_region": "ap-south-1",
"status": "ACTIVE",
"status_message": null,
"size_bytes": 0,
"object_count": 0,
"usage_synced_at": "2026-10-17T07:54:12.778541Z",
"created_at": "2026-10-17T07:54:09.901564Z"
}
}Save data.bucket. It is how you refer to this bucket from now on.
Answers 400 when the name is not valid, when you already have a bucket with that name, when your account is in a grace period, or when you have no running service and no bucket yet.
Get a bucket
GET /buckets/{bucket}
curl -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" "https://gateway.kuberns.cloud/buckets/$BUCKET"Answers 200 with the same object that Create a bucket returns, under data. A bucket that does not exist, or belongs to someone else, answers 404.
Delete a bucket
DELETE /buckets/{bucket}
Permanently deletes the bucket and every file in it. There is no restore. Requires read & write.
curl -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
-X DELETE "https://gateway.kuberns.cloud/buckets/$BUCKET"{
"message": "Bucket deleted successfully.",
"status": 200,
"data": {}
}Create a folder
POST /buckets/{bucket}/folders
Creates an empty folder, so that it shows up in the dashboard before it has any files. You do not need to create a folder before uploading into it, because uploading to reports/2026/summary.pdf creates the folders on its own. Requires read & write.
| Body field | Description |
|---|---|
folder_path |
The folder, for example invoices or reports/2026. |
curl -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
-X POST "https://gateway.kuberns.cloud/buckets/$BUCKET/folders" \
-H "Content-Type: application/json" \
-d '{"folder_path": "invoices"}'{
"message": "Folder invoices/ created successfully.",
"status": 201,
"data": {}
}Working with files
These endpoints use the bucket identifier first, then the file's name: /{bucket}/{key}.
Upload a file
PUT /{bucket}/{key}
The request body is the file itself. Requires read & write.
| Header | Description |
|---|---|
Content-Type |
The file's type, such as image/png. Stored with the file and returned when it is downloaded. |
Content-Length |
Set by your HTTP client. Required. |
curl -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
-X PUT "https://gateway.kuberns.cloud/$BUCKET/reports/2026/summary.pdf" \
-H "Content-Type: application/pdf" \
--data-binary @summary.pdf{
"bucket": "kb-product-assets-3f9a1c2b7d4e",
"key": "reports/2026/summary.pdf",
"size": 48213
}Uploading to a name that already exists replaces the file, and the new file is private. Answers 402 when your account is in a grace period and uploads are paused.
Download a file
GET /{bucket}/{key}
Returns the file's bytes, with its Content-Type, Content-Length, ETag, and Last-Modified headers.
curl -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
"https://gateway.kuberns.cloud/$BUCKET/reports/2026/summary.pdf" \
-o summary.pdfA file that does not exist answers 404 with {"error": "That file does not exist."}.
Get a file's details
HEAD /{bucket}/{key}
Returns the same headers as a download, without the file. Use it to check that a file exists or to read its size.
curl -I -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
"https://gateway.kuberns.cloud/$BUCKET/reports/2026/summary.pdf"200 OK
content-type: application/pdf
content-length: 48213
etag: "5d41402abc4b2a76b9719d911017c592"
last-modified: Sat, 17 Oct 2026 07:54:15 GMTDelete a file
DELETE /{bucket}/{key}
Permanently deletes a file. Requires read & write. It answers 204 No Content with an empty body, and the same answer if the file was already gone, so you can safely repeat it.
curl -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
-X DELETE "https://gateway.kuberns.cloud/$BUCKET/reports/2026/summary.pdf"List files
GET /{bucket}/
Lists one level of a bucket: the files and the folders directly inside a path. It does not list everything underneath.
| Query parameter | Description |
|---|---|
prefix |
List inside this folder, for example reports or reports/2026. Leave it out for the top of the bucket. |
limit |
The most entries to return in one page. The default is 100 and the most is 1,000. |
token |
The next_token from the previous page, to continue. |
curl -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
"https://gateway.kuberns.cloud/$BUCKET/?prefix=reports"{
"bucket": "kb-product-assets-3f9a1c2b7d4e",
"prefix": "reports/",
"folders": ["reports/2026/"],
"objects": [],
"next_token": null
}A file looks like this:
{
"key": "logo.png",
"size": 4096,
"etag": "3bdaf5969285188ac756c339f69f5c79",
"last_modified": "2026-10-17T07:54:15Z"
}Paging. When there is more to list, next_token holds a value. Call again with it as token, and repeat until next_token is null. Folders and files can arrive on different pages, and a page can have a null or empty folders or objects, so treat null as empty and keep going until next_token is null.
A token that is not valid answers 400 with {"error": "That page token is not valid."}.
Visibility and links
Get visibility
GET /buckets/{bucket}/visibility?key={key}
Tells you whether a file is public or private, and gives you a link to it.
curl -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
"https://gateway.kuberns.cloud/buckets/$BUCKET/visibility?key=logo.png"{
"message": "Visibility fetched successfully.",
"status": 200,
"data": {
"object_key": "logo.png",
"visibility": "private",
"url": null,
"share_url": "https://buckets.kuberns.cloud/private/kb-product-assets-3f9a1c2b7d4e/logo.png?Expires=1792227857&Signature=...&Key-Pair-Id=...",
"share_expires_at": "2026-10-17T08:04:17.024448+00:00"
}
}| Field | Meaning |
|---|---|
visibility |
public or private. |
url |
The permanent link of a public file. null for a private file. |
share_url |
A temporary link for a private file. null for a public file. |
share_expires_at |
When share_url stops working. |
Set visibility
PUT /buckets/{bucket}/visibility
Makes a file public or private. Requires read & write.
| Body field | Description |
|---|---|
object_key |
The file's name. |
visibility |
public or private. |
curl -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
-X PUT "https://gateway.kuberns.cloud/buckets/$BUCKET/visibility" \
-H "Content-Type: application/json" \
-d '{"object_key": "logo.png", "visibility": "public"}'{
"message": "This file has been made publicly accessible. Anyone with the link can open it.",
"status": 200,
"data": {
"object_key": "logo.png",
"visibility": "public",
"url": "https://buckets.kuberns.cloud/public/kb-product-assets-3f9a1c2b7d4e/logo.png",
"share_url": null,
"share_expires_at": null
}
}Making a file private again returns its share_url instead, and the permanent link stops working within about a minute.
Get a link
POST /buckets/{bucket}/url
Returns one link to a file, the right kind for its state: a permanent link for a public file, and a temporary link for a private one. Use this when you only want a link and do not care which kind it is.
| Body field | Description |
|---|---|
object_key |
The file's name. |
curl -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
-X POST "https://gateway.kuberns.cloud/buckets/$BUCKET/url" \
-H "Content-Type: application/json" \
-d '{"object_key": "logo.png"}'{
"message": "URL generated successfully.",
"status": 200,
"data": {
"bucket": "kb-product-assets-3f9a1c2b7d4e",
"key": "logo.png",
"visibility": "private",
"url": "https://buckets.kuberns.cloud/private/kb-product-assets-3f9a1c2b7d4e/logo.png?Expires=1792227857&Signature=...&Key-Pair-Id=...",
"expires_at": "2026-10-17T08:04:17.619831+00:00"
}
}For a public file, url is the permanent link and expires_at is null. A file that does not exist answers 400 with {"message": "That file does not exist."}.
A read-only credential may call this endpoint, because a link only lets someone read the file.
Errors
Every error uses a standard HTTP status. See Errors and troubleshooting for the full list and what to do about each.