Image transforms
Serve a resized, re-encoded, or blurred version of a stored image straight from its URL. Transforms run under the same Row-Level Security as a normal Storage read, and every derivative is cached.
Endpoints
The render routes mirror the storage download routes — the bucket and object key are path segments, and the transform is given in the query string:
public serves objects from public buckets with no key (the
bucket's public-read policy is the authorization); authenticated
takes a bearer key or user token and resolves the object under that caller's
RLS; sign serves a transform baked into a
signed URL. A transform can never widen access — an
object you could not download, you cannot render.
# a 400px-wide WebP thumbnail of a public avatar
https://<ref>.kethosbase.com/storage/v1/render/image/public/avatars/alice.png?width=400&format=webp
# authenticated: send the key/token as usual
curl "https://<ref>.kethosbase.com/storage/v1/render/image/authenticated/photos/2026/trip.jpg?width=800&height=800&resize=cover" \
-H "Authorization: Bearer <key>"
Transform parameters
| Parameter | Values | Default |
|---|---|---|
width | pixels, up to 4096 (over is clamped) | from height / source aspect |
height | pixels, up to 4096 (over is clamped) | from width / source aspect |
resize | contain (fit, no crop) · cover (fill, centre-crop) · fill (stretch) | contain |
format | origin · jpeg · png · webp · avif | origin (keep source type) |
quality | 1–100 (ignored for PNG) | 80 |
blur | 0–100 (Gaussian radius) | 0 (none) |
A bad value (a negative dimension, quality outside 1–100, an
unknown resize or format) answers 400.
A request that asks for no change streams the original bytes unchanged.
Caching, quotas, and limits
The first request for a given object-and-parameters combination computes
the derivative and stores it; later requests are served from that cache. The
cache is platform-managed and does not count against your
project's storage. Rendered bytes are metered as egress
just like a download, and a request that would exceed your egress allowance
answers 429.
- Source images up to 40 megapixels; larger answers
422. - Output edges are clamped to 4096px.
- Inputs may be JPEG, PNG, GIF (first frame), WebP, or AVIF.
SVG is refused (never rasterised) and answers
422. - WebP and AVIF are encoded by a sandboxed in-house codec.
Signed transform URLs
To hand out a time-limited link to a specific rendered image — without
exposing a key — mint a signed URL and include a transform
block. The parameters are locked into the signed token, so the holder gets
exactly that rendition and cannot change the object or the transform:
curl -X POST "https://<ref>.kethosbase.com/storage/v1/object/sign/photos/2026/trip.jpg" \
-H "Authorization: Bearer <key>" \
-H "Content-Type: application/json" \
-d '{ "expiresIn": 3600,
"transform": { "width": 1200, "format": "webp", "quality": 70 } }'
→ { "signedURL": "/storage/v1/render/image/sign/photos/2026/trip.jpg?token=…" }
Minting requires that the caller can read the object under RLS, and the transform must actually change the image (an identity transform is rejected). See Storage for signed URLs in general.