SDK Reference

Complete reference for the @offload-run/sdk TypeScript/JavaScript SDK.

Installation

npm install @offload-run/sdk
# or
pnpm add @offload-run/sdk
# or
yarn add @offload-run/sdk

Getting Your API Key

To use the SDK, you need an API key from your offload.run dashboard:

  1. Sign in to your account at app.offload.run
  2. Navigate to SettingsAPI Keys
  3. Click Create New Key and give it a name
  4. Copy the key and store it securely (it won't be shown again)

Security tip: Never commit your API key to version control. Use environment variables like OFFLOAD_API_KEY instead.

OffloadClient

The main client for interacting with the offload.run API.

import { OffloadClient } from '@offload-run/sdk';

const client = new OffloadClient({
  apiKey: process.env.OFFLOAD_API_KEY!,  // Required
  baseUrl: 'https://app.offload.run/api/v1', // Optional (default)
  timeout: 30000, // Optional: request timeout in ms (default: 30000)
});

Methods

enqueueJob()

Enqueue a new job for processing. Returns immediately with a job ID.

const { jobId, status, createdAt } = await client.enqueueJob({
  type: 'compressVideo',      // Required: Job type
  params: {                   // Required: Type-specific parameters
    url: 'https://example.com/video.mp4',
    quality: 'high',
  },
  priority: 5,                // Optional: 1-10, lower = higher priority
  webhookUrl: 'https://...',  // Optional: URL for completion notification
  webhookSecret: 'secret',    // Optional: Secret for webhook signature
});

getJob()

Get the current status and result of a job.

const job = await client.getJob(jobId);

console.log(job.id);       // Job ID
console.log(job.type);     // 'compressVideo', 'compressImage', etc.
console.log(job.status);   // 'pending' | 'processing' | 'completed' | 'failed' | 'cancelled'
console.log(job.error);    // Error message if failed, null otherwise

// Result fields are at root level when completed:
console.log(job.url);              // Output file URL
console.log(job.size);             // Output file size
console.log(job.compressionRatio); // e.g., 0.65 (65% of original)

cancelJob()

Cancel a pending or processing job. Cannot cancel completed jobs.

const { success, jobId } = await client.cancelJob(jobId);

if (success) {
  console.log('Job cancelled');
}

waitForJob()

Poll for job completion. Useful when you need the result immediately.

const job = await client.waitForJob(jobId, {
  timeout: 60000,      // Max wait time in ms (default: 60000)
  pollInterval: 500,   // Poll interval in ms (default: 500)
  onProgress: (job) => {
    console.log(`Status: ${job.status}`);
  },
});

if (job.status === 'completed') {
  console.log('Output URL:', job.url);
} else if (job.status === 'failed') {
  console.error('Job failed:', job.error);
}

enqueueAndWait()

Convenience method that enqueues a job and waits for completion in one call.

// Perfect for simple use cases
const job = await client.enqueueAndWait({
  type: 'compressImage',
  params: {
    url: 'https://example.com/image.jpg',
    quality: 80,
  }
}, {
  timeout: 120000,  // 2 minutes max
});

console.log('Compressed URL:', job.url);
console.log('Original size:', job.source.size);
console.log('Compressed size:', job.size);

Job Types

The SDK supports 5 job types. Each has specific parameters and returns different result fields.

videoThumbnail

Video

Extract a thumbnail from a video. Use timestamp: 'auto' to automatically find the best frame.

Parameters:

{
  url: string;                    // Video URL (required)
  timestamp?: number | 'auto';    // Frame time in seconds, or 'auto' for smart selection
  width?: number;                 // Output width in pixels
  height?: number;                // Output height in pixels
  format?: 'jpg' | 'png' | 'webp'; // Output format (default: 'jpg')
  quality?: number;               // Quality 1-100 (default: 85)
}

Result:

{
  url: string;           // Thumbnail URL
  size: number;          // File size in bytes
  width: number;         // Actual width
  height: number;        // Actual height
  format: string;        // Output format
  timestamp?: number;    // Actual timestamp used
  source: {              // Source video info
    size: number;
    width: number;
    height: number;
    duration: number;
  }
}

Example:

const job = await client.enqueueAndWait({
  type: 'videoThumbnail',
  params: {
    url: 'https://example.com/video.mp4',
    timestamp: 'auto',  // Smart frame selection
    format: 'webp',
    quality: 90,
  }
});

console.log('Thumbnail:', job.url);

compressImage

Image

Compress and optimize images with format conversion and resizing.

Parameters:

{
  url: string;                          // Image URL (required)
  quality?: number;                     // Quality 1-100 (default: 80)
  maxWidth?: number;                    // Max width (maintains aspect ratio)
  maxHeight?: number;                   // Max height (maintains aspect ratio)
  format?: 'jpg' | 'png' | 'webp' | 'avif'; // Output format
  stripMetadata?: boolean;              // Remove EXIF data (default: false)
}

Result:

{
  url: string;              // Compressed image URL
  size: number;             // Output size in bytes
  width: number;            // Output width
  height: number;           // Output height
  format: string;           // Output format
  compressionRatio: number; // e.g., 0.45 means 45% of original
  source: {                 // Source image info
    size: number;
    width: number;
    height: number;
  }
}

Example:

const job = await client.enqueueAndWait({
  type: 'compressImage',
  params: {
    url: 'https://example.com/photo.png',
    quality: 80,
    maxWidth: 1920,
    format: 'webp',
    stripMetadata: true,
  }
});

console.log('Saved', (1 - job.compressionRatio) * 100, '% in file size');

compressVideo

Video

Compress videos for web playback with codec selection and quality presets.

Parameters:

{
  url: string;                      // Video URL (required)
  quality?: 'low' | 'medium' | 'high'; // Quality preset (default: 'medium')
  maxWidth?: number;                // Max width in pixels
  maxHeight?: number;               // Max height in pixels
  targetBitrate?: string;           // e.g., '1M', '2M', '500K'
  codec?: 'h264' | 'h265' | 'vp9';  // Video codec (default: 'h264')
  stripAudio?: boolean;             // Remove audio track (default: false)
}

Result:

{
  url: string;              // Compressed video URL
  size: number;             // Output size in bytes
  width: number;            // Output width
  height: number;           // Output height
  duration: number;         // Duration in seconds
  format: string;           // Container format
  codec: string;            // Video codec used
  bitrate: string;          // Actual bitrate
  compressionRatio: number; // Ratio vs original
  source: {                 // Source video info
    size: number;
    width: number;
    height: number;
    duration: number;
  }
}

Example:

const job = await client.enqueueAndWait({
  type: 'compressVideo',
  params: {
    url: 'https://example.com/video.mp4',
    quality: 'high',
    maxWidth: 1920,
    codec: 'h264',
  }
}, {
  timeout: 300000,  // 5 minutes for video
  onProgress: (j) => console.log(j.status),
});

compressPdf

PDF

Compress PDF documents while maintaining readability.

Parameters:

{
  url: string;                         // PDF URL (required)
  quality?: 'low' | 'medium' | 'high'; // Quality preset (default: 'medium')
  removeMetadata?: boolean;            // Remove document metadata (default: false)
}

Result:

{
  url: string;              // Compressed PDF URL
  size: number;             // Output size in bytes
  format: string;           // Always 'pdf'
  compressionRatio: number; // Ratio vs original
  source: {
    size: number;
  }
}

Example:

const job = await client.enqueueAndWait({
  type: 'compressPdf',
  params: {
    url: 'https://example.com/document.pdf',
    quality: 'medium',
    removeMetadata: true,
  }
});

extractAudio

Audio

Extract audio track from video files as MP3.

Parameters:

{
  url: string;                         // Video URL (required)
  quality?: 'low' | 'medium' | 'high'; // Audio quality (default: 'medium')
  // low: 128kbps, medium: 192kbps, high: 320kbps
}

Result:

{
  url: string;       // MP3 file URL
  size: number;      // File size in bytes
  duration: number;  // Duration in seconds
  format: 'mp3';     // Always 'mp3'
  bitrate: string;   // e.g., '320kbps'
  source: {
    size: number;
    duration: number;
    audioBitrate: number;
    audioCodec: string;
  }
}

Example:

const job = await client.enqueueAndWait({
  type: 'extractAudio',
  params: {
    url: 'https://example.com/video.mp4',
    quality: 'high',  // 320kbps
  }
});

console.log('Audio URL:', job.url);
console.log('Duration:', job.duration, 'seconds');

Webhooks

Instead of polling with waitForJob(), you can receive notifications via webhooks when jobs complete.

Setting up webhooks:

await client.enqueueJob({
  type: 'compressImage',
  params: { url: '...' },
  webhookUrl: 'https://yourapp.com/api/webhooks/offload',
  webhookSecret: process.env.WEBHOOK_SECRET, // For signature verification
});

Webhook headers:

x-offload-signature: sha256=abc123...  // HMAC-SHA256 signature
x-offload-timestamp: 1703123456789     // Unix timestamp in ms

Webhook payload (same structure as job result):

{
  "id": "job_abc123",
  "type": "compressImage",
  "status": "completed",  // or "failed"
  "error": null,          // Error message if failed
  "url": "https://...",   // Result fields at root level
  "size": 102400,
  "compressionRatio": 0.45,
  // ... other result fields
}

Handling webhooks with SDK helpers:

// Next.js App Router
import { handleWebhook } from '@offload-run/sdk';

export async function POST(request: Request) {
  const payload = await handleWebhook(request, process.env.WEBHOOK_SECRET!);
  // payload is verified and typed
  console.log(payload.id, payload.status, payload.url);
  return new Response('OK');
}

Rate Limits

Rate limits depend on your subscription plan:

Free2 concurrent jobs, 100 jobs/hour
Pro10 concurrent jobs, 1,000 jobs/hour
Enterprise50 concurrent jobs, 10,000 jobs/hour

TypeScript Support

The SDK provides full TypeScript support with automatic type inference based on job type:

import type {
  JobType,
  JobStatus,
  Job,
  // Parameters
  VideoThumbnailParams,
  CompressImageParams,
  CompressVideoParams,
  CompressPdfParams,
  ExtractAudioParams,
  // Results
  VideoThumbnailResult,
  CompressImageResult,
  CompressVideoResult,
  CompressPdfResult,
  ExtractAudioResult,
  // Webhooks
  WebhookPayload,
} from '@offload-run/sdk';

// Type-safe job access
const imageJob: Job<'compressImage'> = await client.getJob(id);
console.log(imageJob.compressionRatio); // TypeScript knows this exists

Error Handling

try {
  const job = await client.enqueueAndWait({
    type: 'compressVideo',
    params: { url: '...' }
  });

  if (job.status === 'failed') {
    console.error('Job failed:', job.error);
    return;
  }

  console.log('Success:', job.url);
} catch (error) {
  if (error.response?.status === 401) {
    console.error('Invalid API key');
  } else if (error.response?.status === 429) {
    console.error('Rate limit exceeded');
  } else if (error.message.includes('Timeout')) {
    console.error('Job took too long');
  } else {
    console.error('Error:', error.message);
  }
}