ConvertHub API v2 Documentation

Overview

The ConvertHub API v2 provides a powerful, developer-friendly interface for converting files between 800+ format pairs. The API uses asynchronous job-based processing to handle conversions efficiently and reliably.

Base URL

https://api.converthub.com/v2

Features

  • Asynchronous Processing - Submit files and track conversion progress
  • 800+ Format Pairs - Support for images, documents, audio, video, and more
  • Job-Based Workflow - Track conversions with unique job IDs
  • Chunked Uploads - Upload large files in chunks
  • RESTful Design - Clean, predictable API endpoints
  • Smart Caching - Automatic caching for repeated conversions

Authentication

The ConvertHub API uses Bearer token authentication. All API requests require authentication and must include an Authorization header with your API key.

Header Format:

Authorization: Bearer YOUR_API_KEY

Getting Your API Key:

  1. Sign up for a developer account at https://converthub.com/api/signup
  2. Choose a developer plan that fits your needs
  3. Navigate to your dashboard
  4. Generate a new API key in the API Keys section
  5. Keep your API key secure and never expose it in client-side code

Example Request with Authentication:

curl -X POST https://api.converthub.com/v2/convert \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "target_format=docx"

Important Requirements:

  • Active Membership Required: You must have an active developer membership to use the API
  • Credit System: Each conversion consumes 1 credit from your account
  • Plan Limits: File size limits vary by plan (see your dashboard for details)

Security Best Practices:

  • Store API keys in environment variables
  • Never commit API keys to version control
  • Rotate keys regularly
  • Use different keys for development and production
  • Monitor API key usage in your dashboard

Quick Start

Basic Conversion Flow

  1. Submit a file for conversion using POST /v2/convert
  2. Receive a job ID to track the conversion
  3. Check job status using GET /v2/jobs/{jobId}
  4. Download the result when conversion is complete

Example: Convert PNG to JPG

# 1. Submit file for conversion
curl -X POST https://api.converthub.com/v2/convert \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "target_format=jpg"

# 2. Check job status
curl https://api.converthub.com/v2/jobs/job_123e4567-e89b-12d3-a456-426614174000 \
  -H "Authorization: Bearer YOUR_API_KEY"

# 3. Get download URL
curl https://api.converthub.com/v2/jobs/job_123e4567-e89b-12d3-a456-426614174000/download \
  -H "Authorization: Bearer YOUR_API_KEY"

Core Endpoints

1. Submit File for Conversion

Convert a file from one format to another.

Endpoint: POST /v2/convert

Important: This endpoint has a 50MB file size limit for direct uploads. For files larger than 50MB, use the Chunked Upload endpoints instead.

Request

Parameter Type Required Description
file file Yes The file to convert (max 50MB for direct upload)
target_format string Yes Target format extension (e.g., "pdf", "jpg", "mp3")
output_filename string No Custom name for the output file
webhook_url string No URL to receive webhook notification when complete
options object No Format-specific conversion options
options.quality integer No Quality setting (1-100) for lossy formats
options.resolution string No Resolution for image/video conversions
options.bitrate string No Bitrate for audio/video conversions
options.sample_rate integer No Sample rate for audio conversions
metadata object No Custom metadata for tracking

Response

Success (202 Accepted):

{
  "success": true,
  "job_id": "job_123e4567-e89b-12d3-a456-426614174000",
  "status": "processing",
  "message": "File conversion job has been queued successfully",
  "estimated_time": "Less than 30 seconds",
  "links": {
    "status": "https://api.converthub.com/v2/jobs/job_123e4567-e89b-12d3-a456-426614174000",
    "cancel": "https://api.converthub.com/v2/jobs/job_123e4567-e89b-12d3-a456-426614174000"
  }
}

Cached Result (200 OK):

{
  "success": true,
  "job_id": "job_123e4567-e89b-12d3-a456-426614174000",
  "status": "completed",
  "result": {
    "download_url": "https://cdn.converthub.com/converted/file.jpg",
    "format": "jpg",
    "file_size": 245632,
    "expires_at": "2024-01-15T10:30:00Z"
  },
  "metadata": {
    "user_ref": "user123"
  }
}

Validation Error Response (422 Unprocessable Entity):

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "A file must be provided for conversion. Please include a file in the \"file\" field.",
    "details": {
      "validation_errors": {
        "file": ["A file must be provided for conversion. Please include a file in the \"file\" field."],
        "target_format": ["Target format is required. Please specify the format you want to convert to (e.g., \"pdf\", \"jpg\", \"mp3\")."]
      },
      "failed_fields": ["file", "target_format"]
    }
  }
}

Error Response (400 Bad Request):

{
  "success": false,
  "error": {
    "code": "UNSUPPORTED_SOURCE_FORMAT",
    "message": "The source format 'xyz' is not supported",
    "details": {
      "source_format": "xyz",
      "supported_formats": ["jpg", "png", "pdf", "..."]
    }
  }
}

File Too Large Error (413 Request Entity Too Large):

{
  "success": false,
  "error": {
    "code": "FILE_TOO_LARGE",
    "message": "File size exceeds 50MB limit for direct upload. Please use chunked upload for large files.",
    "details": {
      "file_size": 104857600,
      "max_size": 52428800,
      "file_size_mb": 100.0,
      "max_size_mb": 50,
      "chunked_upload_endpoint": "/v2/upload/init"
    }
  }
}

Example Requests

Basic conversion:

curl -X POST https://api.converthub.com/v2/convert \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "target_format=pdf"

With custom options:

curl -X POST https://api.converthub.com/v2/convert \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "target_format=jpg" \
  -F "output_filename=converted_photo.jpg" \
  -F "options[quality]=85" \
  -F "metadata[project_id]=proj_123"

With webhook notification:

curl -X POST https://api.converthub.com/v2/convert \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "target_format=webm" \
  -F "webhook_url=https://your-app.com/webhooks/conversion-complete"

2. Convert File from URL

Convert a file by providing its URL instead of uploading it directly.

Endpoint: POST /v2/convert-url

Note: This endpoint downloads the file from the provided URL and then processes it. The file at the URL must be publicly accessible.

Request

Parameter Type Required Description
file_url string Yes URL of the file to convert (must be HTTP/HTTPS)
target_format string Yes Target format extension (e.g., "pdf", "jpg", "mp3")
output_filename string No Custom name for the output file
webhook_url string No URL to receive webhook notification when complete
options object No Format-specific conversion options
options.quality integer No Quality setting (1-100) for lossy formats
options.resolution string No Resolution for image/video conversions
options.bitrate string No Bitrate for audio/video conversions
options.sample_rate integer No Sample rate for audio conversions
metadata object No Custom metadata for tracking

URL Requirements

  • Must use http:// or https:// protocol
  • Must point to a specific file (not just a domain)
  • File extension should be visible in the URL or determinable from content-type
  • Maximum URL length: 2000 characters
  • File size limit: 2GB

Response

Success (202 Accepted):

{
  "success": true,
  "job_id": "job_123e4567-e89b-12d3-a456-426614174000",
  "status": "processing",
  "message": "File conversion job has been queued successfully",
  "estimated_time": "Less than 30 seconds",
  "links": {
    "status": "https://api.converthub.com/v2/jobs/job_123e4567-e89b-12d3-a456-426614174000",
    "cancel": "https://api.converthub.com/v2/jobs/job_123e4567-e89b-12d3-a456-426614174000"
  }
}

Error - Invalid URL (400 Bad Request):

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "The file URL must contain a file with a valid extension."
  }
}

Error - Download Failed (400 Bad Request):

{
  "success": false,
  "error": {
    "code": "DOWNLOAD_FAILED",
    "message": "Failed to download file from the provided URL.",
    "details": {
      "url": "https://example.com/file.pdf",
      "error": "Connection timeout"
    }
  }
}

Error - File Too Large (413 Request Entity Too Large):

