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:
- Sign up for a developer account at https://converthub.com/api/signup
- Choose a developer plan that fits your needs
- Navigate to your dashboard
- Generate a new API key in the API Keys section
- 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
- Submit a file for conversion using
POST /v2/convert
- Receive a job ID to track the conversion
- Check job status using
GET /v2/jobs/{jobId}
- 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://
orhttps://
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 processedprocessing
- Conversion is in progresscompleted
- Conversion finished successfullyfailed
- 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
- Ensure authentication - Always include your Bearer token in the Authorization header
- Monitor credit usage - Track your remaining credits to avoid interruptions
- Check plan limits - Be aware of your plan's file size limits before uploading
- Check file size before uploading - use chunked upload for files over 50MB
- Always check job status before attempting to download
- Implement exponential backoff when polling for job status
- Handle errors gracefully with proper retry logic
- Use webhooks for production applications to avoid polling
- Cache job IDs to resume checking status after interruptions
- Validate file formats before submission using the format endpoints
- 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
- Monitor rate limit headers - Check the
X-RateLimit-Remaining
header to avoid hitting limits - Implement exponential backoff - When rate limited, wait for the
Retry-After
duration before retrying - Cache responses - Store format information and reuse it instead of repeatedly querying
- Use webhooks - Avoid polling job status by using webhook notifications
- Batch operations - Combine multiple operations where possible
- 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
- Download Important Files Promptly: Save converted files within 24 hours
- Leverage Caching: Resubmit identical conversions for instant results
- Plan Batch Operations: Convert variations within the cache window
- No Long-term Storage: ConvertHub is not a file storage service
- 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:
- Email: [email protected]
- Documentation: https://converthub.com/api/docs
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