Skip to content

Media API

Public API · Enterprise Edition

The Media library exposes a public, key-gated surface (/api/media/v1/) for external integrations; the workspace-scoped management routes are part of the internal application API. Both are detailed below. Media is an Enterprise-Edition feature.

The Media API manages binary assets (images, videos, documents) stored in Cloudflare R2 object storage. Assets are processed with Sharp for optimization and variant generation.

There are two surfaces:

  • Application API (this page's main sections) — project-scoped, session-authenticated, used by the Studio SPA:
    /api/workspaces/:workspaceId/projects/:projectId/media/...
  • Public Media API — key-gated external surface (see Public Media API below):
    /api/media/v1/:projectId/assets/...

Enterprise Feature

Media upload and management require the enterprise bridge (ee/) to be loaded and R2 credentials to be configured. The media provider is null in the Community Edition, so every media route returns 503 there. On the managed service the media library is available on Starter plans and above.

Upload Media

Upload a file to the project media library.

POST /api/workspaces/:workspaceId/projects/:projectId/media

Request

Multipart form data:

FieldTypeRequiredDescription
fileFileYesBinary file to upload
altstringNoAlt text for accessibility
tagsstringNoComma-separated tags

Response

json
{
  "id": "uuid",
  "filename": "hero-banner.webp",
  "contentType": "image/webp",
  "size": 125000,
  "width": 1920,
  "height": 1080,
  "format": "webp",
  "blurhash": "LEHV6nWB2yk8",
  "alt": "Hero banner image",
  "tags": ["hero", "banner"],
  "originalPath": "media/original/abc123.webp",
  "variants": {
    "thumbnail": {
      "path": "media/thumbnail/abc123.webp",
      "width": 300,
      "height": 169,
      "format": "webp",
      "size": 12000
    }
  },
  "createdAt": "2026-01-01T00:00:00Z"
}

Plan Limits

PlanMax File SizeStorageVariants per Field
Free
Starter5 MB1 GB4
Pro50 MB15 GB10
Enterprise100 MB100 GBUnlimited

Upload from URL

Import a media asset from an external URL.

POST /api/workspaces/:workspaceId/projects/:projectId/media/upload-url

Request Body

FieldTypeRequiredDescription
urlstringYesSource URL to fetch
altstringNoAlt text
tagsstring[]NoTags for organization

List Media

List media assets with filtering and pagination.

GET /api/workspaces/:workspaceId/projects/:projectId/media

Query Parameters

ParameterTypeDefaultDescription
pagenumber1Page number
limitnumber20Items per page
searchstring--Search by filename, alt text
tagsstring--Filter by tags (comma-separated)
contentTypestring--Filter by MIME type prefix (e.g., image)
sortstringnewestSort order: newest, oldest, name, size

Response

json
{
  "assets": [ ... ],
  "total": 42
}

Get Asset

Get full metadata for a specific media asset.

GET /api/workspaces/:workspaceId/projects/:projectId/media/:assetId

Preview Asset

Get a binary preview of a media asset (serves the file).

GET /api/workspaces/:workspaceId/projects/:projectId/media/:assetId/preview

Update Asset Metadata

Update alt text, tags, or focal point for an asset.

PATCH /api/workspaces/:workspaceId/projects/:projectId/media/:assetId

Request Body

FieldTypeRequiredDescription
altstringNoNew alt text
tagsstring[]NoNew tags
focalPoint{ x: number, y: number }NoFocal point coordinates (0-1 range)

Delete Asset

Delete an asset and all its variants from storage and database.

DELETE /api/workspaces/:workspaceId/projects/:projectId/media/:assetId

Bulk Operations

Perform bulk operations on multiple assets.

POST /api/workspaces/:workspaceId/projects/:projectId/media/bulk

Request Body

FieldTypeRequiredDescription
action'delete'YesBulk action type
assetIdsstring[]YesAsset IDs to process

Public Media API (Key-Gated)

The public media surface lets agents and CI authenticate with a CDN/media API key instead of a session. It is gated by CDN keys carrying the right scope:

http
Authorization: Bearer crn_live_your-api-key

Auth model (per request): Bearer key validation → the key's project must match :projectId → scope check → per-key hourly rate limit → plan feature → media provider. The project must have CDN enabled (cdn_enabled); read routes require the media:read scope and the media.library feature, write routes require media:write and media.upload.

MethodPathScope
GET/api/media/v1/:projectId/assetsmedia:read
POST/api/media/v1/:projectId/assetsmedia:write
GET/api/media/v1/:projectId/assets/:assetIdmedia:read
PATCH/api/media/v1/:projectId/assets/:assetIdmedia:write
DELETE/api/media/v1/:projectId/assets/:assetIdmedia:write
POST/api/media/v1/:projectId/assets/bulkmedia:write

List (GET /assets)

Query parameters: search, tags (comma-separated), type (MIME prefix), limit (default 50, max 100), page, sort (newest, oldest, name, size). Returns { assets, total }.

Upload (POST /assets)

Accepts either multipart/form-data with a file part (plus optional alt, tags, variants) or a JSON body { url, alt?, tags?, variants? } for URL import (SSRF-guarded). Returns 201 with the created asset.

Get / Update / Delete (/assets/:assetId)

GET returns the asset. PATCH updates alt, tags, and/or focalPoint. DELETE removes the asset and its variants, returning { "deleted": true }.

Bulk (POST /assets/bulk)

json
{
  "action": "delete",
  "assetIds": ["uuid1", "uuid2"]
}

action is delete or tag (the latter also requires a tags array). Capped at 50 asset IDs per call; assets outside the key's project are silently skipped. Returns { action, affected }.

Released under the AGPL-3.0 License.