{
  "success": false,
  "error": {
    "code": "FILE_TOO_LARGE",
    "message": "The file at the provided URL exceeds the maximum allowed size of 512MB.",
    "details": {
      "max_size_mb": 2048,
      "download_error": "File size limit exceeded during download"
    }
  }
}

Example Requests

Basic URL conversion:

curl -X POST https://api.converthub.com/v2/convert-url \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "file_url": "https://example.com/document.docx",
    "target_format": "pdf"
  }'

With custom options:

curl -X POST https://api.converthub.com/v2/convert-url \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "file_url": "https://example.com/image.png",
    "target_format": "jpg",
    "output_filename": "converted_image.jpg",
    "options": {
      "quality": 85
    },
    "metadata": {
      "project_id": "proj_123"
    }
  }'

With webhook notification:

curl -X POST https://api.converthub.com/v2/convert-url \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "file_url": "https://example.com/video.mp4",
    "target_format": "webm",
    "webhook_url": "https://your-app.com/webhooks/conversion-complete"
  }'

3. Get Job Status

Check the status of a conversion job.

Endpoint: GET /v2/jobs/{jobId}

Response States

The job can be in one of these states:

  • queued - Job is waiting to be processed
  • processing - Conversion is in progress
  • completed - Conversion finished successfully
  • failed - Conversion failed with an error

Response Examples

Processing:

{
  "success": true,
  "job_id": "job_123e4567-e89b-12d3-a456-426614174000",
  "status": "processing",
  "message": "Conversion is in progress",
  "source_format": "docx",
  "target_format": "pdf",
  "created_at": "2024-01-14T10:00:00Z",
  "metadata": {
    "project_id": "proj_123"
  },
  "links": {
    "status": "https://api.converthub.com/v2/jobs/job_123e4567-e89b-12d3-a456-426614174000",
    "cancel": "https://api.converthub.com/v2/jobs/job_123e4567-e89b-12d3-a456-426614174000"
  }
}

Completed:

{
  "success": true,
  "job_id": "job_123e4567-e89b-12d3-a456-426614174000",
  "status": "completed",
  "result": {
    "download_url": "https://cdn.converthub.com/converted/document.pdf",
    "format": "pdf",
    "file_size": 1048576,
    "expires_at": "2024-01-15T10:00:00Z"
  },
  "processing_time": "12.5 seconds",
  "metadata": {
    "project_id": "proj_123"
  },
  "links": {
    "download": "https://api.converthub.com/v2/jobs/job_123e4567-e89b-12d3-a456-426614174000/download"
  }
}

Failed:

{
  "success": false,
  "job_id": "job_123e4567-e89b-12d3-a456-426614174000",
  "status": "failed",
  "error": {
    "code": "CONVERSION_FAILED",
    "message": "Unable to convert file: Invalid document structure"
  },
  "metadata": {
    "project_id": "proj_123"
  }
}

Not Found:

{
  "success": false,
  "error": {
    "code": "JOB_NOT_FOUND",
    "message": "The specified job ID was not found or has expired",
    "details": {
      "job_id": "job_invalid"
    }
  }
}

4. Cancel Job

Cancel a conversion job that is queued or in progress.

Endpoint: DELETE /v2/jobs/{jobId}

Response

Success:

{
  "success": true,
  "job_id": "job_123e4567-e89b-12d3-a456-426614174000",
  "status": "cancelled",
  "message": "Conversion job has been cancelled successfully"
}

Not Found:

{
  "success": false,
  "error": {
    "code": "JOB_NOT_FOUND",
    "message": "The specified job ID was not found or has expired",
    "details": {
      "job_id": "job_invalid"
    }
  }
}

5. Delete Conversion File

Permanently delete a completed conversion file and its associated data from storage. This endpoint allows you to immediately remove files before the automatic 24-hour expiration.

Endpoint: DELETE /v2/jobs/{jobId}/destroy

Use Cases

  • Remove sensitive converted files immediately after download
  • Free up storage when conversions are no longer needed
  • Comply with data retention policies
  • Clean up test conversions

Response

Success:

{
  "success": true,
  "message": "Conversion file and associated data have been deleted successfully",
  "job_id": "job_123e4567-e89b-12d3-a456-426614174000",
  "deleted_at": "2024-01-14T15:30:00Z"
}

Job Not Completed:

{
  "success": false,
  "error": {
    "code": "JOB_NOT_COMPLETED",
    "message": "Can only delete completed conversions",
    "details": {
      "job_id": "job_123e4567-e89b-12d3-a456-426614174000",
      "status": "processing"
    }
  }
}

Not Found:

{
  "success": false,
  "error": {
    "code": "JOB_NOT_FOUND",
    "message": "The specified job ID was not found or has expired",
    "details": {
      "job_id": "job_invalid"
    }
  }
}

Example Request

curl -X DELETE https://api.converthub.com/v2/jobs/job_123e4567-e89b-12d3-a456-426614174000/destroy \
  -H "Authorization: Bearer YOUR_API_KEY"

Important Notes

  • This action is irreversible - deleted files cannot be recovered
  • Only completed conversions can be deleted
  • Deleting a conversion also removes:
    • The converted file from R2/S3 storage
    • The job data from cache
    • Any cached conversion results
  • The original uploaded file is automatically deleted after conversion

6. Get Download URL

Get the download URL for a completed conversion.

Endpoint: GET /v2/jobs/{jobId}/download

Response

Success:

{
  "success": true,
  "job_id": "job_123e4567-e89b-12d3-a456-426614174000",
  "download_url": "https://cdn.converthub.com/converted/document.pdf",
  "filename": "document.pdf",
  "format": "pdf",
  "file_size": 1048576,
  "expires_at": "2024-01-15T10:00:00Z"
}

Job Not Completed:

{
  "success": false,
  "error": {
    "code": "JOB_NOT_COMPLETED",
    "message": "The conversion job is not yet completed",
    "details": {
      "job_id": "job_123e4567-e89b-12d3-a456-426614174000",
      "status": "processing"
    }
  }
}

Format Discovery Endpoints

7. List Supported Formats

Get a list of all supported file formats grouped by type.

Endpoint: GET /v2/formats

Response

{
  "success": true,
  "total_formats": 150,
  "formats": {
    "image": [
      {
        "extension": "jpg",
        "mime_type": "image/jpeg"
      },
      {
        "extension": "png",
        "mime_type": "image/png"
      },
      {
        "extension": "webp",
        "mime_type": "image/webp"
      }
    ],
    "document": [
      {
        "extension": "pdf",
        "mime_type": "application/pdf"
      },
      {
        "extension": "docx",
        "mime_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
      }
    ],
    "audio": [
      {
        "extension": "mp3",
        "mime_type": "audio/mpeg"
      },
      {
        "extension": "wav",
        "mime_type": "audio/wav"
      }
    ],
    "video": [
      {
        "extension": "mp4",
        "mime_type": "video/mp4"
      },
      {
        "extension": "webm",
        "mime_type": "video/webm"
      }
    ]
  }
}

8. Get Format Conversions

Get all possible conversions for a specific source format.

Endpoint: GET /v2/formats/{format}/conversions

Response

{
  "success": true,
  "source_format": "png",
  "mime_type": "image/png",
  "type": "image",
  "available_conversions": [
    {
      "target_format": "jpg",
      "mime_type": "image/jpeg"
    },
    {
      "target_format": "webp",
      "mime_type": "image/webp"
    },
    {
      "target_format": "pdf",
      "mime_type": "application/pdf"
    },
    {
      "target_format": "gif",
      "mime_type": "image/gif"
    }
  ],
  "total_conversions": 25
}

Format Not Supported:

{
  "success": false,
  "error": {
    "code": "FORMAT_NOT_SUPPORTED",
    "message": "The format 'xyz' is not supported",
    "details": {
      "format": "xyz"
    }
  }
}

