Assets

Upload or replace one asset

Stores one file at key, replacing any file already there. Send the bytes as base64, or an importFromUrl for the server to fetch. The key is the path after /assets/ — for example photos/hero.webp or style.css. Do not prefix it with assets/ or /. Keys may not contain .. segments or start with .dotsy/. A single file may be up to 5 MB on the Free plan and 10 MB on a paid plan, and video and audio need a paid plan. HTML files are not accepted. Raster images (not SVG) are optimized on upload: they are re-encoded as WebP and, for the hero and column intents, get a smaller -800 variant, so the stored key can differ from the one you sent. Send optimize: false (?optimize=0 on the raw upload) to store the bytes as sent; animated GIFs are always kept as sent. To upload larger files without base64, send the raw bytes to assets-raw instead. Uploaded files are live in the editor and draft preview at once; the published site picks them up at the next publish.

put/api/v1/sites/{slug}/assets/{key}

Request

  • Base URL: https://api.dotsy.ai
  • URL: https://api.dotsy.ai/api/v1/sites/{slug}/assets/{key}
  • Auth: HTTP bearer

Path parameters

slugstring required
Example:acme-studio

Site slug or site id (UUID). An old slug answers 301/308 and a site id 307 to the canonical slug path.

keystring required

Percent-encode each segment; '/' may be sent raw or as %2F. Keys may contain '/'.

Request body

bodyBase64string

The file's bytes, base64-encoded. Send this or importFromUrl, not both.

bodySha256string

SHA-256 (64 hex characters) of the bytes you send. A mismatch answers 400 body_sha256_mismatch before anything is written.

contentTypestring

The file's MIME type. Defaults to the one implied by the key's extension.

importFromUrlstring uri

Fetch the file from this URL instead of sending bodyBase64. Send this or bodyBase64, not both.

intent'hero' | 'column' | 'inline' | 'logo'

The layout role of an image, which sets its size: hero (up to 2,400 px) and column (1,200 px) also store a smaller -800 variant; inline (800 px) and logo (512 px) do not. Defaults to logo under logos/ or icons/, otherwise column.

titlestring

Display title (up to 500 characters). Defaults to the file name.

optimizeboolean

Default true. false stores a raster image exactly as sent, at the key you gave, instead of re-encoding it as WebP.

Example request

{
  "bodyBase64": "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciLz4=",
  "contentType": "image/svg+xml"
}

Response

An existing asset was replaced.

keystring required

The stored key. For a raster image this is the WebP key, which can differ from the key you sent.

originalKeystring

The key you sent, when the image is stored under another one. /assets/{originalKey} keeps serving it, and published pages that reference it are pointed at the stored image. Use key in new references.

hintstring

Present when {name}.webp already held another image, so this one was stored as {name}-{ext}.webp (in key). Published pages that use the name you sent still show it; CSS and JS must use key.

createdboolean required

True when the asset did not exist before.

sizeinteger required

Stored size in bytes.

contentTypestring required
sha256string required

SHA-256 of the STORED bytes. For JS, CSS and SVG it matches the upload; a raster image is re-encoded to WebP, so it may not.

widthinteger

Pixel width, for a processed raster image.

heightinteger

Pixel height, for a processed raster image.

suggestedSrcsetstring

A ready-made srcset for the image and its smaller variant.

processedboolean

True when the image was optimized on upload.

skippedReencodeboolean

True when the image was already small enough to keep as is.

optimizedfalse

Present as false when a raster image was stored exactly as sent instead of re-encoded; reason says why.

reason'daily_image_budget' | 'optimize_off' | 'animated_gif'

Why optimized is false: the daily image-processing budget was used up (daily_image_budget), you sent optimize: false (optimize_off), or the file is an animated GIF, which keeps its frames (animated_gif).

uploadedAtnumber required

Upload time, Unix ms.

etagstring required

Content fingerprint (MD5 hex).

Example response

{
  "key": "photos/hero.webp",
  "originalKey": "photos/hero.jpg",
  "contentType": "image/webp",
  "suggestedSrcset": "photos/hero-800.webp 800w, photos/hero.webp 1600w"
}

Changes

No recorded changes to this operation across all 1 revision of this API.