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
- Create an account (free, email — no password required)
- From your dashboard, create an API key (free Dev plan, 300 conversions/mo to get started)
- Authenticate your calls with the
Authorization: Bearer cpdf_live_…header
Base URL
https://api.conv2pdf.com/v1
SDK, OpenAPI & Postman
- Official PHP SDK:
composer require conv2pdf/php(repo and examples). - OpenAPI 3.0 specification (JSON) — to generate a client in another language, import it into a tool (Swagger, Insomnia…) or feed an agent.
- Postman collection — import it, set your key, convert a PDF in a minute.
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) | Input | Files | Output |
|---|---|---|---|
image-to-pdf | PNG, JPG, WEBP, GIF, TIFF | 1 | |
heic-to-jpg | HEIC, HEIF | 1 | JPG |
heic-to-pdf | HEIC, HEIF | 1 | |
office-to-pdf | DOC(X/M), ODT, RTF, TXT, XLS(X/M), ODS, CSV, PPT(X/M), ODP | 1 | |
pdf-to-word | 1 | DOCX | |
pdf-to-image | 1 | ZIP (1 image/page) | |
merge-pdf | 2 to 20 | ||
split-pdf | 1 | ||
compress-pdf | 1 | ||
rotate-pdf | 1 | ||
protect-pdf | 1 | ||
unlock-pdf | 1 | ||
watermark-pdf | 1 | ||
page-numbers-pdf | 1 |
Optional parameters (form-data fields):
split-pdf:rangesrequired (e.g.1-5,7,10-12)compress-pdf:quality(low,mediumdefault,high)protect-pdf:passwordrequired (4 to 64 characters); optionalprevent_print=on,prevent_copy=onunlock-pdf:passwordrequired (the PDF’s current password, to remove)rotate-pdf:rotationrequired (90,180or270)watermark-pdf:textrequired (watermark text)pdf-to-image:format(pngdefault orjpg)page-numbers-pdf:position(bottom-centerdefault,bottom-left,bottom-right);format=simplefor the number only (no total)
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
| Code | Error | Cause |
|---|---|---|
| 400 | not_enough_files / too_many_files | File count outside tool bounds |
| 401 | missing_bearer_token / invalid_api_key | Missing auth or invalid key |
| 403 | forbidden | Job belongs to another key |
| 404 | tool_not_found / job_not_found | Tool or job does not exist |
| 409 | job_not_ready | The job exists but has no output: conversion pending, failed or rejected. The body carries status (pending / failed / rejected). |
| 410 | file_expired / job_deleted | Resource is gone for good: 1 h TTL exceeded, or job removed via DELETE /v1/job/:jobId. Do not retry. |
| 413 | file_too_large | File > 200 MB (API limit) |
| 415 | unsupported_content | File 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). |
| 422 | empty_file | Empty file (0 bytes) |
| 422 | password_protected | Password-protected (encrypted) file; remove the protection before converting |
| 422 | pdf_scanned_needs_ocr | PDF → Word: scanned document with no text layer. OCR is website-only, for Premium accounts; the API always returns this code. |
| 422 | pdf_too_many_pages | PDF → Word: more than 500 pages |
| 429 | quota_exceeded | Monthly quota reached |
| 503 | server_busy | Conversion queue saturated (retry within 5 s — Retry-After header) |
| 500 | failed | Server 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.