9. Check Conversion Support

Check if a specific format conversion is supported.

Endpoint: GET /v2/formats/{sourceFormat}/to/{targetFormat}

Response

Supported:

{
  "success": true,
  "supported": true,
  "source_format": {
    "extension": "docx",
    "mime_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    "type": "document"
  },
  "target_format": {
    "extension": "pdf",
    "mime_type": "application/pdf",
    "type": "document"
  },
}

Not Supported:

{
  "success": false,
  "supported": false,
  "source_format": "mp3",
  "target_format": "pdf",
  "message": "Conversion from 'mp3' to 'pdf' is not supported"
}

Chunked Upload Endpoints

For large files (over 50MB), you must use chunked upload. This improves reliability, allows resume capability, and bypasses the 50MB limit of the direct upload endpoint.

10. Initialize Chunked Upload

Start a chunked upload session.

Endpoint: POST /v2/upload/init

Request

Parameter Type Required Description
filename string Yes Original filename
file_size integer Yes Total file size in bytes
total_chunks integer Yes Number of chunks
target_format string Yes Target format for conversion
webhook_url string No URL to receive webhook notification when complete
options object No Conversion options
metadata object No Custom metadata

Response

{
  "success": true,
  "session_id": "upload_987f6543-a21b-98c7-d654-321098765432",
  "expires_at": "2024-01-14T12:00:00Z",
  "links": {
    "upload_chunk": "https://api.converthub.com/v2/upload/upload_987f6543-a21b-98c7-d654-321098765432/chunks/{chunkIndex}",
    "complete": "https://api.converthub.com/v2/upload/upload_987f6543-a21b-98c7-d654-321098765432/complete"
  }
}

11. Upload Chunk

Upload a file chunk.

Endpoint: POST /v2/upload/{sessionId}/chunks/{chunkIndex}

Request

Parameter Type Required Description
chunk file Yes The chunk data

Response

{
  "success": true,
  "session_id": "upload_987f6543-a21b-98c7-d654-321098765432",
  "chunk_index": 0,
  "uploaded_chunks": 1,
  "total_chunks": 10
}

12. Complete Chunked Upload

Complete the upload and start conversion.

Endpoint: POST /v2/upload/{sessionId}/complete

Response

Success:

{
  "success": true,
  "job_id": "job_456e7890-f12g-34h5-i678-901234567890",
  "status": "processing",
  "message": "File assembled and conversion started",
  "links": {
    "status": "https://api.converthub.com/v2/jobs/job_456e7890-f12g-34h5-i678-901234567890",
    "cancel": "https://api.converthub.com/v2/jobs/job_456e7890-f12g-34h5-i678-901234567890"
  }
}

Missing Chunks:

{
  "success": false,
  "error": {
    "code": "MISSING_CHUNKS",
    "message": "Not all chunks have been uploaded",
    "details": {
      "missing_chunks": [3, 5, 7],
      "uploaded_chunks": 7,
      "total_chunks": 10
    }
  }
}

13. Health Check

Check API health and statistics.

Endpoint: GET /v2/health

Response

{
  "success": true,
  "status": "healthy",
  "api_version": "v2",
  "timestamp": "2024-01-14T10:00:00Z",
  "stats": {
    "total_formats": 150,
    "total_conversions": 800
  }
}

Complete Examples

Example 1: Simple Image Conversion

Convert a PNG image to JPG format.

PHP

<?php
// PHP example using cURL
function convertImage() {
    $apiKey = 'YOUR_API_KEY';
    $apiUrl = 'https://api.converthub.com/v2';

    // Step 1: Submit file for conversion
    $file = new CURLFile('photo.png', 'image/png', 'photo.png');

    $postData = [
        'file' => $file,
        'target_format' => 'jpg',
        'options[quality]' => '90'
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $apiUrl . '/convert');
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $apiKey
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $response = curl_exec($ch);
    curl_close($ch);

    $job = json_decode($response, true);
    echo "Job created: " . $job['job_id'] . "\n";

    // Step 2: Poll for completion
    $status = 'processing';
    $result = null;

    while ($status === 'processing') {
        sleep(2); // Wait 2 seconds

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $apiUrl . '/jobs/' . $job['job_id']);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Authorization: Bearer ' . $apiKey
        ]);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $response = curl_exec($ch);
        curl_close($ch);

        $result = json_decode($response, true);
        $status = $result['status'];
        echo "Status: " . $status . "\n";
    }

    // Step 3: Get download URL
    if ($status === 'completed') {
        echo "Download URL: " . $result['result']['download_url'] . "\n";
        return $result['result']['download_url'];
    } else {
        echo "Conversion failed: " . $result['error']['message'] . "\n";
    }
}

convertImage();
?>

JavaScript

// Node.js example using fetch
const FormData = require('form-data');
const fs = require('fs');

async function convertImage() {
  // Step 1: Submit file for conversion
  const form = new FormData();
  form.append('file', fs.createReadStream('photo.png'));
  form.append('target_format', 'jpg');
  form.append('options[quality]', '90');

  const submitResponse = await fetch('https://api.converthub.com/v2/convert', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY'
    },
    body: form
  });

  const job = await submitResponse.json();
  console.log('Job created:', job.job_id);

  // Step 2: Poll for completion
  let status = 'processing';
  let result;

  while (status === 'processing') {
    await new Promise(resolve => setTimeout(resolve, 2000)); // Wait 2 seconds

    const statusResponse = await fetch(`https://api.converthub.com/v2/jobs/${job.job_id}`, {
      headers: {
        'Authorization': 'Bearer YOUR_API_KEY'
      }
    });

    result = await statusResponse.json();
    status = result.status;
    console.log('Status:', status);
  }

  // Step 3: Get download URL
  if (status === 'completed') {
    console.log('Download URL:', result.result.download_url);
    return result.result.download_url;
  } else {
    console.error('Conversion failed:', result.error);
  }
}

convertImage();

Ruby

require 'net/http'
require 'uri'
require 'json'

def convert_image
  api_key = 'YOUR_API_KEY'
  api_url = 'https://api.converthub.com/v2'

  # Step 1: Submit file for conversion
  uri = URI("#{api_url}/convert")

  request = Net::HTTP::Post.new(uri)
  request['Authorization'] = "Bearer #{api_key}"

  form_data = [
    ['file', File.open('photo.png')],
    ['target_format', 'jpg'],
    ['options[quality]', '90']
  ]

  request.set_form(form_data, 'multipart/form-data')

  response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
    http.request(request)
  end

  job = JSON.parse(response.body)
  puts "Job created: #{job['job_id']}"

  # Step 2: Poll for completion
  status = 'processing'
  result = nil

  while status == 'processing'
    sleep(2) # Wait 2 seconds

    status_uri = URI("#{api_url}/jobs/#{job['job_id']}")
    status_request = Net::HTTP::Get.new(status_uri)
    status_request['Authorization'] = "Bearer #{api_key}"

    status_response = Net::HTTP.start(status_uri.hostname, status_uri.port, use_ssl: true) do |http|
      http.request(status_request)
    end

    result = JSON.parse(status_response.body)
    status = result['status']
    puts "Status: #{status}"
  end

  # Step 3: Get download URL
  if status == 'completed'
    puts "Download URL: #{result['result']['download_url']}"
    result['result']['download_url']
  else
    puts "Conversion failed: #{result['error']['message']}"
  end
end

convert_image

Python

import requests
import time

