Media
File uploads, image management, and asset handling
The Media module handles file uploads, image processing, and asset management.
Upload Media
/v1/businesses/{businessId}/media sdk.media.uploadBusinessMedia() Upload files to your media library. Supports uploading multiple files and/or URLs.
// Upload from file input (multiple files)
const fileInput = document.querySelector('input[type="file"]');
const files = Array.from(fileInput.files);
const result = await sdk.media.uploadBusinessMedia({
files: files, // Array of File objects
urls: [] // Can also provide URLs to download
});
result.forEach(media => {
console.log('Uploaded:', media.url);
console.log('Media ID:', media.id);
});
// Upload from URLs
const urlResult = await sdk.media.uploadBusinessMedia({
files: [],
urls: [
'https://example.com/image1.jpg',
'https://example.com/image2.png'
]
});Parameters
| Name | Type | Description |
|---|---|---|
files optional | File[] | Array of files to upload (multipart field name: files) |
urls optional | string[] | Array of URLs to download and store (multipart field name: urls) |
At least one of files or urls must be provided with at least one item.
Supported File Types
| Category | Extensions |
|---|---|
| Images | .jpg, .jpeg, .png, .gif, .webp, .svg, .avif |
| Documents | .pdf, .doc, .docx, .xls, .xlsx |
| Video | .mp4, .webm, .mov |
| Audio | .mp3, .wav, .ogg |
Size Limits
- Images: 10MB
- Documents: 25MB
- Video: 100MB
- Audio: 50MB
Get Single Media Item
/v1/businesses/{businessId}/media/{mediaId} sdk.media.getMedia() Retrieve a single media item by ID.
const media = await sdk.media.getMedia({
mediaId: 'media_xyz789'
});
console.log(media.url, media.mimeType, media.size);
Parameters
| Name | Type | Description |
|---|---|---|
mediaId required | string | Media ID to retrieve |
businessId optional | string | Business ID (defaults to the SDK config) |
List Media
/v1/businesses/{businessId}/media sdk.media.getBusinessMedia() List all media files.
const result = await sdk.media.getBusinessMedia({
mimeType: 'image/jpeg',
query: 'product hero',
limit: 50,
sortField: 'uploadedAt',
sortDirection: 'desc'
});
result.items.forEach(media => {
console.log(media.id, media.url, media.size);
});Parameters
| Name | Type | Description |
|---|---|---|
ids optional | string[] | Filter by specific media IDs |
mimeType optional | string | Filter by MIME type (image/jpeg, image/png, video/mp4, etc.) |
query optional | string | Search in filename and metadata |
sortField optional | string | Sort field |
sortDirection optional | asc | desc | Sort direction |
cursor optional | string | Pagination cursor |
limit required | number | Items per page |
Update Media
/v1/businesses/{businessId}/media/{mediaId} sdk.media.updateMedia() Update media metadata. Currently supports localized slug updates used to generate CDN-friendly filenames.
const result = await sdk.media.updateMedia({
mediaId: 'media_xyz789',
slug: {
en: 'product-hero-front-view',
es: 'producto-hero-vista-frontal'
}
});
Parameters
| Name | Type | Description |
|---|---|---|
mediaId required | string | Media ID to update |
slug optional | Record<string, string> | Localized slug for the media filename |
Delete Media
/v1/businesses/{id}/media/{mediaId} sdk.media.deleteBusinessMedia() Delete a media file.
Deleting media that’s in use (products, nodes, etc.) may cause broken images. Check references before deleting.
const result = await sdk.media.deleteBusinessMedia({
id: 'biz_abc123',
mediaId: 'media_xyz789'
});
Parameters
| Name | Type | Description |
|---|---|---|
id required | string | Business ID |
mediaId required | string | Media ID to delete |
Image Transformations
Arky provides on-the-fly image transformations via URL parameters.
Resize
// Original URL
const originalUrl = media.url;
// https://cdn.arky.io/media/biz_abc123/image.jpg
// Resize to width 400px (height auto)
const resized = `${originalUrl}?w=400`;
// Resize to exact dimensions
const exact = `${originalUrl}?w=400&h=300`;
// Fit within bounds (maintain aspect ratio)
const fit = `${originalUrl}?w=400&h=300&fit=contain`;
// Cover (crop to fill)
const cover = `${originalUrl}?w=400&h=300&fit=cover`;
Quality
// Reduce quality for smaller file size
const compressed = `${originalUrl}?q=75`;
Format Conversion
// Convert to WebP
const webp = `${originalUrl}?format=webp`;
// Convert to AVIF
const avif = `${originalUrl}?format=avif`;
Transformation Parameters
| Parameter | Description | Example |
|---|---|---|
w | Width in pixels | ?w=400 |
h | Height in pixels | ?h=300 |
fit | Resize mode | contain, cover, fill |
q | Quality (1-100) | ?q=80 |
format | Output format | webp, avif, jpg, png |
blur | Blur amount (1-100) | ?blur=10 |
grayscale | Convert to grayscale | ?grayscale=true |
Responsive Images
Generate srcset for responsive images:
function getResponsiveSrcSet(media: Media) {
const baseUrl = media.url;
const widths = [320, 640, 960, 1280, 1920];
return widths
.map(w => `${baseUrl}?w=${w}&format=webp ${w}w`)
.join(', ');
}
// Usage in HTML
const srcSet = getResponsiveSrcSet(productImage);
// <img srcset={srcSet} sizes="(max-width: 768px) 100vw, 50vw" />
Upload with Progress
Track upload progress for large files:
async function uploadWithProgress(
files: File[],
onProgress: (percent: number) => void
) {
const formData = new FormData();
files.forEach((file, i) => {
formData.append(`files[${i}]`, file);
});
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable) {
const percent = Math.round((e.loaded / e.total) * 100);
onProgress(percent);
}
});
xhr.addEventListener('load', () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.responseText));
} else {
reject(new Error('Upload failed'));
}
});
xhr.open('POST', `https://api.arky.io/v1/businesses/${businessId}/media`);
xhr.setRequestHeader('Authorization', `Bearer ${token}`);
xhr.send(formData);
});
}
// Usage
await uploadWithProgress(files, (percent) => {
console.log(`Upload progress: ${percent}%`);
progressBar.style.width = `${percent}%`;
});
Bulk Upload
Upload multiple files using the SDK:
async function uploadMultiple(files: File[]) {
// The SDK handles batching automatically
const results = await sdk.media.uploadBusinessMedia({
files: files
});
console.log(`Uploaded ${results.length} files`);
return results;
}
// Usage
const fileInput = document.querySelector('input[type="file"][multiple]');
const uploaded = await uploadMultiple([...fileInput.files]);
Referencing Media from Content
Reference media by ID via a RELATIONSHIP_MEDIA block in nodes, products, services, or providers:
// Upload images first
const uploadResult = await sdk.media.uploadBusinessMedia({
files: [heroFile, ...galleryFiles]
});
const [heroMedia, ...galleryMedia] = uploadResult;
// Create a node referencing the media
await sdk.cms.createNode({
key: 'my-product-page',
blocks: [
{
key: 'hero-image',
type: 'RELATIONSHIP_MEDIA',
properties: {},
value: [`media:${heroMedia.id}`]
},
{
key: 'gallery',
type: 'RELATIONSHIP_MEDIA',
properties: {},
value: galleryMedia.map(m => `media:${m.id}`)
}
]
});
Use the slug field on media to produce clean, SEO-friendly filenames in CDN URLs.