Files API
Use these endpoints to upload, download, delete, and list the files in a bucket. A file is addressed by the bucket identifier and the file's name, called the key: /{bucket}/{key}. The address and the Basic authentication that every request uses are described in Authentication.
Unlike the bucket endpoints, these answer with the file itself or with plain JSON, without the message, status, and data wrapper. An error answer has the form {"error": "..."}. See Response formats.
The examples read your credential from two environment variables. Set them first:
export KUBERNS_ACCESS_KEY_ID="KBS..."
export KUBERNS_SECRET="your-secret-access-key"Upload a file
PUT /{bucket}/{key}
Uploads a file to a bucket. The request body is the file's bytes, with nothing added around them: not JSON, and not a form.
Access: a read & write credential.
Parameters for "Upload a file"
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Authorization |
string | Required | Basic followed by your credential. See Authentication. |
Content-Type |
string | Optional | The file's type, for example application/pdf. It is stored with the file and sent back when the file is downloaded. |
Content-Length |
integer | Required | The size of the body in bytes, at most 5 GB (5,368,709,120 bytes). Your HTTP client sets it when you send bytes or a file. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket |
string | Required | The bucket identifier, for example kb-product-assets-3f9a1c2b7d4e. It is not the bucket's name. |
key |
string | Required | The name to give the file, with its folders, for example reports/2026/summary.pdf. Each slash (/) makes a folder, so you do not need to create the folders first. Names are case-sensitive. Use a name of 900 characters or fewer, with no backslash, no control characters, no //, and no . or .. between slashes. Create a folder, Get visibility, Set visibility, and Get a link answer 400 to a name that breaks these rules, so you could not share such a file. In the address, percent-encode each part of the name and keep the slashes between parts as they are. A space is %20, and a + is a plus sign, not a space. |
HTTP status codes for "Upload a file"
| Status | When it happens |
|---|---|
200 |
The file was uploaded. |
400 |
The address ends with the bucket identifier and a slash, and has no file name: No object key given. |
401 |
The credential is missing or wrong: Your credentials are missing or not valid. |
402 |
Your account is in a grace period because your storage balance is unpaid, so uploads are paused: New uploads are paused because your storage balance is unpaid. Top up your credits to continue. Nothing is uploaded. |
403 |
The credential is read-only: This credential is read-only. |
403 |
The bucket identifier is not one of your active buckets. It may be mistyped, belong to another account, or name a bucket whose status is not ACTIVE: You do not have access to this bucket. |
403 |
The address is the bucket identifier alone, with no slash and no file name: Buckets are managed from the Kuberns dashboard, not through this endpoint. |
411 |
The request has no Content-Length: Content-Length is required. |
413 |
The file is larger than 5 GB. The server in front of the gateway refuses it, so this answer does not use the {"error": "..."} form. |
500 |
Kuberns could not check the credential: Something went wrong. |
502 |
Storage could not complete the upload: The storage backend could not complete that request. |
Code samples for "Upload a file"
Request example
BUCKET="kb-product-assets-3f9a1c2b7d4e"
KEY="reports/2026/summary.pdf"
curl -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
-X PUT "https://gateway.kuberns.cloud/$BUCKET/$KEY" \
-H "Content-Type: application/pdf" \
--data-binary @summary.pdfimport os
from urllib.parse import quote
import requests
BUCKET = "kb-product-assets-3f9a1c2b7d4e"
KEY = "reports/2026/summary.pdf"
with open("summary.pdf", "rb") as file:
response = requests.put(
f"https://gateway.kuberns.cloud/{BUCKET}/{quote(KEY)}",
auth=(os.environ["KUBERNS_ACCESS_KEY_ID"], os.environ["KUBERNS_SECRET"]),
headers={"Content-Type": "application/pdf"},
data=file,
)
response.raise_for_status()
print(response.json()["size"])import { readFile } from "node:fs/promises";
const BUCKET = "kb-product-assets-3f9a1c2b7d4e";
const KEY = "reports/2026/summary.pdf";
const credentials = Buffer.from(
`${process.env.KUBERNS_ACCESS_KEY_ID}:${process.env.KUBERNS_SECRET}`
).toString("base64");
const encodedKey = KEY.split("/").map(encodeURIComponent).join("/");
const response = await fetch(
`https://gateway.kuberns.cloud/${BUCKET}/${encodedKey}`,
{
method: "PUT",
headers: {
Authorization: `Basic ${credentials}`,
"Content-Type": "application/pdf",
},
body: await readFile("summary.pdf"),
}
);
if (!response.ok) {
throw new Error(`Upload failed: ${response.status}`);
}
const body = await response.json();
console.log(body.size);Response
200 OK
{
"bucket": "kb-product-assets-3f9a1c2b7d4e",
"key": "reports/2026/summary.pdf",
"size": 48213
}Warning: Uploading to a name that already exists replaces the file. The new file is private, even if the old one was public. To share it again, set its visibility to
public.
Note: The 5 GB limit is for uploads through the API. The dashboard accepts files up to 1 GB.
Response fields for "Upload a file"
| Field | Type | Description |
|---|---|---|
bucket |
string | The bucket identifier. |
key |
string | The file's name, as it is stored. |
size |
integer | The size of the file in bytes, taken from the Content-Length you sent. |
Download a file
GET /{bucket}/{key}
Downloads a file. The body of the answer is the file's bytes.
Access: a read-only or read & write credential.
Parameters for "Download a file"
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Authorization |
string | Required | Basic followed by your credential. See Authentication. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket |
string | Required | The bucket identifier, for example kb-product-assets-3f9a1c2b7d4e. It is not the bucket's name. |
key |
string | Required | The file's name, with its folders, for example reports/2026/summary.pdf. Names are case-sensitive. Encode the name in the address as described for Upload a file. |
HTTP status codes for "Download a file"
| Status | When it happens |
|---|---|
200 |
The file's bytes are in the body. |
401 |
The credential is missing or wrong: Your credentials are missing or not valid. |
403 |
The bucket identifier is not one of your active buckets. It may be mistyped, belong to another account, or name a bucket whose status is not ACTIVE: You do not have access to this bucket. |
404 |
The bucket has no file with this name: That file does not exist. |
500 |
Kuberns could not check the credential: Something went wrong. |
502 |
Storage could not complete the download: The storage backend could not complete that request. |
Code samples for "Download a file"
Request example
BUCKET="kb-product-assets-3f9a1c2b7d4e"
KEY="reports/2026/summary.pdf"
curl --fail -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
"https://gateway.kuberns.cloud/$BUCKET/$KEY" \
-o summary.pdfimport os
from urllib.parse import quote
import requests
BUCKET = "kb-product-assets-3f9a1c2b7d4e"
KEY = "reports/2026/summary.pdf"
with requests.get(
f"https://gateway.kuberns.cloud/{BUCKET}/{quote(KEY)}",
auth=(os.environ["KUBERNS_ACCESS_KEY_ID"], os.environ["KUBERNS_SECRET"]),
stream=True,
) as response:
response.raise_for_status()
with open("summary.pdf", "wb") as file:
for chunk in response.iter_content(chunk_size=1024 * 1024):
file.write(chunk)
print("Saved summary.pdf")import { createWriteStream } from "node:fs";
import { Readable } from "node:stream";
import { pipeline } from "node:stream/promises";
const BUCKET = "kb-product-assets-3f9a1c2b7d4e";
const KEY = "reports/2026/summary.pdf";
const credentials = Buffer.from(
`${process.env.KUBERNS_ACCESS_KEY_ID}:${process.env.KUBERNS_SECRET}`
).toString("base64");
const encodedKey = KEY.split("/").map(encodeURIComponent).join("/");
const response = await fetch(
`https://gateway.kuberns.cloud/${BUCKET}/${encodedKey}`,
{ headers: { Authorization: `Basic ${credentials}` } }
);
if (!response.ok) {
throw new Error(`Download failed: ${response.status}`);
}
await pipeline(
Readable.fromWeb(response.body),
createWriteStream("summary.pdf")
);
console.log("Saved summary.pdf");Response
200 OK
Content-Type: application/pdf
Content-Length: 48213
ETag: "5d41402abc4b2a76b9719d911017c592"
Last-Modified: Sat, 17 Oct 2026 07:54:15 GMTResponse headers for "Download a file"
| Header | Description |
|---|---|
Content-Type |
The type stored with the file when it was uploaded, for example application/pdf. |
Content-Length |
The size of the file in bytes. |
ETag |
A value that identifies the file's content, in double quotes. It changes when the file is replaced with different content. |
Last-Modified |
When the file was last uploaded or replaced, as an HTTP date in GMT. |
Get a file's details
HEAD /{bucket}/{key}
Returns a file's type, size, and time of last change without downloading the file, which also tells you that the file exists.
Access: a read-only or read & write credential.
Parameters for "Get a file's details"
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Authorization |
string | Required | Basic followed by your credential. See Authentication. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket |
string | Required | The bucket identifier, for example kb-product-assets-3f9a1c2b7d4e. It is not the bucket's name. |
key |
string | Required | The file's name, with its folders, for example reports/2026/summary.pdf. Names are case-sensitive. Encode the name in the address as described for Upload a file. |
HTTP status codes for "Get a file's details"
| Status | When it happens |
|---|---|
200 |
The file exists. Its details are in the headers. |
400 |
The address ends with the bucket identifier and a slash, and has no file name. |
401 |
The credential is missing or wrong. |
403 |
The bucket identifier is not one of your active buckets. It may be mistyped, belong to another account, or name a bucket whose status is not ACTIVE. |
404 |
The bucket has no file with this name. |
500 |
Kuberns could not check the credential. |
502 |
Storage could not complete the request. |
A HEAD answer never has a body, so the error messages that the other endpoints return do not appear here. Only the status tells you what happened.
Code samples for "Get a file's details"
Request example
BUCKET="kb-product-assets-3f9a1c2b7d4e"
KEY="reports/2026/summary.pdf"
curl -I -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
"https://gateway.kuberns.cloud/$BUCKET/$KEY"import os
from urllib.parse import quote
import requests
BUCKET = "kb-product-assets-3f9a1c2b7d4e"
KEY = "reports/2026/summary.pdf"
response = requests.head(
f"https://gateway.kuberns.cloud/{BUCKET}/{quote(KEY)}",
auth=(os.environ["KUBERNS_ACCESS_KEY_ID"], os.environ["KUBERNS_SECRET"]),
)
response.raise_for_status()
print(response.headers["Content-Length"])const BUCKET = "kb-product-assets-3f9a1c2b7d4e";
const KEY = "reports/2026/summary.pdf";
const credentials = Buffer.from(
`${process.env.KUBERNS_ACCESS_KEY_ID}:${process.env.KUBERNS_SECRET}`
).toString("base64");
const encodedKey = KEY.split("/").map(encodeURIComponent).join("/");
const response = await fetch(
`https://gateway.kuberns.cloud/${BUCKET}/${encodedKey}`,
{ method: "HEAD", headers: { Authorization: `Basic ${credentials}` } }
);
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
console.log(response.headers.get("content-length"));Response
200 OK
Content-Type: application/pdf
Content-Length: 48213
ETag: "5d41402abc4b2a76b9719d911017c592"
Last-Modified: Sat, 17 Oct 2026 07:54:15 GMTResponse headers for "Get a file's details"
| Header | Description |
|---|---|
Content-Type |
The type stored with the file when it was uploaded, for example application/pdf. |
Content-Length |
The size of the file in bytes. |
ETag |
A value that identifies the file's content, in double quotes. It changes when the file is replaced with different content. |
Last-Modified |
When the file was last uploaded or replaced, as an HTTP date in GMT. |
Delete a file
DELETE /{bucket}/{key}
Deletes a file permanently.
Access: a read & write credential.
Parameters for "Delete a file"
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Authorization |
string | Required | Basic followed by your credential. See Authentication. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket |
string | Required | The bucket identifier, for example kb-product-assets-3f9a1c2b7d4e. It is not the bucket's name. |
key |
string | Required | The file's name, with its folders, for example reports/2026/summary.pdf. Names are case-sensitive. Encode the name in the address as described for Upload a file. |
HTTP status codes for "Delete a file"
| Status | When it happens |
|---|---|
204 |
The file was deleted, or there was no file with this name. Both get the same answer, so you can repeat the request safely. |
400 |
The address ends with the bucket identifier and a slash, and has no file name: No object key given. |
401 |
The credential is missing or wrong: Your credentials are missing or not valid. |
403 |
The credential is read-only: This credential is read-only. |
403 |
The bucket identifier is not one of your active buckets. It may be mistyped, belong to another account, or name a bucket whose status is not ACTIVE: You do not have access to this bucket. |
403 |
The address is the bucket identifier alone, with no slash and no file name: Buckets are managed from the Kuberns dashboard, not through this endpoint. |
500 |
Kuberns could not check the credential: Something went wrong. |
502 |
Storage could not complete the delete: The storage backend could not complete that request. |
Code samples for "Delete a file"
Request example
BUCKET="kb-product-assets-3f9a1c2b7d4e"
KEY="reports/2026/summary.pdf"
curl -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
-X DELETE "https://gateway.kuberns.cloud/$BUCKET/$KEY" \
-w "%{http_code}\n"import os
from urllib.parse import quote
import requests
BUCKET = "kb-product-assets-3f9a1c2b7d4e"
KEY = "reports/2026/summary.pdf"
response = requests.delete(
f"https://gateway.kuberns.cloud/{BUCKET}/{quote(KEY)}",
auth=(os.environ["KUBERNS_ACCESS_KEY_ID"], os.environ["KUBERNS_SECRET"]),
)
response.raise_for_status()
print(response.status_code)const BUCKET = "kb-product-assets-3f9a1c2b7d4e";
const KEY = "reports/2026/summary.pdf";
const credentials = Buffer.from(
`${process.env.KUBERNS_ACCESS_KEY_ID}:${process.env.KUBERNS_SECRET}`
).toString("base64");
const encodedKey = KEY.split("/").map(encodeURIComponent).join("/");
const response = await fetch(
`https://gateway.kuberns.cloud/${BUCKET}/${encodedKey}`,
{ method: "DELETE", headers: { Authorization: `Basic ${credentials}` } }
);
if (!response.ok) {
throw new Error(`Delete failed: ${response.status}`);
}
console.log(response.status);Response
204 No Content
Response headers for "Delete a file"
The body is empty, and the answer has no headers you need to read.
List files
GET /{bucket}/
Lists the files and folders directly inside a folder of a bucket, one level at a time. It does not list what is inside the folders it returns.
Access: a read-only or read & write credential.
Parameters for "List files"
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Authorization |
string | Required | Basic followed by your credential. See Authentication. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket |
string | Required | The bucket identifier, for example kb-product-assets-3f9a1c2b7d4e. It is not the bucket's name. Keep the slash after it. |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
folder |
string | Optional | The folder to list, for example reports or reports/2026. A / is added at the end if you leave it off. Leave it out to list the top of the bucket. |
limit |
integer | Optional | The most entries to return in one page. Files and folders count together. Default: 100. The most is 1000: a larger number is lowered to 1000. A value that is not a whole number, or is less than 1, is ignored and the default is used. |
page |
string | Optional | The next_page of the previous answer, to get the next page. It is not a page number. Send it exactly as you received it. It can contain /, +, and =, so let your HTTP client encode it as a query parameter. Leave it out for the first page. |
HTTP status codes for "List files"
| Status | When it happens |
|---|---|
200 |
The page is in the body. A bucket with no files answers 200 too. |
400 |
page is not valid: That page is not valid. Use the next_page value from the previous response. |
401 |
The credential is missing or wrong: Your credentials are missing or not valid. |
403 |
The bucket identifier is not one of your active buckets. It may be mistyped, belong to another account, or name a bucket whose status is not ACTIVE: You do not have access to this bucket. |
500 |
Kuberns could not check the credential: Something went wrong. |
502 |
Storage could not complete the listing: The storage backend could not complete that request. |
Code samples for "List files"
Request example
BUCKET="kb-product-assets-3f9a1c2b7d4e"
curl -G -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
"https://gateway.kuberns.cloud/$BUCKET/" \
--data-urlencode "limit=2"import os
import requests
BUCKET = "kb-product-assets-3f9a1c2b7d4e"
response = requests.get(
f"https://gateway.kuberns.cloud/{BUCKET}/",
auth=(os.environ["KUBERNS_ACCESS_KEY_ID"], os.environ["KUBERNS_SECRET"]),
params={"limit": 2},
)
response.raise_for_status()
answer = response.json()
for folder in answer["folders"]:
print(folder)
for file in answer["objects"]:
print(file["key"], file["size"])
print("has_next:", answer["has_next"])
print("next_page:", answer["next_page"])const BUCKET = "kb-product-assets-3f9a1c2b7d4e";
const credentials = Buffer.from(
`${process.env.KUBERNS_ACCESS_KEY_ID}:${process.env.KUBERNS_SECRET}`
).toString("base64");
const params = new URLSearchParams({ limit: "2" });
const response = await fetch(
`https://gateway.kuberns.cloud/${BUCKET}/?${params}`,
{ headers: { Authorization: `Basic ${credentials}` } }
);
if (!response.ok) {
throw new Error(`List files failed with status ${response.status}`);
}
const answer = await response.json();
for (const folder of answer.folders) {
console.log(folder);
}
for (const file of answer.objects) {
console.log(file.key, file.size);
}
console.log("has_next:", answer.has_next);
console.log("next_page:", answer.next_page);These samples ask for 2 entries at a time, so that the paging keys show up in the answer. Leave limit out to get up to 100 entries a page.
Response
200 OK
{
"bucket": "kb-product-assets-3f9a1c2b7d4e",
"folder": "",
"folders": [
"invoices/"
],
"has_next": true,
"next_page": "1YsArNwnJgeAHhJPrz0DUmetRWnV9BHKt/RrOEl0yGjnZF0ZT60PMw6nGL9Skqm0SJw8Hsd0vAvQ=",
"objects": [
{
"etag": "3bdaf5969285188ac756c339f69f5c79",
"key": "logo.png",
"last_modified": "2026-10-17T07:54:15Z",
"size": 4
}
]
}Note: This is the first of two pages. The bucket holds
invoices/,logo.png,notes.txt, andreports/, and the request asked for 2 entries.has_nextistrue, so there is more, andnext_pageis what you send to get it. The answer also repeatsfolderandnext_pageasprefixandnext_token, the names the first version of the API used. Those names, andprefixandtokenin the request, still work, but use the new names in new code.
The paging keys
| Key | Where | Example | What it means |
|---|---|---|---|
limit |
In your request | 2 |
How many entries you want on this page. Files and folders count together. |
folder |
In your request | reports/2026 |
Which folder to list. Leave it out for the top of the bucket. |
page |
In your request | The next_page of the previous answer |
Which page to return. Leave it out for the first page. It is not a page number. |
has_next |
In the answer | true |
true when there is another page after this one. false on the last page. |
next_page |
In the answer | "1YsArNwn..." |
What to send as page to get the next page. null on the last page. |
Get the next page
Send next_page back as page, with the same folder and limit. These samples ask for the first page and then for the second. The cURL sample needs jq.
BUCKET="kb-product-assets-3f9a1c2b7d4e"
FIRST=$(curl -s -G -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
"https://gateway.kuberns.cloud/$BUCKET/" \
--data-urlencode "limit=2")
PAGE=$(echo "$FIRST" | jq -r '.next_page')
curl -G -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
"https://gateway.kuberns.cloud/$BUCKET/" \
--data-urlencode "limit=2" \
--data-urlencode "page=$PAGE"import os
import requests
BUCKET = "kb-product-assets-3f9a1c2b7d4e"
def list_page(page=None):
params = {"limit": 2}
if page:
params["page"] = page
response = requests.get(
f"https://gateway.kuberns.cloud/{BUCKET}/",
auth=(os.environ["KUBERNS_ACCESS_KEY_ID"], os.environ["KUBERNS_SECRET"]),
params=params,
)
response.raise_for_status()
return response.json()
first = list_page()
second = list_page(first["next_page"])
for folder in second["folders"]:
print(folder)
for file in second["objects"]:
print(file["key"], file["size"])
print("has_next:", second["has_next"])const BUCKET = "kb-product-assets-3f9a1c2b7d4e";
const credentials = Buffer.from(
`${process.env.KUBERNS_ACCESS_KEY_ID}:${process.env.KUBERNS_SECRET}`
).toString("base64");
async function listPage(page) {
const params = new URLSearchParams({ limit: "2" });
if (page) {
params.set("page", page);
}
const response = await fetch(
`https://gateway.kuberns.cloud/${BUCKET}/?${params}`,
{ headers: { Authorization: `Basic ${credentials}` } }
);
if (!response.ok) {
throw new Error(`List files failed with status ${response.status}`);
}
return response.json();
}
const first = await listPage();
const second = await listPage(first.next_page);
for (const folder of second.folders) {
console.log(folder);
}
for (const file of second.objects) {
console.log(file.key, file.size);
}
console.log("has_next:", second.has_next);The second answer has the rest. has_next is false and next_page is null, so this was the last page:
{
"bucket": "kb-product-assets-3f9a1c2b7d4e",
"folder": "",
"folders": [
"reports/"
],
"has_next": false,
"next_page": null,
"objects": [
{
"etag": "4358b5009c67d0e31d7fbf1663fcd3bf",
"key": "notes.txt",
"last_modified": "2026-10-17T07:54:15Z",
"size": 5
}
]
}These samples assume the first answer has has_next set to true. To handle any number of pages, use the loop below. See Pagination for more.
Read every page
These samples read every page of one folder and print the name of every file. The cURL sample needs jq.
BUCKET="kb-product-assets-3f9a1c2b7d4e"
FOLDER="reports"
PAGE=""
while true; do
ANSWER=$(curl -s -G -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
"https://gateway.kuberns.cloud/$BUCKET/" \
--data-urlencode "folder=$FOLDER" \
--data-urlencode "limit=100" \
--data-urlencode "page=$PAGE")
echo "$ANSWER" | jq -r '.objects[].key'
[ "$(echo "$ANSWER" | jq -r '.has_next')" = "true" ] || break
PAGE=$(echo "$ANSWER" | jq -r '.next_page')
doneimport os
import requests
BUCKET = "kb-product-assets-3f9a1c2b7d4e"
FOLDER = "reports"
page = None
while True:
params = {"folder": FOLDER, "limit": 100}
if page:
params["page"] = page
response = requests.get(
f"https://gateway.kuberns.cloud/{BUCKET}/",
auth=(os.environ["KUBERNS_ACCESS_KEY_ID"], os.environ["KUBERNS_SECRET"]),
params=params,
)
response.raise_for_status()
answer = response.json()
for file in answer["objects"]:
print(file["key"])
if not answer["has_next"]:
break
page = answer["next_page"]const BUCKET = "kb-product-assets-3f9a1c2b7d4e";
const FOLDER = "reports";
const credentials = Buffer.from(
`${process.env.KUBERNS_ACCESS_KEY_ID}:${process.env.KUBERNS_SECRET}`
).toString("base64");
let page = null;
while (true) {
const params = new URLSearchParams({ folder: FOLDER, limit: "100" });
if (page) {
params.set("page", page);
}
const response = await fetch(
`https://gateway.kuberns.cloud/${BUCKET}/?${params}`,
{ headers: { Authorization: `Basic ${credentials}` } }
);
if (!response.ok) {
throw new Error(`List files failed with status ${response.status}`);
}
const answer = await response.json();
for (const file of answer.objects) {
console.log(file.key);
}
if (!answer.has_next) break;
page = answer.next_page;
}To read the folders too, collect answer.folders on every page. To list the top of the bucket, leave folder out or set it to an empty string.
Response fields for "List files"
| Field | Type | Description |
|---|---|---|
bucket |
string | The bucket identifier. |
folder |
string | The folder that was listed. It ends with /, or is an empty string for the top of the bucket. |
folders |
array of strings | The folders directly inside folder, each as a full path that ends with /, such as reports/2026/. An empty array when this page has none. |
objects |
array of objects | The files directly inside folder. An empty array when this page has none. |
objects[].key |
string | The file's full name, including its folders. |
objects[].size |
integer | The size of the file in bytes. |
objects[].etag |
string | A value that identifies the file's content. It is the ETag header of a download, without the double quotes. |
objects[].last_modified |
string | When the file was last uploaded or replaced, as an ISO 8601 time in UTC. |
has_next |
boolean | true when there is another page after this one. false on the last page. |
next_page |
string or null | Send it as page to get the next page. null on the last page. |