def convert_image():
    api_key = 'YOUR_API_KEY'
    api_url = 'https://api.converthub.com/v2'

    # Step 1: Submit file for conversion
    with open('photo.png', 'rb') as f:
        files = {'file': f}
        data = {
            'target_format': 'jpg',
            'options[quality]': '90'
        }

        response = requests.post(
            f'{api_url}/convert',
            headers={'Authorization': f'Bearer {api_key}'},
            files=files,
            data=data
        )

    job = response.json()
    print(f"Job created: {job['job_id']}")

    # Step 2: Poll for completion
    status = 'processing'
    result = None

    while status == 'processing':
        time.sleep(2)  # Wait 2 seconds

        response = requests.get(
            f"{api_url}/jobs/{job['job_id']}",
            headers={'Authorization': f'Bearer {api_key}'}
        )

        result = response.json()
        status = result['status']
        print(f"Status: {status}")

    # Step 3: Get download URL
    if status == 'completed':
        print(f"Download URL: {result['result']['download_url']}")
        return result['result']['download_url']
    else:
        print(f"Conversion failed: {result['error']['message']}")

convert_image()

Example 2: Document Conversion with Webhook

Convert a Word document to PDF with webhook notification.

PHP

<?php
// PHP example with webhook handling
function convertDocument() {
    $apiKey = 'YOUR_API_KEY';
    $apiUrl = 'https://api.converthub.com/v2';

    // Submit conversion with webhook
    $file = new CURLFile('document.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'document.docx');

    $postData = [
        'file' => $file,
        'target_format' => 'pdf',
        'webhook_url' => 'https://your-app.com/webhooks/conversion',
        'metadata[document_id]' => 'doc_123',
        'metadata[user_id]' => 'user_456'
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $apiUrl . '/convert');
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $apiKey
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $response = curl_exec($ch);
    curl_close($ch);

    $job = json_decode($response, true);
    echo "Job ID: " . $job['job_id'] . "\n";
    echo "Webhook will be called when complete\n";

    return $job['job_id'];
}

// Webhook handler (webhook.php)
function handleWebhook() {
    $input = file_get_contents('php://input');
    $data = json_decode($input, true);

    if ($data['status'] === 'completed') {
        echo "Conversion completed!\n";
        echo "Download URL: " . $data['result']['download_url'] . "\n";
        echo "Document ID: " . $data['metadata']['document_id'] . "\n";

        // Download the converted file
        downloadFile($data['result']['download_url']);
    } else {
        echo "Conversion failed: " . $data['error']['message'] . "\n";
    }

    http_response_code(200);
}

function downloadFile($url) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

    $data = curl_exec($ch);
    curl_close($ch);

    file_put_contents('converted_document.pdf', $data);
    echo "File downloaded successfully\n";
}
?>

JavaScript

// Node.js example with Express webhook handler
const FormData = require('form-data');
const fs = require('fs');
const express = require('express');
const fetch = require('node-fetch');

async function convertDocument() {
  // Submit conversion with webhook
  const form = new FormData();
  form.append('file', fs.createReadStream('document.docx'));
  form.append('target_format', 'pdf');
  form.append('webhook_url', 'https://your-app.com/webhooks/conversion');
  form.append('metadata[document_id]', 'doc_123');
  form.append('metadata[user_id]', 'user_456');

  const response = await fetch('https://api.converthub.com/v2/convert', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY'
    },
    body: form
  });

  const job = await response.json();
  console.log(`Job ID: ${job.job_id}`);
  console.log('Webhook will be called when complete');

  return job.job_id;
}

// Webhook handler (Express)
const app = express();
app.use(express.json());

app.post('/webhooks/conversion', async (req, res) => {
  const data = req.body;

  if (data.status === 'completed') {
    console.log('Conversion completed!');
    console.log(`Download URL: ${data.result.download_url}`);
    console.log(`Document ID: ${data.metadata.document_id}`);

    // Download the converted file
    await downloadFile(data.result.download_url);
  } else {
    console.log(`Conversion failed: ${data.error.message}`);
  }

  res.status(200).send();
});

async function downloadFile(url) {
  const response = await fetch(url);
  const buffer = await response.buffer();
  fs.writeFileSync('converted_document.pdf', buffer);
  console.log('File downloaded successfully');
}

app.listen(3000, () => {
  console.log('Webhook server listening on port 3000');
});

Ruby

require 'net/http'
require 'uri'
require 'json'
require 'sinatra'

def convert_document
  api_key = 'YOUR_API_KEY'
  api_url = 'https://api.converthub.com/v2'

  # Submit conversion with webhook
  uri = URI("#{api_url}/convert")

  request = Net::HTTP::Post.new(uri)
  request['Authorization'] = "Bearer #{api_key}"

  form_data = [
    ['file', File.open('document.docx')],
    ['target_format', 'pdf'],
    ['webhook_url', 'https://your-app.com/webhooks/conversion'],
    ['metadata[document_id]', 'doc_123'],
    ['metadata[user_id]', 'user_456']
  ]

  request.set_form(form_data, 'multipart/form-data')

  response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
    http.request(request)
  end

  job = JSON.parse(response.body)
  puts "Job ID: #{job['job_id']}"
  puts "Webhook will be called when complete"

  job['job_id']
end

# Webhook handler (Sinatra)
post '/webhooks/conversion' do
  request.body.rewind
  data = JSON.parse(request.body.read)

  if data['status'] == 'completed'
    puts "Conversion completed!"
    puts "Download URL: #{data['result']['download_url']}"
    puts "Document ID: #{data['metadata']['document_id']}"

    # Download the converted file
    download_file(data['result']['download_url'])
  else
    puts "Conversion failed: #{data['error']['message']}"
  end

  status 200
  ''
end

def download_file(url)
  uri = URI(url)
  response = Net::HTTP.get_response(uri)

  File.open('converted_document.pdf', 'wb') do |file|
    file.write(response.body)
  end

  puts "File downloaded successfully"
end

Python

# Python example using requests and Flask
import requests
from flask import Flask, request

def convert_document():
    api_key = 'YOUR_API_KEY'
    api_url = 'https://api.converthub.com/v2'

    # Submit conversion with webhook
    with open('document.docx', 'rb') as f:
        files = {'file': f}
        data = {
            'target_format': 'pdf',
            'webhook_url': 'https://your-app.com/webhooks/conversion',
            'metadata[document_id]': 'doc_123',
            'metadata[user_id]': 'user_456'
        }

        response = requests.post(
            f'{api_url}/convert',
            headers={'Authorization': f'Bearer {api_key}'},
            files=files,
            data=data
        )

    job = response.json()
    print(f"Job ID: {job['job_id']}")
    print("Webhook will be called when complete")

    return job['job_id']

# Webhook handler (Flask)
app = Flask(__name__)

@app.route('/webhooks/conversion', methods=['POST'])
def handle_conversion_webhook():
    data = request.json

    if data['status'] == 'completed':
        print("Conversion completed!")
        print(f"Download URL: {data['result']['download_url']}")
        print(f"Document ID: {data['metadata']['document_id']}")

        # Download the converted file
        download_file(data['result']['download_url'])
    else:
        print(f"Conversion failed: {data['error']['message']}")

    return '', 200

def download_file(url):
    response = requests.get(url)
    with open('converted_document.pdf', 'wb') as f:
        f.write(response.content)
    print("File downloaded successfully")

if __name__ == '__main__':
    app.run(port=3000)

Example 3: Convert File from URL

Convert a file by providing its URL instead of uploading it directly.

PHP

