Images API

Complete reference for the Images endpoint. Learn how to list, upload, and manage images programmatically.

List Images

Retrieve a list of all images across all your collections.

GET https://api.optimage.com/api/v1/images

Response (200 OK)

[
  {
    "id": "img_1234567890",
    "slug": "beach-sunset",
    "collectionId": "col_abc123",
    "checksum": "a1b2c3d4...",
    "createdAt": "2025-12-04T10:30:00Z",
    "baseUrl": "https://cdn.optimage.com"
  },
  {
    "id": "img_0987654321",
    "slug": "mountain-view",
    "collectionId": "col_xyz789",
    "checksum": "e5f6g7h8...",
    "createdAt": "2025-12-03T15:20:00Z",
    "baseUrl": "https://cdn.optimage.com"
  }
]

Example (JavaScript)

const response = await fetch('https://api.optimage.com/api/v1/images', {
  credentials: 'include'
});

const images = await response.json();
console.log(`Total images: ${images.length}`);

Upload Image

Upload a new image to a specific collection. The image will be automatically processed and optimized into multiple sizes.

POST https://api.optimage.com/api/v1/images

Request Format

Use multipart/form-data format with the following fields:

  • file (required): The image file (JPEG, PNG, WebP, or GIF)
  • checksum (required): SHA-256 hash of the file for integrity verification
  • collection (required): Collection ID where the image will be stored
  • slug (optional): Custom slug for the image URL (auto-generated if not provided)

Response (201 Created)

{
  "id": "img_1234567890",
  "slug": "beach-sunset",
  "collectionId": "col_abc123",
  "checksum": "a1b2c3d4e5f6g7h8...",
  "status": "processing",
  "createdAt": "2025-12-04T10:30:00Z",
  "baseUrl": "https://cdn.optimage.com"
}

Error Responses

400 Bad Request - Invalid file format or missing required fields

401 Unauthorized - Not authenticated

403 Forbidden - Collection does not belong to user

429 Too Many Requests - Monthly quota exceeded

SHA-256 Checksum Calculation

Calculate the checksum before uploading:

async function calculateChecksum(file) {
  const arrayBuffer = await file.arrayBuffer();
  const hashBuffer = await crypto.subtle.digest('SHA-256', arrayBuffer);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  const hashHex = hashArray
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
  return hashHex;
}

Complete Upload Example (JavaScript)

async function uploadImage(file, collectionId, customSlug = null) {
  // Calculate checksum
  const checksum = await calculateChecksum(file);

  // Create form data
  const formData = new FormData();
  formData.append('file', file);
  formData.append('checksum', checksum);
  formData.append('collection', collectionId);
  if (customSlug) {
    formData.append('slug', customSlug);
  }

  // Upload
  const response = await fetch('https://api.optimage.com/api/v1/images', {
    method: 'POST',
    credentials: 'include',
    body: formData
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.message || 'Upload failed');
  }

  const image = await response.json();
  console.log('Image uploaded:', image.slug);
  return image;
}

// Usage
const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files[0];
const collectionId = 'col_abc123';

try {
  const image = await uploadImage(file, collectionId);
  console.log('Upload successful:', image);
} catch (error) {
  console.error('Upload failed:', error.message);
}

Tip: The upload endpoint returns immediately with status "processing". The image becomes available at its CDN URLs within 5-15 seconds after processing completes.

Image Processing

After upload, OPTIMAGE automatically processes your image through a task pipeline:

  1. Validation: Verify file format and checksum
  2. WebP Conversion: Convert original to WebP format (size 0)
  3. Resize: Generate 11 responsive sizes (320px to 1280px wide)
  4. Optimization: Compress each size to 80% quality
  5. CDN Upload: Distribute to Cloudflare R2 CDN
  6. URL Activation: Images become available at their CDN URLs

Total processing time is typically 5-15 seconds depending on the original image size.

Available Sizes

Each image is automatically processed into these sizes:

Size CodeWidthDescription
0OriginalWebP conversion of original (maintains aspect ratio)
320320pxMobile portrait, small thumbnails
384384pxMobile landscape
448448pxSmall tablets
512512pxTablets portrait
576576pxLarge mobile, small tablet landscape
672672pxTablet landscape
768768pxSmall desktop, large tablets
896896pxDesktop
10241024pxDesktop, small retina
11521152pxLarge desktop
12801280pxLarge desktop, retina displays

Image URLs

All images are served from the OPTIMAGE CDN with the following URL structure:

https://cdn.optimage.com/{collectionId}/{size}/{slug}.webp

URL Examples

// Original WebP conversion
https://cdn.optimage.com/col_abc123/0/beach-sunset.webp

// 768px size (default for src)
https://cdn.optimage.com/col_abc123/768/beach-sunset.webp

// 1280px size (largest)
https://cdn.optimage.com/col_abc123/1280/beach-sunset.webp

Building srcset in Code

function buildSrcset(collectionId, slug) {
  const baseUrl = 'https://cdn.optimage.com';
  const sizes = [320, 384, 448, 512, 576, 672, 768, 896, 1024, 1152, 1280];

  const srcset = sizes
    .map(size => `${baseUrl}/${collectionId}/${size}/${slug}.webp ${size}w`)
    .join(', ');

  const src = `${baseUrl}/${collectionId}/768/${slug}.webp`;

  return { src, srcset };
}

// Usage
const { src, srcset } = buildSrcset('col_abc123', 'beach-sunset');
console.log('src:', src);
console.log('srcset:', srcset);

Rate Limits

Upload limits are based on your account's monthly quota:

  • Free Plan: 500 images per month
  • Pro Plan: 5,000 images per month
  • Business Plan: 25,000 images per month

Quotas reset on the first day of each month. Once you reach your quota limit, you'll receive a 429 Too Many Requests error until your quota resets.

Tip: Check your remaining quota before uploading by calling the GET /api/v1/config endpoint.