REST API documentation

conv2pdf REST API — convert, merge, split, compress, protect and number PDFs from your application — 14 tools exposed via 5 REST endpoints. Hosting in France, GDPR-compliant, no US third party in the processing chain.

Quick start

  1. Create an account (free, email — no password required)
  2. From your dashboard, create an API key (free Dev plan, 300 conversions/mo to get started)
  3. Authenticate your calls with the Authorization: Bearer cpdf_live_… header

Base URL

https://api.conv2pdf.com/v1

SDK, OpenAPI & Postman

Authentication

Every request must include the HTTP header Authorization: Bearer <your_key>. A revoked or non-existent key returns a 401 status. An exceeded quota returns 429 with reset details.

Endpoints

GET /v1/tools

Returns the list of available tools, their limits and accepted formats.

curl https://api.conv2pdf.com/v1/tools \
  -H "Authorization: Bearer cpdf_live_..."

POST /v1/convert/:tool

Performs a conversion. Files are sent as multipart/form-data.

14 tools available. The up-to-date machine list (accepted formats, file bounds) is returned by GET /v1/tools.

Tool (:tool)InputFilesOutput
image-to-pdfPNG, JPG, WEBP, GIF, TIFF1PDF
heic-to-jpgHEIC, HEIF1JPG
heic-to-pdfHEIC, HEIF1PDF
office-to-pdfDOC(X/M), ODT, RTF, TXT, XLS(X/M), ODS, CSV, PPT(X/M), ODP1PDF
pdf-to-wordPDF1DOCX
pdf-to-imagePDF1ZIP (1 image/page)
merge-pdfPDF2 to 20PDF
split-pdfPDF1PDF
compress-pdfPDF1PDF
rotate-pdfPDF1PDF
protect-pdfPDF1PDF
unlock-pdfPDF1PDF
watermark-pdfPDF1PDF
page-numbers-pdfPDF1PDF

Optional parameters (form-data fields):

Example — Image → PDF (curl)

curl -X POST https://api.conv2pdf.com/v1/convert/image-to-pdf \
  -H "Authorization: Bearer cpdf_live_..." \
  -F "file=@photo.jpg"

Example — Merge PDFs (curl)

curl -X POST https://api.conv2pdf.com/v1/convert/merge-pdf \
  -H "Authorization: Bearer cpdf_live_..." \
  -F "file=@doc1.pdf" \
  -F "file=@doc2.pdf" \
  -F "file=@doc3.pdf"

Example — Compression (curl)

curl -X POST https://api.conv2pdf.com/v1/convert/compress-pdf \
  -H "Authorization: Bearer cpdf_live_..." \
  -F "file=@big.pdf" \
  -F "quality=medium"

Example — PDF → Word (curl)

curl -X POST https://api.conv2pdf.com/v1/convert/pdf-to-word \
  -H "Authorization: Bearer cpdf_live_..." \
  -F "file=@report.pdf"

Returns an editable .docx file. A scanned PDF (no text layer) returns 422 pdf_scanned_needs_ocr: OCR is available to Premium accounts on the website only, and is not exposed through the API; beyond 500 pages, 422 pdf_too_many_pages.

Example — PDF → Image (curl)

curl -X POST https://api.conv2pdf.com/v1/convert/pdf-to-image \
  -H "Authorization: Bearer cpdf_live_..." \
  -F "file=@report.pdf" \
  -F "format=png"

Renders each page as an image at 150 DPI and returns a .zip archive (one image per page). The format field is png (default) or jpg. Beyond 100 pages, 422 too_many_pages; if the result exceeds the maximum size, 422 output_too_large.

Example — Password protection (curl)

curl -X POST https://api.conv2pdf.com/v1/convert/protect-pdf \
  -H "Authorization: Bearer cpdf_live_..." \
  -F "file=@confidential.pdf" \
  -F "password=secret123" \
  -F "prevent_print=on" \
  -F "prevent_copy=on"

AES-256 encryption. The resulting PDF will prompt for the password on opening and apply the selected restrictions.

Successful response

The quota object is only present for calls authenticated with an API key.

{
  "job_id": "abc123…",
  "status": "success",
  "download_url": "/v1/download/abc123…",
  "size_bytes": 124533,
  "quota": {
    "plan": "starter",
    "quota": 1000,
    "used": 42,
    "soft_cap_limit": 1100,
    "status": "ok",
    "period_end": 1715789012345
  }
}

