API Reference

The ConvertFly REST API lets you convert, optimize, and transform files programmatically. Build conversion pipelines with jobs and tasks - import a file, process it, and export the result in a single request.

Base URLhttps://convertfly.io/api/v1

All endpoints are relative to this base URL. Requests and responses use JSON. All timestamps are UTC ISO 8601.

Authentication

Every request must include an API key in the Authorization header. Keys are prefixed with cvfly_sk_ and can be created in your dashboard.

HTTP Header
Authorization: Bearer cvfly_sk_live_abc123def456...

Security tip: Never expose API keys in client-side code. Store them in environment variables and make API calls from your server.

Key Scopes

API keys can be scoped to limit what operations they allow:

ScopeAccess
jobs:writeCreate and cancel jobs
jobs:readList and retrieve jobs/tasks
webhooks:manageCreate, list, and delete webhooks
*Full access (default)

Quick Start

Convert a PDF to DOCX in three steps: create a job, wait for it to finish, then download the result.

1

Create a conversion job

curl
curl -X POST https://convertfly.io/api/v1/jobs \
  -H "Authorization: Bearer cvfly_sk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "tasks": {
      "import-file": {
        "operation": "import/url",
        "url": "https://example.com/report.pdf"
      },
      "convert": {
        "operation": "convert",
        "input": ["import-file"],
        "output_format": "docx"
      },
      "export": {
        "operation": "export/url",
        "input": ["convert"]
      }
    }
  }'
JavaScript
const res = await fetch("https://convertfly.io/api/v1/jobs", {
  method: "POST",
  headers: {
    "Authorization": "Bearer cvfly_sk_live_abc123...",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    tasks: {
      "import-file": {
        operation: "import/url",
        url: "https://example.com/report.pdf",
      },
      convert: {
        operation: "convert",
        input: ["import-file"],
        output_format: "docx",
      },
      export: {
        operation: "export/url",
        input: ["convert"],
      },
    },
  }),
});

const { data: job } = await res.json();
console.log(job.id);     // "job_7kX9mP2qR..."
console.log(job.status); // "PROCESSING"
Python
import requests

resp = requests.post(
    "https://convertfly.io/api/v1/jobs",
    headers={"Authorization": "Bearer cvfly_sk_live_abc123..."},
    json={
        "tasks": {
            "import-file": {
                "operation": "import/url",
                "url": "https://example.com/report.pdf",
            },
            "convert": {
                "operation": "convert",
                "input": ["import-file"],
                "output_format": "docx",
            },
            "export": {
                "operation": "export/url",
                "input": ["convert"],
            },
        }
    },
)
job = resp.json()["data"]
print(job["id"])      # "job_7kX9mP2qR..."
print(job["status"])  # "PROCESSING"
2

Wait for completion

Poll the job status or use webhooks for real-time notifications.

curl
curl https://convertfly.io/api/v1/jobs/job_7kX9mP2qR \
  -H "Authorization: Bearer cvfly_sk_live_abc123..."
Response
{
  "data": {
    "id": "job_7kX9mP2qR",
    "status": "FINISHED",
    "created_at": "2026-04-03T10:30:00Z",
    "tasks": {
      "export": {
        "status": "FINISHED",
        "result": {
          "url": "https://storage.convertfly.io/dl/abc123..."
        }
      }
    }
  }
}
3

Download the result

Use the URL from the export task result. Download links expire after 24 hours.

curl
curl -o result.docx "https://storage.convertfly.io/dl/abc123..."

Jobs

A Job is a container for one or more Tasks that form a conversion pipeline. Tasks within a job are executed in dependency order - each task can reference the output of a previous task via the input field.

Pipeline concept

A typical pipeline looks like: import/url -> convert -> export/url. You can also chain multiple operations: import -> convert -> optimize -> watermark -> export.

Job statuses

StatusDescription
WAITINGJob created, queued for processing
PROCESSINGAt least one task is currently running
FINISHEDAll tasks completed successfully
ERROROne or more tasks failed

Create a job

POST/api/v1/jobs
tagstring

Optional label to organize jobs (e.g. batch-2026-04).

tasksobjectrequired

A map of task names to task definitions. Task names must be unique within the job.

webhook_urlstring

URL to receive a job.finished or job.failed event when the job completes.

