Kalpana Docs
Resources

Upload an asset

Upload an image as base64 so it can be used by image variables.

POST /api/assets

Requires assets:create. Returns 201 with the asset, including its id.

Request body

FieldRequiredDescription
workspaceIdYesWorkspace id or slug. Note the field name differs from other endpoints.
contentHashYesA hash that identifies the bytes. Use the SHA-256 hex digest of the image. The server does not check it against the bytes. If the workspace already holds a file under this hash, that file is kept and the bytes you send are not stored again.
imageBytesYesThe image, base64 encoded.
filenameNoDisplay name. Defaults to asset-<contentHash>.
contentTypeNoimage/png, image/jpeg, image/jpg, image/webp, image/gif, image/avif or image/bmp. Any other type returns 400 with Unsupported image content type. Defaults to image/png.
collectionIdNoImage collection to add the image to. A collection that is not in the workspace is skipped.
curl --request POST "https://app.kalpana.one/api/assets" \
  --header "x-api-key: $KALPANA_API_KEY" \
  --header "content-type: application/json" \
  --data '{
    "workspaceId": "acme",
    "contentHash": "'"$(shasum -a 256 logo.png | cut -d' ' -f1)"'",
    "imageBytes": "'"$(base64 < logo.png | tr -d '\n')"'",
    "filename": "logo.png",
    "contentType": "image/png"
  }'

Response

{
  "id": "0b0f5a3e-5b1c-4d65-9a5e-3f7d2f2f6c11",
  "workspaceId": "ws_123",
  "contentHash": "…",
  "storageKey": "…",
  "filename": "logo.png",
  "contentType": "image/png",
  "sizeBytes": 20480,
  "meta": { "width": 512, "height": 512 },
  "uploadedBy": "user_123",
  "status": "ready",
  "createdAt": "2026-09-01T10:00:00.000Z",
  "updatedAt": "2026-09-01T10:00:00.000Z",
  "url": "https://cdn.example/temporary-url"
}

Uploading a contentHash the workspace already holds returns the existing asset. Its name changes only when you send a filename. url is a temporary link.

Limits

  • 5 MB per image. The image must be 5 MB or smaller, otherwise the request fails with 400 and a message giving its size. Images are stored as uploaded, without re-encoding; resize it or export JPEG or WebP and try again.
  • Image types. PNG, JPEG, WebP, GIF, AVIF, and BMP. SVG is not accepted. AVIF is converted to PNG because the renderer cannot decode it, and the 5 MB limit applies to the PNG.
  • No domain whitelist. The whitelist applies only to Upload from a URL, which fetches the file for you. Direct uploads send the bytes, so any source is fine.
  • Request size. The bytes travel as base64 inside a JSON body, which is about a third larger than the file. For anything near the limit, use Upload assets directly, or host the image on a whitelisted domain and use Upload from a URL.
Was this page helpful?

Updated 4 Nov 2026

On this page