Sharing API
A file in a bucket is private until you make it public. A public file has a permanent link that anyone can open. A private file has no permanent link, but you can give it a temporary one. Share files and links explains these ideas. Use the endpoints on this page to read and change a file's visibility and to get a link to it.
Every request goes to https://gateway.kuberns.cloud and carries your credential as HTTP Basic authentication. See Authentication for the address and the header.
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"Get visibility
GET /buckets/{bucket}/visibility?key={key}
Returns whether a file is public or private, with a link to it. A public file has a permanent link in url. A private file has a temporary link in share_url, which opens in any browser without a credential and works for 10 minutes.
Access: a read-only or read & write credential.
Parameters for "Get visibility"
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. |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
key |
string | Required | The file's name, including its folder, for example reports/2026/summary.pdf. Names are case-sensitive. Surrounding spaces and a leading / are removed. It can be up to 900 characters. It cannot end with /, and it cannot contain //, a backslash, a control character, or a . or .. part. |
HTTP status codes for "Get visibility"
| Status | When it happens |
|---|---|
200 |
The answer describes the file. |
400 |
key is missing, or is not a usable file name, for example because it ends with /: That file path is not allowed. |
400 |
The file does not exist: That file does not exist. This is a 400, not the 404 that Download a file answers. |
400 |
Storage could not complete the request. You can try again: Something went wrong. Please try again. |
401 |
The credential is missing or wrong: Your credentials are missing or not valid. |
403 |
Your account is on a free trial, and storage buckets are for paid plans: Storage buckets are available on paid plans. This answer has the validation error format, not the usual one. |
404 |
The bucket does not exist, or it belongs to someone else: Bucket not found. |
Code samples for "Get visibility"
Request example
BUCKET="kb-product-assets-3f9a1c2b7d4e"
KEY="reports/2026/summary.pdf"
curl -G -u "$KUBERNS_ACCESS_KEY_ID:$KUBERNS_SECRET" \
"https://gateway.kuberns.cloud/buckets/$BUCKET/visibility" \
--data-urlencode "key=$KEY"import os
import requests
BUCKET = "kb-product-assets-3f9a1c2b7d4e"
KEY = "reports/2026/summary.pdf"
response = requests.get(
f"https://gateway.kuberns.cloud/buckets/{BUCKET}/visibility",
auth=(os.environ["KUBERNS_ACCESS_KEY_ID"], os.environ["KUBERNS_SECRET"]),
params={"key": KEY},
)
response.raise_for_status()
data = response.json()["data"]
print(data["visibility"])
print(data["url"] or data["share_url"])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 query = new URLSearchParams({ key: KEY });
const response = await fetch(
`https://gateway.kuberns.cloud/buckets/${BUCKET}/visibility?${query}`,
{ headers: { Authorization: `Basic ${credentials}` } }
);
const body = await response.json();
console.log(body.data.visibility);
console.log(body.data.url ?? body.data.share_url);Response
200 OK
{
"message": "Visibility fetched successfully.",
"status": 200,
"data": {
"object_key": "reports/2026/summary.pdf",
"visibility": "private",
"url": null,
"share_url": "https://buckets.kuberns.cloud/private/kb-product-assets-3f9a1c2b7d4e/reports/2026/summary.pdf?Expires=<unix-time>&Signature=<signature>&Key-Pair-Id=<key-pair-id>",
"share_expires_at": "2026-10-17T08:04:17.024448+00:00"
}
}Note: This example is a private file. For a public file,
visibilityispublic,urlis its permanent link, andshare_urlandshare_expires_atarenull.
Response fields for "Get visibility"
| Field | Type | Description |
|---|---|---|
message |
string | A short sentence describing the result. |
status |
integer | The HTTP status code, repeated in the body. |
data |
object | The file's visibility and its link. |
data.object_key |
string | The file's name, with surrounding spaces and a leading / removed. |
data.visibility |
string | Whether the file is public or private. Can be one of: public, private. |
data.url |
string or null | The permanent link of a public file. It does not expire. null for a private file, which has no permanent link. Characters in the name that an address cannot hold, such as spaces, are percent-encoded. |
data.share_url |
string or null | A temporary link to a private file. null for a public file, and also when the service cannot create temporary links. |
data.share_expires_at |
string or null | When share_url stops working, as an ISO 8601 time in UTC. null when share_url is null. |
Set visibility
PUT /buckets/{bucket}/visibility
Makes a file public or private. Making a file private answers with a temporary link in share_url, and the file's permanent link stops working within about a minute.
Access: a read & write credential.
Parameters for "Set visibility"
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Authorization |
string | Required | Basic followed by your credential. See Authentication. |
Content-Type |
string | Optional | Send application/json. The gateway does not check this header. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket |
string | Required | The bucket identifier, for example kb-product-assets-3f9a1c2b7d4e. |
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
object_key |
string | Required | The file's name, including its folder, for example reports/2026/summary.pdf. Names are case-sensitive. Surrounding spaces and a leading / are removed. It can be up to 900 characters. It cannot end with /, and it cannot contain //, a backslash, a control character, or a . or .. part. |
visibility |
string | Required | The visibility the file should have. Can be one of: public, private. |
HTTP status codes for "Set visibility"
| Status | When it happens |
|---|---|
200 |
The file now has the visibility you asked for. It also answers 200 when the file already had it. |
400 |
object_key or visibility is missing or not valid. The message names the field, for example This field is required. or "nonsense" is not a valid choice. This answer has the validation error format, not the usual one. |
400 |
object_key is not a usable file name, for example because it ends with /: That file path is not allowed. |
400 |
The file does not exist: That file does not exist. This is a 400, not the 404 that Download a file answers. |
400 |
Storage could not complete the request. You can try again: Something went wrong. Please try again. |
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 |
Your account is on a free trial, and storage buckets are for paid plans: Storage buckets are available on paid plans. This answer has the validation error format, not the usual one. |
404 |
The bucket does not exist, or it belongs to someone else: Bucket not found. |
Code samples for "Set visibility"
Request example
BUCKET="kb-product-assets-3f9a1c2b7d4e"
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": "reports/2026/summary.pdf", "visibility": "public"}'import os
import requests
BUCKET = "kb-product-assets-3f9a1c2b7d4e"
KEY = "reports/2026/summary.pdf"
response = requests.put(
f"https://gateway.kuberns.cloud/buckets/{BUCKET}/visibility",
auth=(os.environ["KUBERNS_ACCESS_KEY_ID"], os.environ["KUBERNS_SECRET"]),
json={"object_key": KEY, "visibility": "public"},
)
response.raise_for_status()
print(response.json()["data"]["url"])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 response = await fetch(
`https://gateway.kuberns.cloud/buckets/${BUCKET}/visibility`,
{
method: "PUT",
headers: {
Authorization: `Basic ${credentials}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ object_key: KEY, visibility: "public" }),
}
);
const body = await response.json();
console.log(body.data.url);Response
200 OK
{
"message": "This file has been made publicly accessible. Anyone with the link can open it.",
"status": 200,
"data": {
"object_key": "reports/2026/summary.pdf",
"visibility": "public",
"url": "https://buckets.kuberns.cloud/public/kb-product-assets-3f9a1c2b7d4e/reports/2026/summary.pdf",
"share_url": null,
"share_expires_at": null
}
}Warning: Uploading a file to a name that already exists replaces it, and the new file is private, even if the file it replaced was public. After you upload over a public file, call this endpoint again to make it public.
Response fields for "Set visibility"
| Field | Type | Description |
|---|---|---|
message |
string | A short sentence describing the result. |
status |
integer | The HTTP status code, repeated in the body. |
data |
object | The file's new visibility and its link. |
data.object_key |
string | The file's name, with surrounding spaces and a leading / removed. |
data.visibility |
string | The visibility the file now has. Can be one of: public, private. |
data.url |
string or null | The permanent link, when the file is now public. It does not expire. null when the file is now private. Characters in the name that an address cannot hold, such as spaces, are percent-encoded. |
data.share_url |
string or null | A temporary link, when the file is now private. It works for 10 minutes. null when the file is now public, and also when the service cannot create temporary links. |
data.share_expires_at |
string or null | When share_url stops working, as an ISO 8601 time in UTC. null when share_url is null. |
Get a link
POST /buckets/{bucket}/url
Returns one link to a file, of the kind that fits its state: a permanent link for a public file, and a temporary link for a private one. Use it when you want a link and do not need to know which kind it is. A temporary link opens in any browser without a credential and works for 10 minutes. A read-only credential can call this endpoint, because a link only lets someone read the file.
Access: a read-only or read & write credential.
Parameters for "Get a link"
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Authorization |
string | Required | Basic followed by your credential. See Authentication. |
Content-Type |
string | Optional | Send application/json. The gateway does not check this header. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
bucket |
string | Required | The bucket identifier, for example kb-product-assets-3f9a1c2b7d4e. |
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
object_key |
string | Required | The file's name, including its folder, for example reports/2026/summary.pdf. Names are case-sensitive. Surrounding spaces and a leading / are removed. It can be up to 900 characters. It cannot end with /, and it cannot contain //, a backslash, a control character, or a . or .. part. |
HTTP status codes for "Get a link"
| Status | When it happens |
|---|---|
200 |
The answer holds a link to the file. |
400 |
object_key is missing or not valid. The message names the field, for example This field is required. This answer has the validation error format, not the usual one. |
400 |
object_key is not a usable file name, for example because it ends with /: That file path is not allowed. |
400 |
The file does not exist: That file does not exist. This is a 400, not the 404 that Download a file answers. |
400 |
The file is private and the service cannot create temporary links: Signed links are not configured on this environment. |
400 |
Storage could not complete the request. You can try again: Something went wrong. Please try again. |
401 |
The credential is missing or wrong: Your credentials are missing or not valid. |
403 |
Your account is on a free trial, and storage buckets are for paid plans: Storage buckets are available on paid plans. This answer has the validation error format, not the usual one. |
404 |
The bucket does not exist, or it belongs to someone else: Bucket not found. |
Code samples for "Get a link"
Request example
BUCKET="kb-product-assets-3f9a1c2b7d4e"
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": "reports/2026/summary.pdf"}'import os
import requests
BUCKET = "kb-product-assets-3f9a1c2b7d4e"
KEY = "reports/2026/summary.pdf"
response = requests.post(
f"https://gateway.kuberns.cloud/buckets/{BUCKET}/url",
auth=(os.environ["KUBERNS_ACCESS_KEY_ID"], os.environ["KUBERNS_SECRET"]),
json={"object_key": KEY},
)
response.raise_for_status()
print(response.json()["data"]["url"])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 response = await fetch(
`https://gateway.kuberns.cloud/buckets/${BUCKET}/url`,
{
method: "POST",
headers: {
Authorization: `Basic ${credentials}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ object_key: KEY }),
}
);
const body = await response.json();
console.log(body.data.url);Response
200 OK
{
"message": "URL generated successfully.",
"status": 200,
"data": {
"bucket": "kb-product-assets-3f9a1c2b7d4e",
"key": "reports/2026/summary.pdf",
"visibility": "private",
"url": "https://buckets.kuberns.cloud/private/kb-product-assets-3f9a1c2b7d4e/reports/2026/summary.pdf?Expires=<unix-time>&Signature=<signature>&Key-Pair-Id=<key-pair-id>",
"expires_at": "2026-10-17T08:04:17.619831+00:00"
}
}Note: This example is a private file. For a public file,
visibilityispublic,urlis its permanent link, andexpires_atisnull.
Warning: A file that does not exist answers
400here, with the messageThat file does not exist.Download a file and Get a file's details answer404for the same reason.
Response fields for "Get a link"
| Field | Type | Description |
|---|---|---|
message |
string | A short sentence describing the result. |
status |
integer | The HTTP status code, repeated in the body. |
data |
object | The link and the file it opens. |
data.bucket |
string | The bucket identifier. |
data.key |
string | The file's name, with surrounding spaces and a leading / removed. |
data.visibility |
string | Whether the file is public or private. Can be one of: public, private. |
data.url |
string | The link. For a public file it is the permanent link, which does not expire. For a private file it is a temporary link. Characters in the name that an address cannot hold, such as spaces, are percent-encoded. |
data.expires_at |
string or null | When a temporary link stops working, as an ISO 8601 time in UTC. null for a public file. |