curl
curl -X POST https://convertfly.io/api/v1/jobs \
  -H "Authorization: Bearer cvfly_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "tag": "invoice-batch",
    "tasks": {
      "import-file": {
        "operation": "import/url",
        "url": "https://example.com/invoice.pdf"
      },
      "to-png": {
        "operation": "convert",
        "input": ["import-file"],
        "output_format": "png",
        "options": { "density": 300 }
      },
      "export": {
        "operation": "export/url",
        "input": ["to-png"]
      }
    }
  }'
Response (201 Created)
{
  "data": {
    "id": "job_7kX9mP2qR",
    "tag": "invoice-batch",
    "status": "PROCESSING",
    "credits_used": 1,
    "created_at": "2026-04-03T10:30:00Z",
    "tasks": {
      "import-file": { "status": "FINISHED" },
      "to-png":      { "status": "PROCESSING" },
      "export":      { "status": "WAITING" }
    }
  }
}

Get a job

GET/api/v1/jobs/:id

Retrieve job details and the status of all its tasks.

curl
curl https://convertfly.io/api/v1/jobs/job_7kX9mP2qR \
  -H "Authorization: Bearer cvfly_sk_..."

List jobs

GET/api/v1/jobs
pageinteger

Page number, starting at 1. Default: 1.

limitinteger

Results per page, 1-100. Default: 20.

statusstring

Filter by status: WAITING, PROCESSING, FINISHED, ERROR.

tagstring

Filter by tag.

curl
curl "https://convertfly.io/api/v1/jobs?status=FINISHED&limit=5" \
  -H "Authorization: Bearer cvfly_sk_..."
Response
{
  "data": [ ... ],
  "meta": {
    "page": 1,
    "limit": 5,
    "total": 42
  }
}

Delete a job

DELETE/api/v1/jobs/:id

Delete a job and all its associated files. Running tasks will be cancelled. This action is irreversible.

curl
curl -X DELETE https://convertfly.io/api/v1/jobs/job_7kX9mP2qR \
  -H "Authorization: Bearer cvfly_sk_..."

Wait for completion

GET/api/v1/jobs/:id/wait

Long-poll endpoint that blocks until the job reaches a terminal state (FINISHED or ERROR). Times out after 300 seconds with a 202 Accepted if the job is still processing.

curl
curl "https://convertfly.io/api/v1/jobs/job_7kX9mP2qR/wait?timeout=120" \
  -H "Authorization: Bearer cvfly_sk_..."

Tasks

Tasks are the individual steps within a job. Each task has a name (the key in the tasks object), an operation, and optionally an input array referencing previous task names.

Task fields

FieldTypeDescription
operationstringThe operation to perform (see Operations)
inputstring[]Names of tasks whose output to use as input
output_formatstringTarget format for convert operations
optionsobjectOperation-specific settings (quality, density, etc.)

List tasks for a job

GET/api/v1/jobs/:id/tasks
Response
{
  "data": [
    {
      "name": "import-file",
      "operation": "import/url",
      "status": "FINISHED",
      "result": { "file_id": "file_Xk9m..." }
    },
    {
      "name": "convert",
      "operation": "convert",
      "status": "FINISHED",
      "result": { "file_id": "file_Pm3n..." }
    }
  ]
}

Get a task

GET/api/v1/jobs/:job_id/tasks/:task_name

Cancel a task

POST/api/v1/jobs/:job_id/tasks/:task_name/cancel

Cancel a running or waiting task. Downstream tasks that depend on it will also be cancelled.

Retry a failed task

POST/api/v1/jobs/:job_id/tasks/:task_name/retry

Retry a task that has status ERROR. This consumes credits again if the task is billable.

File Upload

There are three ways to get files into ConvertFly. Choose the one that best fits your use case.

Import from URL

The simplest method. ConvertFly downloads the file from a publicly accessible URL.

Task definition
{
  "import-file": {
    "operation": "import/url",
    "url": "https://example.com/document.pdf",
    "filename": "document.pdf",
    "headers": {
      "Authorization": "Bearer your-external-token"
    }
  }
}

Direct upload (presigned URL)

For files on your local machine. This is a two-step process: first create the task to get a presigned upload URL, then PUT your file to that URL.

Step 1: Create job with import/upload
{
  "upload-file": {
    "operation": "import/upload",
    "filename": "photo.jpg"
  }
}
Step 2: Upload to the presigned URL
# The task result will contain the presigned URL
curl -X PUT "https://storage.convertfly.io/upload/abc123..." \
  -H "Content-Type: image/jpeg" \
  --data-binary @photo.jpg

Import from Base64