<?php
// PHP example for URL-based conversion
function convertFromUrl() {
    $apiKey = 'YOUR_API_KEY';
    $apiUrl = 'https://api.converthub.com/v2';

    // Step 1: Submit URL for conversion
    $data = [
        'file_url' => 'https://example.com/document.pdf',
        'target_format' => 'docx',
        'output_filename' => 'converted_document.docx',
        'metadata' => [
            'source' => 'url_conversion',
            'user_id' => 'user_123'
        ]
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $apiUrl . '/convert-url');
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json'
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($httpCode !== 202) {
        $error = json_decode($response, true);
        echo "Error: " . $error['error']['message'] . "\n";
        return;
    }

    $job = json_decode($response, true);
    echo "Job created: " . $job['job_id'] . "\n";

    // Step 2: Poll for completion
    $status = 'processing';
    $result = null;
    $maxAttempts = 30;
    $attempt = 0;

    while ($status === 'processing' && $attempt < $maxAttempts) {
        sleep(2); // Wait 2 seconds between checks
        $attempt++;

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $apiUrl . '/jobs/' . $job['job_id']);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Authorization: Bearer ' . $apiKey
        ]);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $response = curl_exec($ch);
        curl_close($ch);

        $result = json_decode($response, true);
        $status = $result['status'];
        echo "Status: " . $status . "\n";
    }

    // Step 3: Handle result
    if ($status === 'completed') {
        echo "Conversion completed!\n";
        echo "Download URL: " . $result['result']['download_url'] . "\n";

        // Download the converted file
        $ch = curl_init($result['result']['download_url']);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        $fileContent = curl_exec($ch);
        curl_close($ch);

        file_put_contents('converted_document.docx', $fileContent);
        echo "File downloaded successfully\n";
    } else {
        echo "Conversion failed: " . ($result['error']['message'] ?? 'Unknown error') . "\n";
    }
}

convertFromUrl();
?>

JavaScript (Node.js)

// Node.js example for URL-based conversion
const fetch = require('node-fetch');
const fs = require('fs');
const https = require('https');

async function convertFromUrl() {
    const apiKey = 'YOUR_API_KEY';
    const apiUrl = 'https://api.converthub.com/v2';

    try {
        // Step 1: Submit URL for conversion
        const submitResponse = await fetch(`${apiUrl}/convert-url`, {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${apiKey}`,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                file_url: 'https://example.com/image.png',
                target_format: 'jpg',
                output_filename: 'converted_image.jpg',
                metadata: {
                    source: 'url_conversion',
                    user_id: 'user_123'
                }
            })
        });

        if (!submitResponse.ok) {
            const error = await submitResponse.json();
            console.error('Error:', error.error.message);
            return;
        }

        const job = await submitResponse.json();
        console.log(`Job created: ${job.job_id}`);

        // Step 2: Poll for completion
        let status = 'processing';
        let result = null;
        let attempts = 0;
        const maxAttempts = 30;

        while (status === 'processing' && attempts < maxAttempts) {
            await new Promise(resolve => setTimeout(resolve, 2000)); // Wait 2 seconds
            attempts++;

            const statusResponse = await fetch(`${apiUrl}/jobs/${job.job_id}`, {
                headers: {
                    'Authorization': `Bearer ${apiKey}`
                }
            });

            result = await statusResponse.json();
            status = result.status;
            console.log(`Status: ${status}`);
        }

        // Step 3: Handle result
        if (status === 'completed') {
            console.log('Conversion completed!');
            console.log(`Download URL: ${result.result.download_url}`);

            // Download the converted file
            const file = fs.createWriteStream('converted_image.jpg');
            https.get(result.result.download_url, (response) => {
                response.pipe(file);
                file.on('finish', () => {
                    file.close();
                    console.log('File downloaded successfully');
                });
            });
        } else {
            console.error('Conversion failed:', result.error?.message || 'Unknown error');
        }
    } catch (error) {
        console.error('Error:', error.message);
    }
}

convertFromUrl();

Ruby

# Ruby example for URL-based conversion
require 'net/http'
require 'json'
require 'uri'

def convert_from_url
  api_key = 'YOUR_API_KEY'
  api_url = 'https://api.converthub.com/v2'

  # Step 1: Submit URL for conversion
  uri = URI("#{api_url}/convert-url")
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true

  request = Net::HTTP::Post.new(uri)
  request['Authorization'] = "Bearer #{api_key}"
  request['Content-Type'] = 'application/json'
  request.body = {
    file_url: 'https://example.com/presentation.pptx',
    target_format: 'pdf',
    output_filename: 'converted_presentation.pdf',
    metadata: {
      source: 'url_conversion',
      user_id: 'user_123'
    }
  }.to_json

  response = http.request(request)

  if response.code != '202'
    error = JSON.parse(response.body)
    puts "Error: #{error['error']['message']}"
    return
  end

  job = JSON.parse(response.body)
  puts "Job created: #{job['job_id']}"

  # Step 2: Poll for completion
  status = 'processing'
  result = nil
  max_attempts = 30
  attempt = 0

  while status == 'processing' && attempt < max_attempts
    sleep(2) # Wait 2 seconds
    attempt += 1

    uri = URI("#{api_url}/jobs/#{job['job_id']}")
    request = Net::HTTP::Get.new(uri)
    request['Authorization'] = "Bearer #{api_key}"

    response = http.request(request)
    result = JSON.parse(response.body)
    status = result['status']
    puts "Status: #{status}"
  end

  # Step 3: Handle result
  if status == 'completed'
    puts 'Conversion completed!'
    puts "Download URL: #{result['result']['download_url']}"

    # Download the converted file
    download_uri = URI(result['result']['download_url'])
    download_response = Net::HTTP.get_response(download_uri)

    File.open('converted_presentation.pdf', 'wb') do |file|
      file.write(download_response.body)
    end

    puts 'File downloaded successfully'
  else
    puts "Conversion failed: #{result['error']['message'] || 'Unknown error'}"
  end
end

convert_from_url

Python

# Python example for URL-based conversion
import requests
import time
import json

def convert_from_url():
    api_key = 'YOUR_API_KEY'
    api_url = 'https://api.converthub.com/v2'

    # Step 1: Submit URL for conversion
    headers = {
        'Authorization': f'Bearer {api_key}',
        'Content-Type': 'application/json'
    }

    data = {
        'file_url': 'https://example.com/video.mov',
        'target_format': 'mp4',
        'output_filename': 'converted_video.mp4',
        'metadata': {
            'source': 'url_conversion',
            'user_id': 'user_123'
        }
    }

    response = requests.post(
        f'{api_url}/convert-url',
        headers=headers,
        json=data
    )

    if response.status_code != 202:
        error = response.json()
        print(f"Error: {error['error']['message']}")
        return

    job = response.json()
    print(f"Job created: {job['job_id']}")

    # Step 2: Poll for completion
    status = 'processing'
    result = None
    max_attempts = 30
    attempt = 0

    while status == 'processing' and attempt < max_attempts:
        time.sleep(2)  # Wait 2 seconds
        attempt += 1

        response = requests.get(
            f"{api_url}/jobs/{job['job_id']}",
            headers={'Authorization': f'Bearer {api_key}'}
        )

        result = response.json()
        status = result['status']
        print(f"Status: {status}")

    # Step 3: Handle result
    if status == 'completed':
        print('Conversion completed!')
        download_url = result['result']['download_url']
        print(f"Download URL: {download_url}")

        # Download the converted file
        download_response = requests.get(download_url)

        with open('converted_video.mp4', 'wb') as f:
            f.write(download_response.content)

        print('File downloaded successfully')
    else:
        error_msg = result.get('error', {}).get('message', 'Unknown error')
        print(f"Conversion failed: {error_msg}")

if __name__ == '__main__':
    convert_from_url()

Example 4: Chunked Upload for Large Files

Upload a large video file in chunks.

PHP

<?php
// PHP example for chunked upload
function uploadLargeFile($filePath) {
    $apiKey = 'YOUR_API_KEY';
    $apiUrl = 'https://api.converthub.com/v2';

    $fileSize = filesize($filePath);
    $chunkSize = 5 * 1024 * 1024; // 5MB chunks
    $totalChunks = ceil($fileSize / $chunkSize);

    // Step 1: Initialize session
    $initData = [
        'filename' => basename($filePath),
        'file_size' => $fileSize,
        'total_chunks' => $totalChunks,
        'target_format' => 'mp4',
        'webhook_url' => 'https://your-app.com/webhooks/conversion-complete',
        'metadata' => [
            'user_id' => 'user_123',
            'project_id' => 'proj_456'
        ]
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $apiUrl . '/upload/init');
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($initData));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json'
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $response = curl_exec($ch);
    curl_close($ch);

    $session = json_decode($response, true);
    echo "Upload session created: " . $session['session_id'] . "\n";

    // Step 2: Upload chunks
    $handle = fopen($filePath, 'rb');

    for ($i = 0; $i < $totalChunks; $i++) {

        $chunkData = fread($handle, $chunkSize);

        $tmp = tmpfile();
        fwrite($tmp, $chunkData);
        $meta = stream_get_meta_data($tmp);
        $tmpFilePath = $meta['uri'];

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $apiUrl . '/upload/' . $session['session_id'] . '/chunks/' . $i);
        curl_setopt($ch, CURLOPT_POST, true);

        $postData = [
            'chunk' => new CURLFile($tmpFilePath)
        ];

        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Authorization: Bearer ' . $apiKey
        ]);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $chunkResponse = curl_exec($ch);
        curl_close($ch);

        fclose($tmp);

        echo "Uploaded chunk " . ($i + 1) . "/" . $totalChunks . "\n";
    }

    fclose($handle);

    // Step 3: Complete upload and start conversion
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $apiUrl . '/upload/' . $session['session_id'] . '/complete');
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $apiKey
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $completeResponse = curl_exec($ch);
    curl_close($ch);

    $job = json_decode($completeResponse, true);
    echo "Conversion started: " . $job['job_id'] . "\n";

    return $job['job_id'];
}

uploadLargeFile('large_video.mov');
?>

JavaScript

// JavaScript example for chunked upload (browser/Node.js)
async function uploadLargeFile(file) {
  const CHUNK_SIZE = 5 * 1024 * 1024; // 5MB chunks
  const totalChunks = Math.ceil(file.size / CHUNK_SIZE);

  // Step 1: Initialize session
  const initResponse = await fetch('https://api.converthub.com/v2/upload/init', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      filename: file.name,
      file_size: file.size,
      total_chunks: totalChunks,
      target_format: 'mp4',
      webhook_url: 'https://your-app.com/webhooks/conversion-complete',
      metadata: {
        user_id: 'user_123',
        project_id: 'proj_456'
      }
    })
  });

  const session = await initResponse.json();
  console.log('Upload session created:', session.session_id);

  // Step 2: Upload chunks
  for (let i = 0; i < totalChunks; i++) {
    const start = i * CHUNK_SIZE;
    const end = Math.min(start + CHUNK_SIZE, file.size);
    const chunk = file.slice(start, end);

    const formData = new FormData();
    formData.append('chunk', chunk);

    const chunkResponse = await fetch(
      `https://api.converthub.com/v2/upload/${session.session_id}/chunks/${i}`,
      {
        method: 'POST',
        headers: {
          'Authorization': 'Bearer YOUR_API_KEY'
        },
        body: formData
      }
    );

    const chunkResult = await chunkResponse.json();
    console.log(`Uploaded chunk ${i + 1}/${totalChunks}`);
  }

  // Step 3: Complete upload and start conversion
  const completeResponse = await fetch(
    `https://api.converthub.com/v2/upload/${session.session_id}/complete`,
    {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer YOUR_API_KEY'
      }
    }
  );

  const job = await completeResponse.json();
  console.log('Conversion started:', job.job_id);

  return job.job_id;
}