GET /v1/download/:jobId

Downloads the converted file. The file is served with its output MIME type (application/pdf, DOCX for PDF → Word, or application/zip for PDF → Image) and Cache-Control: no-store. Available for 1 hour after conversion.

curl https://api.conv2pdf.com/v1/download/abc123… \
  -H "Authorization: Bearer cpdf_live_..." \
  -o output.pdf

GET /v1/job/:jobId

Returns a job’s status and metadata (status, size, dates). Handy to check that a conversion is ready before downloading it.

curl https://api.conv2pdf.com/v1/job/abc123… \
  -H "Authorization: Bearer cpdf_live_..."

DELETE /v1/job/:jobId

Immediately deletes a job and its file, without waiting for the automatic expiry (1 hour).

curl -X DELETE https://api.conv2pdf.com/v1/job/abc123… \
  -H "Authorization: Bearer cpdf_live_..."

Examples — Node.js

import { readFile } from 'node:fs/promises';

const file = await readFile('./photo.jpg');
const formData = new FormData();
formData.append('file', new Blob([file]), 'photo.jpg');

const res = await fetch('https://api.conv2pdf.com/v1/convert/image-to-pdf', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer cpdf_live_...' },
  body: formData
});
const data = await res.json();
console.log(data.download_url);

Examples — Python

import requests

with open('photo.jpg', 'rb') as f:
    r = requests.post(
        'https://api.conv2pdf.com/v1/convert/image-to-pdf',
        headers={'Authorization': 'Bearer cpdf_live_...'},
        files={'file': f}
    )
print(r.json()['download_url'])

Examples — PHP

Official SDK (recommended)

Install the SDK: composer require conv2pdf/php. See the repo and its examples.

use Conv2pdf\Conv2pdf;

$c = new Conv2pdf('cpdf_live_...');
$job = $c->convert('image-to-pdf', 'photo.jpg');
$c->download($job['download_url'], 'photo.pdf');

Without a dependency (raw request)

$ch = curl_init('https://api.conv2pdf.com/v1/convert/image-to-pdf');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer cpdf_live_...'],
  CURLOPT_POSTFIELDS => ['file' => new CURLFile('photo.jpg')],
]);
$data = json_decode(curl_exec($ch), true);
echo $data['download_url'];

Error codes

CodeErrorCause
400not_enough_files / too_many_filesFile count outside tool bounds
401missing_bearer_token / invalid_api_keyMissing auth or invalid key
403forbiddenJob belongs to another key
404tool_not_found / job_not_foundTool or job does not exist
409job_not_readyThe job exists but has no output: conversion pending, failed or rejected. The body carries status (pending / failed / rejected).
410file_expired / job_deletedResource is gone for good: 1 h TTL exceeded, or job removed via DELETE /v1/job/:jobId. Do not retry.
413file_too_largeFile > 200 MB (API limit)
415unsupported_contentFile content does not match the tool. The type is determined from CONTENT, never from the filename extension: a valid PDF is accepted even without an extension, and a file renamed to .pdf is rejected. The response carries the detected type (detected_type).
422empty_fileEmpty file (0 bytes)
422password_protectedPassword-protected (encrypted) file; remove the protection before converting
422pdf_scanned_needs_ocrPDF → Word: scanned document with no text layer. OCR is website-only, for Premium accounts; the API always returns this code.
422pdf_too_many_pagesPDF → Word: more than 500 pages
429quota_exceededMonthly quota reached
503server_busyConversion queue saturated (retry within 5 s — Retry-After header)
500failedServer conversion error (details in error field)

Quotas and reset

Each API key has a monthly quota according to its plan (see pricing). The quota resets on a monthly anniversary date (not on the 1st of the month): the timestamp of the next reset is returned in period_end, and the used counter goes back to zero. A small overage is tolerated (soft_cap_limit, +10%) before the 429 block.

Privacy

No file (input or output) is kept beyond 1 hour. No result caching is applied. All processing happens on servers in France (OVH Gravelines). See our privacy policy for details.

Support

For any technical question, use our contact form (subject "Technical question"). Business and Custom plans: priority support with contractual SLA.