For small files (under 10 MB). Embed the file content directly in the request.

Task definition
{
  "import-file": {
    "operation": "import/base64",
    "file": "JVBERi0xLjQKJcOkw7zD...",
    "filename": "document.pdf"
  }
}
MethodMax sizeBest for
import/url5 GBFiles already hosted online
import/upload5 GBLocal files, large files
import/base6410 MBSmall files, inline in request

Conversion Options

Each operation supports specific options. Here are all available operations and the format pairs for conversions.

Available operations

OperationDescriptionCredits
import/uploadUpload a file via presigned URL0
import/urlImport a file from a URL0
import/base64Import a file from base64 data0
convertConvert between formats1-4
optimizeCompress/optimize a file1
thumbnailGenerate a thumbnail preview1
mergeMerge multiple files into one1
watermarkAdd text or image watermark1
metadataExtract file metadata1
export/urlGet a presigned download URL0
export/s3Export directly to your S3 bucket0

Supported format pairs

Popular conversions. The format is auto-detected from the file, but you can also set input_format explicitly.

CategoryInput formatsOutput formats
Documentspdf, docx, doc, odt, rtf, txt, htmlpdf, docx, odt, rtf, txt, html
Spreadsheetsxlsx, xls, ods, csvxlsx, ods, csv, pdf
Presentationspptx, ppt, odppptx, odp, pdf
Imagesjpg, png, gif, bmp, tiff, webp, svg, heicjpg, png, gif, bmp, tiff, webp
Videomp4, avi, mov, mkv, webmmp4, avi, mov, mkv, webm, gif
Audiomp3, wav, ogg, flac, aac, m4amp3, wav, ogg, flac, aac

Quality and processing options

Pass these in the options object on a convert task.

qualityinteger

Output quality for lossy formats (1-100). Default: 85.

densityinteger

DPI for document-to-image conversion. Default: 150.

widthinteger

Resize to this width in pixels. Maintains aspect ratio if height is omitted.

heightinteger

Resize to this height in pixels. Maintains aspect ratio if width is omitted.

pagesstring

Page range for document operations. E.g. 1-5, 1,3,5, all.

Example: high-quality PNG at 300 DPI
{
  "convert-hq": {
    "operation": "convert",
    "input": ["import-file"],
    "output_format": "png",
    "options": {
      "density": 300,
      "quality": 95
    }
  }
}

Webhooks

Register webhook URLs to receive real-time notifications when jobs or tasks change status. All payloads are signed with HMAC-SHA256 so you can verify they came from ConvertFly.

Create a webhook

POST/api/v1/webhooks
urlstringrequired

The HTTPS URL to receive webhook events.

eventsstring[]required

Event types to subscribe to.

curl
curl -X POST https://convertfly.io/api/v1/webhooks \
  -H "Authorization: Bearer cvfly_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/convertfly",
    "events": ["job.finished", "job.failed"]
  }'
Response (201 Created)
{
  "data": {
    "id": "wh_Abc123...",
    "url": "https://your-app.com/webhooks/convertfly",
    "events": ["job.finished", "job.failed"],
    "signing_secret": "whsec_9f8e7d6c5b4a...",
    "created_at": "2026-04-03T10:30:00Z"
  }
}

List webhooks

GET/api/v1/webhooks

Delete a webhook

DELETE/api/v1/webhooks/:id

Event types

EventTrigger
job.finishedAll tasks in the job completed successfully
job.failedOne or more tasks failed, job is in ERROR state
task.finishedAn individual task completed
task.failedAn individual task failed

Webhook payload

POST to your webhook URL
{
  "event": "job.finished",
  "timestamp": "2026-04-03T10:31:15Z",
  "data": {
    "id": "job_7kX9mP2qR",
    "status": "FINISHED",
    "tasks": { ... }
  }
}

Verifying signatures

Each webhook request includes two headers: X-Webhook-Signature and X-Webhook-Timestamp. Verify them to ensure the payload was sent by ConvertFly and was not tampered with.

Node.js
import crypto from "crypto";

function verifyWebhook(rawBody, signature, timestamp, secret) {
  const signedContent = timestamp + "." + rawBody;
  const expected = "v1=" + crypto
    .createHmac("sha256", secret)
    .update(signedContent)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}
Python
import hmac, hashlib

