Clatter Labs
Console

Code Buckets

Public files

Share stored files with a public link, or keep them private (the default). Images get their own fast host.

Every file in a bucket is private by default: it can only be read with an API key and your Account ID, or in the Console. Make a file public and it gets a link anyone can open.

Public links live on two hosts, picked by what the file is:

FilePublic linkCache
Images (image/*: PNG, JPEG, GIF, WebP, AVIF, SVG, ICO…)https://img.cdn.clatterlabs.xyz/<id>1 year, immutable
Everything else (code, static files, archives, video, PDFs…)https://files.cdn-buckets.clatterlabs.xyz/<object_id>/<name>60 seconds
Text
https://img.cdn.clatterlabs.xyz/V1StGXR8Z5jdHi6BmyT2kq
https://files.cdn-buckets.clatterlabs.xyz/cbo_x4p8t2w6r1k9m3q7n5d0/app.js

Both are served decrypted on our servers, with the right Content-Type, edge caching and ETag. Private files are never served: their links answer 404, the same as a link that doesn't exist. You don't pick the host: public_url in every response is already the right link, and served_as says which kind it is (image or file).

Images: img.cdn.clatterlabs.xyz

  • The link is an opaque id (22 letters and digits), with no file name, bucket or object id in it.
  • A file counts as an image when its upload's content_type is image/*, or, when that was empty or application/octet-stream, when its extension is an image one (.png, .jpg, .jpeg, .gif, .webp, .avif, .svg, .ico, .bmp, .tif, .heic, .jxl).
  • Served with that Content-Type and Cache-Control: public, max-age=31536000, immutable: a stored file never changes, so browsers and CDNs can keep it for a year. Put these links straight into <img> tags, Markdown, emails or OG tags.
  • When an image stops being public, its id is retired for good: the old link answers 404 and keeps doing so, even if you make the image public again (it then gets a new id and a new public_url). Browsers that already loaded the image may still show their cached copy.
  • An older files.cdn-buckets.clatterlabs.xyz link to an image redirects (308) to its image link. Add ?download=1 to download the original from the files host instead.

Files: files.cdn-buckets.clatterlabs.xyz

https://files.cdn-buckets.clatterlabs.xyz/<object_id>/<name>

  • The file name at the end is for people and tools; the object id identifies the file.
  • Content-Type comes from the upload's content_type, or from the file extension when it was application/octet-stream.
  • Opens inline in the browser; add ?download=1 to download it as an attachment.
  • Supports HEAD, single Range requests (206 Partial Content, so large videos and files stream and resume), and ETag / If-None-Match (304).
  • HTML, SVG and XML files are served with a sandboxing Content-Security-Policy, so they can't run scripts on our domain.
  • Cache-Control: public, max-age=60, must-revalidate.

Both hosts allow CORS from any website (Access-Control-Allow-Origin: *).

File or bucket

  • A bucket is private (the default) or public.
  • A file (a stored zip or asset) is inherit (the default: follow the bucket), private or public.

What applies is the file's own setting, or the bucket's when the file is inherit. So you can make one image public in a private bucket, or keep one file private in a public bucket. The response's effective_visibility and public_url always tell you the result.

The code preview tree (the files unpacked from your zips) is never public. To publish a file from your code, upload it as an asset.

Make a file public

curl -X PATCH "https://api.codebuckets.clatterlabs.xyz/v1/buckets/$BUCKET_ID/objects/$OBJECT_ID/visibility" \
  -H "Authorization: Bearer $CLATTER_API_KEY" \
  -H "X-Clatter-Account: $CLATTER_ACCOUNT_ID" \
  -H "Content-Type: application/json" \
  -d '{"visibility": "public"}'
# { "object": "object", "name": "hero.png", "visibility": "public", "effective_visibility": "public",
#   "public_url": "https://img.cdn.clatterlabs.xyz/V1StGXR8Z5jdHi6BmyT2kq", "served_as": "image", ... }
import os, requests

CB = "https://api.codebuckets.clatterlabs.xyz"
H = {"Authorization": f"Bearer {os.environ['CLATTER_API_KEY']}", "X-Clatter-Account": os.environ["CLATTER_ACCOUNT_ID"]}

r = requests.patch(f"{CB}/v1/buckets/{bucket_id}/objects/{object_id}/visibility", headers=H, json={"visibility": "public"})
r.raise_for_status()
print(r.json()["public_url"])  # img.cdn.clatterlabs.xyz/<id> for images, files.cdn-buckets.clatterlabs.xyz/... otherwise
const CB = "https://api.codebuckets.clatterlabs.xyz";
const headers = { Authorization: `Bearer ${process.env.CLATTER_API_KEY}`, "X-Clatter-Account": process.env.CLATTER_ACCOUNT_ID, "Content-Type": "application/json" };

const r = await fetch(`${CB}/v1/buckets/${bucketId}/objects/${objectId}/visibility`, { method: "PATCH", headers, body: JSON.stringify({ visibility: "public" }) });
console.log((await r.json()).public_url);

You can also upload straight to public: pass "visibility": "public" (and the right content_type, like image/png) when you start the upload, and public_url works as soon as the upload completes.

To make a whole bucket public, use Set bucket visibility. Get a public URL returns a file's link at any time, with public telling you whether it works right now.

Make it private again

Send "visibility": "private" (or "inherit" in a private bucket). The link stops working on the next request: every request to the public hosts checks the file's visibility first, and edge-cached parts of a file are only served after that check. An image's id is retired at the same moment (see above). Copies already in someone's browser are out of our reach: up to 60 seconds for files, longer for images, which are cached as immutable.

Deleting a public file also turns its link off.

Events

Every change is in the events feed: object.visibility_changed (with from, to, effective and public_url in data) and bucket.visibility_changed (with from, to and how many files follow the bucket).

Tokens

Changing visibility is a normal request: 1 token. Traffic to your public links (both hosts) is counted for your account at the same rate as API downloads (1 token per request + 1 per MiB sent) and shows in Get usage under storage.public_files.

In the Console

Open a bucket › Uploads & files and pick Public, Private or Bucket default next to a file. Public files show their link with a copy button, and images a thumbnail served from the images host. The bucket's own default is in Settings › Access.