CloudConvert is a capable, well-documented file conversion API. But its per-minute billing creates unpredictable costs, and its async job system adds 3–5 lines of polling code to every integration. If your use case is straightforward — upload a file, get a converted file back — you're paying for infrastructure you're not using.

ChangeThisFile is a direct conversion API: one POST endpoint, synchronous response, flat per-conversion pricing. No job IDs, no polling, no webhook registration, no SDK required. This guide walks through every step of migrating an existing CloudConvert integration.

Why people migrate from CloudConvert

Unpredictable billing. CloudConvert bills per conversion-minute — the wall-clock time a job runs on their servers. A simple DOCX-to-PDF that takes 8 seconds rounds up to 1 minute. Fast document batches are fine; heavy PDF workflows or anything that varies in processing time creates invoices you can't predict. Several developers report 2–3× monthly cost variance at identical request volumes.

Async overhead for simple use cases. CloudConvert's job system is powerful but verbose: create a job, get a job ID, poll until status is finished or use a webhook, then download the result. For "convert this file" workflows, this is 40–60 extra lines of boilerplate that adds latency and complexity.

No free tier. CloudConvert has no ongoing free API tier. Every test costs money. ChangeThisFile gives you 1,000 free conversions/month with no credit card, which covers almost all development and low-volume production use.

SDK lock-in. CloudConvert's official SDKs wrap their async job system. Switching away means rewriting those calls from scratch anyway.

Who should stay on CloudConvert: Pipelines that need webhooks on completion, S3/GCS output, video encoding with custom bitrate/codec settings, or formats outside ChangeThisFile's 690-route catalog. CloudConvert's job system is the right tool for long-running, multi-step pipelines.

Cost comparison: what you'll actually save

Volume/monthCloudConvert (est.)ChangeThisFileMonthly savings
1,000 conversions~$20–40 (no free tier)$0 (free tier)$20–40
5,000 conversions~$50–100$29 (Hobby)$21–71
20,000 conversions~$150–250$99 (Startup)$51–151
100,000 conversions~$400–700$499 (Scale)$0–200

CloudConvert estimates assume average 15-second job duration at their standard per-minute rate. Document-heavy workloads (DOCX, PDF, XLSX) tend toward the higher end; image conversions toward the lower. Check your CloudConvert dashboard's conversion-minute usage for an accurate projection.

To estimate your savings: Take your average monthly CloudConvert invoice, subtract the ChangeThisFile plan cost for your conversion volume. Most teams at under 50K conversions/month see $50–$150/month in savings.

API endpoint mapping

CloudConvert actionChangeThisFile equivalent
POST /v2/jobs (create job)POST /v1/convert (single call)
GET /v2/jobs/{id} (poll status)Not needed — synchronous response
GET /v2/jobs/{id}/export/url (get output)Not needed — file returned in body
Bearer {API key} auth headerBearer ctf_sk_{key} auth header
tasks[].operation: "convert"data.target: "pdf" (or target format)
tasks[].input: "import-file"files["file"]: open("file.docx", "rb")
tasks[].output_format: "pdf"data.target: "pdf"
export/url task to download resultresponse.content (raw bytes)

Source format is auto-detected from the filename extension — you don't need to specify it explicitly.

Code migration: BEFORE and AFTER

Here's a complete DOCX-to-PDF conversion in Python, before and after:

# BEFORE: CloudConvert (async job + polling + download)
import cloudconvert
import requests
import time

cloudconvert.configure(api_key='your_cloudconvert_key')

job = cloudconvert.Job.create(payload={
    'tasks': {
        'import-my-file': {
            'operation': 'import/upload'
        },
        'convert-my-file': {
            'operation': 'convert',
            'input': 'import-my-file',
            'output_format': 'pdf'
        },
        'export-my-file': {
            'operation': 'export/url',
            'input': 'convert-my-file'
        }
    }
})

# Upload the file
upload_task = next(t for t in job['tasks'] if t['operation'] == 'import/upload')
with open('document.docx', 'rb') as f:
    cloudconvert.Task.upload(file_name='document.docx', task=upload_task, file=f)

# Poll until done
while True:
    job = cloudconvert.Job.find(id=job['id'])
    if job['status'] == 'finished':
        break
    if job['status'] == 'error':
        raise Exception('Conversion failed')
    time.sleep(2)

# Download result
export_task = next(t for t in job['tasks'] if t['operation'] == 'export/url')
download_url = export_task['result']['files'][0]['url']
result = requests.get(download_url)
with open('document.pdf', 'wb') as f:
    f.write(result.content)