// Node.js file reading example
const fs = require('fs');
const fileBuffer = fs.readFileSync('large_video.mov');
const file = new File([fileBuffer], 'large_video.mov');
uploadLargeFile(file);

Ruby

require 'net/http'
require 'uri'
require 'json'

def upload_large_file(file_path)
  api_key = 'YOUR_API_KEY'
  api_url = 'https://api.converthub.com/v2'

  file_size = File.size(file_path)
  chunk_size = 5 * 1024 * 1024 # 5MB chunks
  total_chunks = (file_size.to_f / chunk_size).ceil

  # Step 1: Initialize session
  init_uri = URI("#{api_url}/upload/init")

  init_data = {
    filename: File.basename(file_path),
    file_size: file_size,
    total_chunks: total_chunks,
    target_format: 'mp4',
    webhook_url: 'https://your-app.com/webhooks/conversion-complete',
    metadata: {
      user_id: 'user_123',
      project_id: 'proj_456'
    }
  }

  init_request = Net::HTTP::Post.new(init_uri)
  init_request['Authorization'] = "Bearer #{api_key}"
  init_request['Content-Type'] = 'application/json'
  init_request.body = init_data.to_json

  init_response = Net::HTTP.start(init_uri.hostname, init_uri.port, use_ssl: true) do |http|
    http.request(init_request)
  end

  session = JSON.parse(init_response.body)
  puts "Upload session created: #{session['session_id']}"

  # Step 2: Upload chunks
  File.open(file_path, 'rb') do |file|
    total_chunks.times do |i|
      chunk = file.read(chunk_size)

      chunk_uri = URI("#{api_url}/upload/#{session['session_id']}/chunks/#{i}")
      chunk_request = Net::HTTP::Post.new(chunk_uri)
      chunk_request['Authorization'] = "Bearer #{api_key}"

      form_data = [['chunk', chunk, {filename: 'chunk', content_type: 'application/octet-stream'}]]
      chunk_request.set_form(form_data, 'multipart/form-data')

      Net::HTTP.start(chunk_uri.hostname, chunk_uri.port, use_ssl: true) do |http|
        http.request(chunk_request)
      end

      puts "Uploaded chunk #{i + 1}/#{total_chunks}"
    end
  end

  # Step 3: Complete upload and start conversion
  complete_uri = URI("#{api_url}/upload/#{session['session_id']}/complete")
  complete_request = Net::HTTP::Post.new(complete_uri)
  complete_request['Authorization'] = "Bearer #{api_key}"

  complete_response = Net::HTTP.start(complete_uri.hostname, complete_uri.port, use_ssl: true) do |http|
    http.request(complete_request)
  end

  job = JSON.parse(complete_response.body)
  puts "Conversion started: #{job['job_id']}"

  job['job_id']
end

upload_large_file('large_video.mov')

Python

import requests
import os
import math

def upload_large_file(file_path):
    api_key = 'YOUR_API_KEY'
    api_url = 'https://api.converthub.com/v2'

    file_size = os.path.getsize(file_path)
    chunk_size = 5 * 1024 * 1024  # 5MB chunks
    total_chunks = math.ceil(file_size / chunk_size)

    # Step 1: Initialize session
    init_data = {
        'filename': os.path.basename(file_path),
        'file_size': file_size,
        'total_chunks': total_chunks,
        'target_format': 'mp4',
        'webhook_url': 'https://your-app.com/webhooks/conversion-complete',
        'metadata': {
            'user_id': 'user_123',
            'project_id': 'proj_456'
        }
    }

    init_response = requests.post(
        f'{api_url}/upload/init',
        headers={
            'Authorization': f'Bearer {api_key}',
            'Content-Type': 'application/json'
        },
        json=init_data
    )

    session = init_response.json()
    print(f"Upload session created: {session['session_id']}")

    # Step 2: Upload chunks
    with open(file_path, 'rb') as file:
        for i in range(total_chunks):
            chunk = file.read(chunk_size)

            files = {'chunk': ('chunk', chunk, 'application/octet-stream')}

            chunk_response = requests.post(
                f"{api_url}/upload/{session['session_id']}/chunks/{i}",
                headers={'Authorization': f'Bearer {api_key}'},
                files=files
            )

            print(f"Uploaded chunk {i + 1}/{total_chunks}")

    # Step 3: Complete upload and start conversion
    complete_response = requests.post(
        f"{api_url}/upload/{session['session_id']}/complete",
        headers={'Authorization': f'Bearer {api_key}'}
    )

    job = complete_response.json()
    print(f"Conversion started: {job['job_id']}")

    return job['job_id']

