Media API
Upload, manage, and retrieve media files (images, documents, videos) programmatically.
Try it — API Explorer
Authentication
Authenticated endpoints require your API key as a Bearer token:
Authorization: Bearer YOUR_API_KEY
Public endpoints work without authentication but return fewer fields.
Public endpoints
No authentication required. These endpoints support CORS.
List media
GET /api/v1/public/media
cURL:
curl https://your-site.clearcms.app/api/v1/public/media
Query parameters:
| Parameter | Type | Description |
|---|---|---|
folder | string | Filter by folder path (e.g. /images) |
type | string | Filter by type: image, document, or video |
limit | integer | Results per page. Default: 24. Max: 100 |
offset | integer | Pagination offset |
With an API key, search, sort, and order parameters are also available.
Response:
{
"data": [
{
"id": "media_abc123",
"filename": "product.jpg",
"mimeType": "image/jpeg",
"width": 1920,
"height": 1080,
"alt": "Product showcase",
"url": "/uploads/2026/03/abc123.jpg",
"focalX": 50,
"focalY": 50
}
],
"total": 45,
"limit": 24,
"offset": 0
}
Get a media item
GET /api/v1/public/media/{id}
Returns a single media item by ID. Cached for 1 hour.
Authenticated endpoints
Require an API key. Return full metadata including size, title, description, folder, and createdAt.
List media (full)
GET /api/v1/media
Query parameters:
| Parameter | Type | Description |
|---|---|---|
folder | string | Filter by folder path |
type | string | Filter by type: image, document, video |
search | string | Search filename and alt text |
limit | integer | Results per page. Default: 24 |
offset | integer | Pagination offset |
sort | string | Sort by createdAt, filename, or size. Default: createdAt |
order | string | asc or desc. Default: desc |
Response:
{
"data": [
{
"id": "media_abc123",
"filename": "product.jpg",
"mimeType": "image/jpeg",
"size": 245000,
"width": 1920,
"height": 1080,
"alt": "Product showcase",
"title": "Product Image",
"description": "High-quality product photo",
"url": "/uploads/2026/03/abc123.jpg",
"folder": "/images/products",
"focalX": 50,
"focalY": 50,
"createdAt": "2026-03-26T10:30:00Z"
}
],
"total": 45,
"limit": 24,
"offset": 0,
"folders": ["/", "/images", "/documents", "/logos"]
}
Get a media item (full)
GET /api/v1/media/{id}
Returns the full media item including all metadata fields.
Upload media
POST /api/v1/media
Content-Type: multipart/form-data
cURL:
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "files=@photo.jpg" \
-F "folder=/images" \
https://your-site.clearcms.app/api/v1/media
Form fields:
| Field | Type | Required | Description |
|---|---|---|---|
files | File[] | Yes | One or more files to upload |
folder | string | No | Target folder path (default: /) |
alt | string | No | Alt text for images |
Response (201):
{
"data": [
{
"id": "media_def456",
"filename": "banner.png",
"mimeType": "image/png",
"size": 512000,
"width": 1200,
"height": 400,
"url": "/uploads/2026/03/def456.png",
"folder": "/",
"focalX": 50,
"focalY": 50,
"createdAt": "2026-03-26T11:00:00Z"
}
],
"errors": []
}
Supported file types: JPEG, PNG, GIF, WebP, SVG, PDF, MP4, WebM
Size limits: 50 MB (local storage), 500 MB (cloud storage)
Images are automatically optimized into multiple sizes (150px, 400px, 800px, 1200px) and converted to WebP.
Update media metadata
PATCH /api/v1/media/{id}
Request body:
{
"alt": "Updated alt text",
"title": "New title",
"description": "New description",
"folder": "/images/updated",
"focalX": 35,
"focalY": 65
}
All fields are optional. focalX and focalY are percentages (0–100) that set the focal point for smart cropping.
Delete media
DELETE /api/v1/media/{id}
Returns { "success": true } on success.
Presigned uploads
For large files, use presigned URLs to upload directly to cloud storage (R2/S3), bypassing your server.
1. Request a presigned URL
POST /api/v1/media/presign
cURL:
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"filename":"video.mp4","mimeType":"video/mp4","size":500000000}' \
https://your-site.clearcms.app/api/v1/media/presign
Request body:
{
"filename": "large-video.mp4",
"mimeType": "video/mp4",
"size": 500000000
}
Response:
{
"uploadUrl": "https://storage.example.com/signed-url...",
"publicUrl": "https://cdn.example.com/2026/03/abc123.mp4",
"storageKey": "site_id/2026/03/abc123.mp4",
"expiresAt": "2026-03-26T12:30:00Z",
"method": "PUT",
"headers": {
"Content-Type": "video/mp4"
}
}
2. Upload the file
Send the file to the uploadUrl with the headers from the response:
await fetch(uploadUrl, {
method: "PUT",
headers: { "Content-Type": "video/mp4" },
body: fileBlob,
});
3. Confirm the upload
POST /api/v1/media/confirm
Request body:
{
"storageKey": "site_id/2026/03/abc123.mp4",
"filename": "large-video.mp4",
"mimeType": "video/mp4",
"size": 500000000,
"folder": "/videos"
}
Response (201):
{
"success": true,
"data": {
"id": "media_xyz789",
"filename": "large-video.mp4",
"url": "https://cdn.example.com/2026/03/abc123.mp4",
"folder": "/videos",
"createdAt": "2026-03-26T11:45:00Z"
}
}
Presigned uploads require a cloud storage adapter (R2, S3). Sites using local storage should use the regular upload endpoint.
Folders
List folders
GET /api/v1/media/folders
Returns all folder paths as a flat array:
{
"folders": ["/", "/images", "/images/products", "/documents", "/logos"]
}
Create a folder
POST /api/v1/media/folders
{
"path": "/images/new-category"
}
Delete a folder
DELETE /api/v1/media/folders
{
"path": "/images/old-category"
}
Folders must be empty before deletion. The root folder / cannot be deleted.
Error responses
Errors follow the same format as the Headless API.
| Status | Meaning |
|---|---|
400 | Invalid request (bad file type, focal point out of range, invalid folder path) |
401 | Missing or invalid API key |
403 | Insufficient permissions |
404 | Media item or folder not found |
500 | Server error |