def verify_webhook(raw_body: bytes, signature: str, timestamp: str, secret: str) -> bool:
    signed_content = f"{timestamp}.{raw_body.decode()}"
    expected = "v1=" + hmac.new(
        secret.encode(), signed_content.encode(), hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

API Keys

Manage API keys programmatically. You can also manage keys from the dashboard.

Create an API key

POST/api/v1/api-keys
namestringrequired

A descriptive name for the key.

scopesstring[]

Permissions to grant. Default: ["*"] (full access).

Response (201 Created)
{
  "data": {
    "id": "key_Xk9m...",
    "name": "production-server",
    "key": "cvfly_sk_live_abc123def456...",
    "scopes": ["*"],
    "created_at": "2026-04-03T10:30:00Z"
  }
}

Important: The full API key is only shown once at creation time. Store it securely - you will not be able to retrieve it again.

List API keys

GET/api/v1/api-keys

Revoke an API key

DELETE/api/v1/api-keys/:id

Immediately invalidates the key. Any requests using it will return 401.

Rate Limiting

API requests are rate-limited per API key to ensure fair usage. When you exceed the limit, requests return 429 Too Many Requests.

Default limits

PlanRequests / minuteConcurrent jobs
Free102
Pro6010
Business20050
EnterpriseCustomCustom

Response headers

Every API response includes these headers:

X-RateLimit-Limitheader

Maximum requests allowed in the current window.

X-RateLimit-Remainingheader

Requests remaining in the current window.

X-RateLimit-Resetheader

Unix timestamp when the window resets.

Retry-Afterheader

Seconds to wait before retrying (only on 429 responses).

Example 429 response
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1743681600
Retry-After: 45

{
  "code": "TOO_MANY_REQUESTS",
  "message": "Rate limit exceeded. Retry after 45 seconds."
}

Errors

ConvertFly uses conventional HTTP status codes. All error responses follow a consistent format with a machine-readable code and a human-readable message.

Error response format

JSON
{
  "code": "INVALID_DATA",
  "message": "Missing required field: output_format",
  "details": {
    "field": "output_format",
    "reason": "required"
  }
}

Error codes

CodeHTTPDescription
INVALID_DATA400Invalid request body or parameters
UNAUTHENTICATED401Missing or invalid API key
FORBIDDEN403API key lacks the required scope for this operation
NOT_FOUND404Resource does not exist or has been deleted
CONFLICT409Resource already exists or operation conflicts with current state
PAYLOAD_TOO_LARGE413Request body exceeds maximum allowed size
UNSUPPORTED_FORMAT422Requested conversion is not supported
TOO_MANY_REQUESTS429Rate limit exceeded - see Rate Limiting
INSUFFICIENT_CREDITS402Not enough credits to complete the operation
SERVER_ERROR500Internal server error - retry or contact support
UNAVAILABLE503Service temporarily unavailable - try again in a moment

Handling errors

JavaScript
const res = await fetch("https://convertfly.io/api/v1/jobs", {
  method: "POST",
  headers: {
    "Authorization": "Bearer cvfly_sk_...",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ tasks: { /* ... */ } }),
});

if (!res.ok) {
  const error = await res.json();
  console.error(`[${error.code}] ${error.message}`);
  // "[INVALID_DATA] Missing required field: output_format"
  return;
}

const { data: job } = await res.json();

Credits

Each operation costs a certain number of credits. Import and export operations are free. Your remaining balance is included in every API response via the X-Credits-Remaining header.

Credit costs by conversion type

OperationCostExamples
Import / ExportFreeimport/url, import/upload, export/url, export/s3
Image conversion1 creditjpg to png, webp to gif, heic to jpg
Audio conversion1 creditmp3 to wav, flac to aac
Document to PDF1 credittxt to pdf, html to pdf, md to pdf
Office to PDF2 creditsdocx to pdf, pptx to pdf, xlsx to pdf
Video conversion2 creditsmp4 to webm, mov to mp4
PDF to Office4 creditspdf to docx, pdf to pptx
Optimize1 creditCompress images, PDFs
Thumbnail1 creditGenerate preview image
Merge1 creditCombine multiple PDFs
Watermark1 creditAdd text/image overlay
Metadata1 creditExtract file info

Checking your balance

Every API response includes the X-Credits-Remaining header with your current balance.

Response headers
HTTP/1.1 201 Created
Content-Type: application/json
X-Credits-Remaining: 9847
X-Credits-Used: 2

When your balance is too low to complete a job, the API returns 402 with the INSUFFICIENT_CREDITS error code. Top up credits in your billing dashboard.

Ready to start building?

Create your free account and get 50 credits to try the API.