upload_large_file('large_video.mov')

Example 4: Audio Conversion with Options

Convert an audio file with specific quality settings.

PHP

<?php
// PHP example for audio conversion
function convertAudio($filePath) {
    $apiKey = 'YOUR_API_KEY';
    $apiUrl = 'https://api.converthub.com/v2';

    // Submit conversion
    $file = new CURLFile($filePath, 'audio/wav', basename($filePath));

    $postData = [
        'file' => $file,
        'target_format' => 'mp3',
        'options[bitrate]' => '320k',
        'options[sample_rate]' => '44100',
        'output_filename' => 'converted_audio.mp3'
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $apiUrl . '/convert');
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $apiKey
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $response = curl_exec($ch);
    curl_close($ch);

    $job = json_decode($response, true);
    echo "Job ID: " . $job['job_id'] . "\n";

    // Check status
    while (true) {
        sleep(2);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $apiUrl . '/jobs/' . $job['job_id']);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Authorization: Bearer ' . $apiKey
        ]);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $statusResponse = curl_exec($ch);
        curl_close($ch);

        $result = json_decode($statusResponse, true);

        switch ($result['status']) {
            case 'completed':
                echo "Download URL: " . $result['result']['download_url'] . "\n";
                return $result['result']['download_url'];
            case 'failed':
                echo "Conversion failed: " . $result['error']['message'] . "\n";
                return null;
            default:
                echo "Status: " . $result['status'] . "\n";
        }
    }
}

convertAudio('podcast.wav');
?>

JavaScript

// Node.js example for audio conversion
const FormData = require('form-data');
const fs = require('fs');

async function convertAudio(filePath) {
  // Submit conversion
  const form = new FormData();
  form.append('file', fs.createReadStream(filePath));
  form.append('target_format', 'mp3');
  form.append('options[bitrate]', '320k');
  form.append('options[sample_rate]', '44100');
  form.append('output_filename', 'converted_audio.mp3');

  const submitResponse = await fetch('https://api.converthub.com/v2/convert', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY'
    },
    body: form
  });

  const job = await submitResponse.json();
  console.log(`Job ID: ${job.job_id}`);

  // Check status
  while (true) {
    await new Promise(resolve => setTimeout(resolve, 2000));

    const statusResponse = await fetch(`https://api.converthub.com/v2/jobs/${job.job_id}`, {
      headers: {
        'Authorization': 'Bearer YOUR_API_KEY'
      }
    });

    const result = await statusResponse.json();

    switch (result.status) {
      case 'completed':
        console.log(`Download URL: ${result.result.download_url}`);
        return result.result.download_url;
      case 'failed':
        console.log(`Conversion failed: ${result.error.message}`);
        return null;
      default:
        console.log(`Status: ${result.status}`);
    }
  }
}

convertAudio('podcast.wav');

Ruby

require 'net/http'
require 'uri'
require 'json'

def convert_audio(file_path)
  api_key = 'YOUR_API_KEY'
  api_url = 'https://api.converthub.com/v2'

  # Submit conversion
  uri = URI("#{api_url}/convert")

  request = Net::HTTP::Post.new(uri)
  request['Authorization'] = "Bearer #{api_key}"

  form_data = [
    ['file', File.open(file_path)],
    ['target_format', 'mp3'],
    ['options[bitrate]', '320k'],
    ['options[sample_rate]', '44100'],
    ['output_filename', 'converted_audio.mp3']
  ]

  request.set_form(form_data, 'multipart/form-data')

  response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
    http.request(request)
  end

  job = JSON.parse(response.body)
  puts "Job ID: #{job['job_id']}"

  # Check status
  loop do
    sleep(2)

    status_uri = URI("#{api_url}/jobs/#{job['job_id']}")
    status_request = Net::HTTP::Get.new(status_uri)
    status_request['Authorization'] = "Bearer #{api_key}"

    status_response = Net::HTTP.start(status_uri.hostname, status_uri.port, use_ssl: true) do |http|
      http.request(status_request)
    end

    result = JSON.parse(status_response.body)

    case result['status']
    when 'completed'
      puts "Download URL: #{result['result']['download_url']}"
      return result['result']['download_url']
    when 'failed'
      puts "Conversion failed: #{result['error']['message']}"
      return nil
    else
      puts "Status: #{result['status']}"
    end
  end
end

convert_audio('podcast.wav')

Python

import requests
import time

def convert_audio(file_path):
    api_key = 'YOUR_API_KEY'
    api_url = 'https://api.converthub.com/v2'

    # Submit conversion
    with open(file_path, 'rb') as f:
        files = {'file': f}
        data = {
            'target_format': 'mp3',
            'options[bitrate]': '320k',
            'options[sample_rate]': '44100',
            'output_filename': 'converted_audio.mp3'
        }

        response = requests.post(
            f'{api_url}/convert',
            headers={'Authorization': f'Bearer {api_key}'},
            files=files,
            data=data
        )

    job = response.json()
    print(f"Job ID: {job['job_id']}")

    # Check status
    while True:
        time.sleep(2)

        status_response = requests.get(
            f"{api_url}/jobs/{job['job_id']}",
            headers={'Authorization': f'Bearer {api_key}'}
        )

        result = status_response.json()

        if result['status'] == 'completed':
            print(f"Download URL: {result['result']['download_url']}")
            return result['result']['download_url']
        elif result['status'] == 'failed':
            print(f"Conversion failed: {result['error']['message']}")
            return None
        else:
            print(f"Status: {result['status']}")

convert_audio('podcast.wav')

Error Handling

Error Codes

Code Description HTTP Status
Authentication & Authorization Errors
AUTHENTICATION_REQUIRED No Bearer token provided in Authorization header 401
NO_MEMBERSHIP No active membership found for the authenticated user 403
MEMBERSHIP_INACTIVE Membership is expired or inactive 403
INSUFFICIENT_CREDITS Not enough credits for this conversion 402
FILE_SIZE_EXCEEDS_PLAN_LIMIT File size exceeds your plan's limit 413
Validation Errors
VALIDATION_ERROR Request validation failed - missing or invalid parameters 400
FILE_TOO_LARGE File size exceeds 50MB limit for direct upload (use chunked upload instead) 413
UNSUPPORTED_SOURCE_FORMAT The source file format is not supported 400
UNSUPPORTED_TARGET_FORMAT The target format is not supported 400
CONVERSION_NOT_SUPPORTED The specific format conversion is not available 400
Processing Errors
CONVERSION_FAILED The conversion process failed 500
CONVERSION_ERROR General conversion error 500
JOB_NOT_FOUND The job ID doesn't exist or has expired 404
JOB_NOT_COMPLETED The job hasn't finished processing 400
Format Errors
FORMAT_NOT_SUPPORTED The specified format is not recognized 404
SOURCE_FORMAT_NOT_SUPPORTED Source format in conversion check is not supported 404
TARGET_FORMAT_NOT_SUPPORTED Target format in conversion check is not supported 404
Upload Errors
SESSION_NOT_FOUND Upload session not found or expired 404
INVALID_CHUNK_INDEX Chunk index exceeds total chunks 400
MISSING_CHUNKS Not all chunks have been uploaded 400
CHUNK_NOT_FOUND Chunk file not found during assembly 500
Rate Limiting
RATE_LIMIT_EXCEEDED Too many requests - rate limit has been exceeded 429

Error Response Examples

Authentication Required (401)

{
  "success": false,
  "error": {
    "code": "AUTHENTICATION_REQUIRED",
    "message": "Authentication is required to use the conversion API",
    "details": {
      "hint": "Please include a valid Bearer token in the Authorization header"
    }
  }
}

No Membership (403)

{
  "success": false,
  "error": {
    "code": "NO_MEMBERSHIP",
    "message": "No active membership found for your account",
    "details": {
      "user_id": 12345,
      "hint": "Please subscribe to a plan to use the API"
    }
  }
}