# AFTER: ChangeThisFile (one call, synchronous)
import requests

response = requests.post(
    'https://changethisfile.com/v1/convert',
    headers={'Authorization': 'Bearer ctf_sk_your_key'},
    files={'file': open('document.docx', 'rb')},
    data={'target': 'pdf'}
)
with open('document.pdf', 'wb') as f:
    f.write(response.content)

The CloudConvert version is ~35 lines. The ChangeThisFile version is 9 lines. Both do exactly the same thing.

Auth and token migration

  1. Get your ChangeThisFile API key: Visit changethisfile.com/v1/keys/free — no credit card required. Your key starts with ctf_sk_.
  2. Update your authorization header: Replace Authorization: Bearer {cloudconvert_key} with Authorization: Bearer ctf_sk_{your_key}.
  3. Remove SDK imports: Delete import cloudconvert and remove the cloudconvert.configure() call. ChangeThisFile works with any HTTP client.
  4. Store the key securely: Add CTF_API_KEY=ctf_sk_... to your .env file and reference it via environment variable, same as you did with your CloudConvert key.
  5. Retire your CloudConvert key: Once your integration is confirmed working, revoke the old API key from your CloudConvert dashboard to avoid any accidental usage charges.

Webhook migration

CloudConvert supports webhooks that fire when a job completes. ChangeThisFile uses a synchronous API — the converted file is returned directly in the HTTP response, so webhooks are not needed or supported.

If you used CloudConvert webhooks for async notification: Remove the webhook handler. The await response or response.content is your completion signal. Your code that ran inside the webhook handler should run after the requests.post() call returns.

If you used CloudConvert webhooks for reliability (retry on failure): Wrap the ChangeThisFile call in your own retry logic:

import requests
from tenacity import retry, stop_after_attempt, wait_exponential

@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10))
def convert_file(input_path, target_format):
    with open(input_path, 'rb') as f:
        response = requests.post(
            'https://changethisfile.com/v1/convert',
            headers={'Authorization': f'Bearer {CTF_API_KEY}'},
            files={'file': f},
            data={'target': target_format},
            timeout=120
        )
    response.raise_for_status()
    return response.content

Rollback plan

Keep your CloudConvert API key active during the migration period. A safe rollback takes under 5 minutes:

  1. Keep both integrations behind a feature flag or environment variable: CONVERTER=changethisfile vs CONVERTER=cloudconvert.
  2. If ChangeThisFile returns errors for a specific format (e.g., a format in your pipeline that falls outside CTF's 690 routes), set CONVERTER=cloudconvert to revert immediately.
  3. Run parallel for 48–72 hours if your volume allows it — call both APIs and compare outputs before switching traffic fully.
  4. Cancel your CloudConvert subscription once you've confirmed 30 days of clean ChangeThisFile operation.

ChangeThisFile returns HTTP 400 with a JSON error body if the format pair is unsupported. Log these errors during the parallel-run period to catch any edge-case formats before full cutover.

Common migration questions

Does ChangeThisFile support all the same formats as CloudConvert?
ChangeThisFile has 690 conversion routes. CloudConvert's catalog is broader for niche formats (CAD, EXR, HDR, industry-specific). Run a quick audit: list every source→target pair in your CloudConvert jobs and check them against the ChangeThisFile format list. If any are missing, keep CloudConvert for those specific routes.

How do I handle large files?
ChangeThisFile's free-tier upload limit is 25MB. Paid plans support larger files. If your CloudConvert pipeline handles files over 25MB, upgrade to a paid CTF plan before migrating those workflows.

Can I keep using the CloudConvert SDK and just change the endpoint?
No — the CloudConvert SDK wraps an async job API. ChangeThisFile's API is synchronous with a completely different shape. You'll need to rewrite those calls, but the rewrite is simpler than the original (see the BEFORE/AFTER above).

What's the timeout?
ChangeThisFile's server-side conversions time out at 120 seconds for video/audio and 120 seconds for documents. Set your HTTP client timeout to at least 130 seconds. Most conversions complete in under 10 seconds.

Does ChangeThisFile have a staging environment?
No separate staging environment. Use your free tier (1,000/mo) for testing and development — it's the same infrastructure as production.

The migration is mostly deleting code — the job creation, polling loop, and export/download steps all go away. What's left is a single HTTP POST that returns your file. Get a free API key and test your most common conversion pair before committing to the switch.