SaskStore API

Self-hosted Media CDN — Upload, transform, and serve images & videos via API.

Base URL: https://media.yourdomain.com
Authentication: Pass your API key in the X-API-Key header.

Upload

POST /api/v1/upload

Upload a single file (image, video, or document).

curl -X POST https://media.yourdomain.com/api/v1/upload \
  -H "X-API-Key: nxs_your_key_here" \
  -F "file=@photo.jpg" \
  -F "folder=/products"
ParamTypeRequiredDescription
fileFileYesThe file to upload (multipart/form-data)
folderStringNoVirtual folder path (default: /)
is_publicBooleanNoMake file publicly accessible (default: true)

Response:

{
  "id": "58257a0e-a8c7-4b64-b09f-1c0e2c7a092e",
  "url": "https://media.yourdomain.com/media/58257a0e-...",
  "thumbnail": "https://media.yourdomain.com/media/58257a0e-...?w=300&h=300",
  "type": "image",
  "mime_type": "image/jpeg",
  "size": 245760,
  "width": 1920,
  "height": 1080,
  "original_name": "photo.jpg"
}

POST /api/v1/upload/bulk

Upload up to 20 files at once.

curl -X POST https://media.yourdomain.com/api/v1/upload/bulk \
  -H "X-API-Key: nxs_your_key_here" \
  -F "files=@img1.jpg" \
  -F "files=@img2.jpg" \
  -F "folder=/gallery"

Serve Media

GET /media/:id

Serve a file. No authentication needed for public files. Supports on-the-fly image transforms via query params.

<!-- Original -->
<img src="https://media.yourdomain.com/media/58257a0e-..." />

<!-- Resized 300x300 WebP -->
<img src="https://media.yourdomain.com/media/58257a0e-...?w=300&h=300&format=webp" />

<!-- Width only, auto height, quality 60 -->
<img src="https://media.yourdomain.com/media/58257a0e-...?w=500&q=60" />

<!-- AVIF format -->
<img src="https://media.yourdomain.com/media/58257a0e-...?format=avif&q=70" />
ParamTypeDescription
wNumberResize width (px)
hNumberResize height (px)
qNumberQuality 1-100 (default: 80)
formatStringOutput format: webp, avif, jpg, png (default: webp)
fitStringResize fit: cover, contain, fill, inside (default: cover)
Transforms are cached on NVMe SSD. First request generates the transform, subsequent requests serve from cache instantly.

File Management

GET /api/v1/files

List your files with pagination and filters.

curl https://media.yourdomain.com/api/v1/files?type=image&folder=/products&page=1&limit=20 \
  -H "X-API-Key: nxs_your_key_here"

GET /api/v1/files/:id

Get file details.

DELETE /api/v1/files/:id

Delete a file and all its cached transforms.

curl -X DELETE https://media.yourdomain.com/api/v1/files/58257a0e-... \
  -H "X-API-Key: nxs_your_key_here"

Usage Stats

GET /api/v1/usage

Get storage usage, file counts, and request stats for your API key.

{
  "api_key": "My App",
  "storage": { "used_mb": 1250, "limit_mb": 10240, "percent": 12 },
  "files": { "total": 342, "images": 310, "videos": 32 },
  "cache": { "size_mb": 85 },
  "requests": 15420
}

Integration Examples

Node.js / Express

const FormData = require('form-data');
const fs = require('fs');

async function uploadImage(filePath) {
  const form = new FormData();
  form.append('file', fs.createReadStream(filePath));
  form.append('folder', '/products');

  const res = await fetch('https://media.yourdomain.com/api/v1/upload', {
    method: 'POST',
    headers: { 'X-API-Key': 'nxs_your_key_here' },
    body: form,
  });

  const data = await res.json();
  return data.url; // Use this URL in your app
}

React / Frontend

async function uploadFile(file) {
  const form = new FormData();
  form.append('file', file);

  const res = await fetch('https://media.yourdomain.com/api/v1/upload', {
    method: 'POST',
    headers: { 'X-API-Key': 'nxs_your_key_here' },
    body: form,
  });

  const data = await res.json();
  return data.url;
}

// Usage in JSX
<img src={`${imageUrl}?w=400&format=webp`} />

HTML (Direct)

<!-- Original image -->
<img src="https://media.yourdomain.com/media/FILE_ID" />

<!-- Optimized thumbnail -->
<img src="https://media.yourdomain.com/media/FILE_ID?w=200&h=200&format=webp&q=75" />

<!-- Responsive with srcset -->
<img srcset="
  https://media.yourdomain.com/media/FILE_ID?w=400&format=webp 400w,
  https://media.yourdomain.com/media/FILE_ID?w=800&format=webp 800w,
  https://media.yourdomain.com/media/FILE_ID?w=1200&format=webp 1200w
" sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px" />
SaskStore v1.0 — Self-hosted Media CDN