Membership Inactive (403)

{
  "success": false,
  "error": {
    "code": "MEMBERSHIP_INACTIVE",
    "message": "Your membership is not active",
    "details": {
      "status": "expired",
      "reason": "Membership expired on 2024-01-01 00:00:00",
      "plan": "Basic",
      "hint": "Please renew your membership to continue using the API"
    }
  }
}

Insufficient Credits (402)

{
  "success": false,
  "error": {
    "code": "INSUFFICIENT_CREDITS",
    "message": "You have insufficient credits for this conversion",
    "details": {
      "current_credits": 0,
      "credits_required": 1,
      "plan": "Free",
      "hint": "Please upgrade your plan or wait for your monthly credit reset"
    }
  }
}

File Size Exceeds Plan Limit (413)

{
  "success": false,
  "error": {
    "code": "FILE_SIZE_EXCEEDS_PLAN_LIMIT",
    "message": "File size exceeds your plan's limit",
    "details": {
      "file_size": 104857600,
      "file_size_mb": 100,
      "plan_limit": 52428800,
      "plan_limit_mb": 50,
      "plan": "Basic",
      "hint": "Please upgrade to a higher plan to convert larger files"
    }
  }
}

Best Practices

  1. Ensure authentication - Always include your Bearer token in the Authorization header
  2. Monitor credit usage - Track your remaining credits to avoid interruptions
  3. Check plan limits - Be aware of your plan's file size limits before uploading
  4. Check file size before uploading - use chunked upload for files over 50MB
  5. Always check job status before attempting to download
  6. Implement exponential backoff when polling for job status
  7. Handle errors gracefully with proper retry logic
  8. Use webhooks for production applications to avoid polling
  9. Cache job IDs to resume checking status after interruptions
  10. Validate file formats before submission using the format endpoints
  11. Use chunked uploads for files larger than 50MB to avoid timeout and size limits

Rate Limits

All API endpoints are protected by rate limiting to ensure fair usage and protect the service from abuse. Rate limits are applied per user (authenticated) or per IP address (unauthenticated).

Rate Limit Headers

Every API response includes headers that provide information about your current rate limit status:

Header Description
X-RateLimit-Limit Maximum number of requests allowed in the current window
X-RateLimit-Remaining Number of requests remaining in the current window
X-RateLimit-Reset Unix timestamp when the rate limit window resets
Retry-After Number of seconds to wait before retrying (only included when rate limited)

Endpoint Rate Limits

Endpoint Category Rate Limit Description
Conversion 60/minute Main conversion endpoint (POST /v2/convert)
Job Management 100/minute Job status, cancellation, and download endpoints
Chunked Upload 500/minute Upload initialization, chunk upload, and completion
Format Discovery 200/minute Format listing and conversion support checks
Health Check 60/minute API health status endpoint

Rate Limit Response

When you exceed the rate limit, the API returns a 429 Too Many Requests response:

{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many conversion requests. Please wait before trying again.",
    "details": {
      "retry_after": 30,
      "limit": 60,
      "window": "1 minute"
    }
  }
}

Best Practices

  1. Monitor rate limit headers - Check the X-RateLimit-Remaining header to avoid hitting limits
  2. Implement exponential backoff - When rate limited, wait for the Retry-After duration before retrying
  3. Cache responses - Store format information and reuse it instead of repeatedly querying
  4. Use webhooks - Avoid polling job status by using webhook notifications
  5. Batch operations - Combine multiple operations where possible
  6. Distribute requests - Spread requests evenly over time rather than bursting

Additional Limits

  • Concurrent conversions: 10 active conversions per user
  • Result retention: Converted files are available for download for 24 hours
  • Maximum file size: 50MB for direct upload (use chunked upload for larger files)

Data Retention & Caching

File Retention Policy

ConvertHub follows strict data retention policies to ensure your data privacy and optimize storage:

Converted Files

  • Retention Period: 24 hours
  • Access: Files remain accessible via the download URL for 24 hours after conversion
  • Automatic Deletion: Converted files are permanently deleted after 24 hours
  • Manual Deletion: Use the DELETE /v2/jobs/{jobId}/destroy endpoint to immediately delete files
  • No Recovery: Once deleted, files cannot be recovered

Source Files

  • Immediate Deletion: Source files are deleted immediately after successful conversion
  • Privacy First: We do not retain copies of your original files
  • Failed Conversions: Source files are also deleted if conversion fails

Early Deletion Option

You can manually delete converted files before the 24-hour automatic expiration using the destroy endpoint:

  • Endpoint: DELETE /v2/jobs/{jobId}/destroy
  • Use Cases:
    • Immediate removal of sensitive data
    • Compliance with data retention policies
    • Storage optimization for high-volume users
  • Requirements: Only completed conversions can be deleted
  • Effect: Removes the file from storage and all associated cache data

Smart Caching

ConvertHub implements intelligent caching to improve performance and reduce processing time:

Cache Behavior

  • Automatic Detection: When you convert the same file to the same format with identical options
  • Cache Duration: 24 hours
  • Instant Results: Cached conversions return immediately without reprocessing
  • Cost Effective: Cached conversions do not consume additional credits

Cache Key Components

The cache system considers:

  • File content (hash)
  • Target format
  • Conversion options (quality, resolution, etc.)
  • Any option change creates a new cache entry

Example Timeline

Hour 0:   Upload file.pdf → Convert to .docx → Processing
Hour 0.1: Conversion complete → Source file deleted
Hour 1:   Same file.pdf → Convert to .docx → Instant (from cache, no credits used)
Hour 12:  Download converted.docx → Success
Hour 24:  Converted file deleted → Download URL expires
Hour 25:  Same file.pdf → Convert to .docx → Processing (cache expired)

Best Practices

  1. Download Important Files Promptly: Save converted files within 24 hours
  2. Leverage Caching: Resubmit identical conversions for instant results
  3. Plan Batch Operations: Convert variations within the cache window
  4. No Long-term Storage: ConvertHub is not a file storage service
  5. GDPR Compliant: Automatic deletion ensures data privacy compliance

Security & Privacy

  • Encryption: All files are encrypted at rest and in transit
  • Isolation: Each user's files are isolated and inaccessible to others
  • No Manual Access: Automated systems only, no human access to files
  • Audit Logs: All file operations are logged for security purposes
  • Permanent Deletion: Files are securely overwritten when deleted

Webhooks

When providing a webhook_url, ConvertHub will send a POST request to your endpoint when the conversion completes.

Webhook Payload

Success:

{
  "event": "conversion.completed",
  "job_id": "job_123e4567-e89b-12d3-a456-426614174000",
  "status": "completed",
  "result": {
    "download_url": "https://cdn.converthub.com/converted/file.pdf",
    "format": "pdf",
    "file_size": 1048576,
    "expires_at": "2024-01-15T10:00:00Z"
  },
  "metadata": {
    "your_custom_field": "value"
  },
  "timestamp": "2024-01-14T10:15:30Z"
}

Failure:

{
  "event": "conversion.failed",
  "job_id": "job_123e4567-e89b-12d3-a456-426614174000",
  "status": "failed",
  "error": {
    "code": "CONVERSION_FAILED",
    "message": "Unable to process file"
  },
  "metadata": {
    "your_custom_field": "value"
  },
  "timestamp": "2024-01-14T10:15:30Z"
}

SDK Support

Official SDKs are planned for:

  • JavaScript/TypeScript
  • Python
  • PHP
  • Ruby
  • Go

Support

For API support, please contact:


Changelog

Version 2.0.0 (Current)

  • Initial v2 API release
  • Job-based asynchronous processing
  • Improved error handling with error codes
  • Chunked upload support
  • Webhook notifications
  • Format discovery endpoints
  • Metadata support for tracking

Last updated: August 2025