Documentation de l’API REST
API REST conv2pdf : convertissez, fusionnez, découpez, compressez, protégez et numérotez vos PDF depuis votre application — 14 outils exposés via 5 endpoints REST. Hébergement en France, RGPD respecté. Aucun service américain n’intervient dans le processus.
Démarrage rapide
- Créez un compte (gratuit, magic link par email)
- Depuis votre tableau de bord, créez une clé API (plan Dev gratuit, 300 conversions offertes pour tester, valables 12 mois, sans renouvellement)
- Authentifiez vos appels avec l’en-tête
Authorization: Bearer cpdf_live_…
Base URL
https://api.conv2pdf.com/v1
SDK, OpenAPI & Postman
- SDK PHP officiel :
composer require conv2pdf/php(repo et exemples). - Spécification OpenAPI 3.0 (JSON) — pour générer un client dans un autre langage, l'importer dans un outil (Swagger, Insomnia…) ou alimenter un agent.
- Collection Postman — importez-la, renseignez votre clé, convertissez un PDF en une minute.
Authentification
Chaque requête doit inclure l’en-tête HTTP Authorization: Bearer <votre_clé>. Une clé révoquée ou inexistante renvoie un code 401. Un quota dépassé renvoie 429 avec les détails de réinitialisation.
Endpoints
GET /v1/tools
Renvoie la liste des outils disponibles, leurs limites et formats acceptés.
curl https://api.conv2pdf.com/v1/tools \
-H "Authorization: Bearer cpdf_live_..."
POST /v1/convert/:tool
Effectue une conversion. Les fichiers sont envoyés en multipart/form-data.
14 outils disponibles. La liste machine à jour (formats acceptés, bornes de fichiers) est renvoyée par GET /v1/tools.
Outil (:tool) | Entrée | Fichiers | Sortie |
|---|---|---|---|
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, ODG, SXW/SXC/SXI/SXD, FODT/FODS/FODP/FODG | 1 | |
pdf-to-word | 1 | DOCX | |
pdf-to-image | 1 | ZIP (1 image/page) | |
merge-pdf | 2 à 20 | ||
split-pdf | 1 | ||
compress-pdf | 1 | ||
rotate-pdf | 1 | ||
protect-pdf | 1 | ||
unlock-pdf | 1 | ||
watermark-pdf | 1 | ||
page-numbers-pdf | 1 |
Paramètres optionnels (champs form-data) :
split-pdf:rangesrequis (ex :1-5,7,10-12)compress-pdf:quality(low,mediumpar défaut,high)protect-pdf:passwordrequis (4 à 64 caractères) ; optionnelsprevent_print=on,prevent_copy=onunlock-pdf:passwordrequis (mot de passe actuel du PDF, à retirer)rotate-pdf:rotationrequis (90,180ou270)watermark-pdf:textrequis (texte du filigrane)pdf-to-image:format(pngpar défaut oujpg)page-numbers-pdf:position(bottom-centerpar défaut,bottom-left,bottom-right) ;format=simplepour le numéro seul (sans total)
Exemple : Image → PDF (curl)
curl -X POST https://api.conv2pdf.com/v1/convert/image-to-pdf \
-H "Authorization: Bearer cpdf_live_..." \
-F "file=@photo.jpg"
Exemple : Fusion PDF (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"
Exemple : Compression (curl)
curl -X POST https://api.conv2pdf.com/v1/convert/compress-pdf \
-H "Authorization: Bearer cpdf_live_..." \
-F "file=@gros.pdf" \
-F "quality=medium"
Exemple : PDF → Word (curl)
curl -X POST https://api.conv2pdf.com/v1/convert/pdf-to-word \
-H "Authorization: Bearer cpdf_live_..." \
-F "file=@rapport.pdf"
Renvoie un fichier .docx éditable. Un PDF scanné (sans couche texte) renvoie 422 pdf_scanned_needs_ocr : l'OCR existe pour les comptes Premium, sur le site uniquement, et n'est pas exposé par l'API ; au-delà de 500 pages, 422 pdf_too_many_pages.
Exemple : PDF → Image (curl)
curl -X POST https://api.conv2pdf.com/v1/convert/pdf-to-image \
-H "Authorization: Bearer cpdf_live_..." \
-F "file=@rapport.pdf" \
-F "format=png"
Rend chaque page en image à 150 DPI et renvoie une archive .zip (une image par page). Champ format : png (défaut) ou jpg. Au-delà de 100 pages, 422 too_many_pages ; si le résultat dépasse la taille maximale, 422 output_too_large.
Exemple : Protection par mot de passe (curl)
curl -X POST https://api.conv2pdf.com/v1/convert/protect-pdf \
-H "Authorization: Bearer cpdf_live_..." \
-F "file=@confidentiel.pdf" \
-F "password=secret123" \
-F "prevent_print=on" \
-F "prevent_copy=on"
Chiffrement AES-256. Le PDF généré demandera le mot de passe à l’ouverture et appliquera les restrictions cochées.
Réponse en cas de succès
L’objet quota n’est présent que pour les appels authentifiés par clé API.
{
"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
Télécharge le fichier converti. Le fichier est servi avec son type MIME (application/pdf, le format DOCX pour PDF → Word, ou application/zip pour PDF → Image) et Cache-Control: no-store. Disponible une heure après la conversion.
curl https://api.conv2pdf.com/v1/download/abc123… \
-H "Authorization: Bearer cpdf_live_..." \
-o sortie.pdf
GET /v1/job/:jobId
Renvoie le statut et les métadonnées d’un job (status, taille, dates). Pratique pour vérifier qu’une conversion est prête avant de la télécharger.
curl https://api.conv2pdf.com/v1/job/abc123… \
-H "Authorization: Bearer cpdf_live_..."
DELETE /v1/job/:jobId
Supprime immédiatement un job et son fichier, sans attendre l’expiration automatique (1 h).
curl -X DELETE https://api.conv2pdf.com/v1/job/abc123… \
-H "Authorization: Bearer cpdf_live_..."
Exemples : 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);
Exemples : 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'])
Exemples : PHP
SDK officiel (recommandé)
Installez le SDK : composer require conv2pdf/php. Voir le repo et ses exemples.
use Conv2pdf\Conv2pdf;
$c = new Conv2pdf('cpdf_live_...');
$job = $c->convert('image-to-pdf', 'photo.jpg');
$c->download($job['download_url'], 'photo.pdf');
Sans dépendance (requête brute)
$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'];
Codes d’erreur
Toute réponse d’erreur porte un champ error : un code stable, sur lequel brancher du code. Les champs supplémentaires listés ci-dessous disent quoi corriger. Les refus à l’entrée (upload, plan, contenu) portent aussi plan ; les erreurs survenues pendant la conversion portent job_id et status (rejected pour un verdict sur le fichier, failed pour une panne).
| Code | Erreur | Cause |
|---|---|---|
| 400 | not_enough_files / too_many_files | Nombre de fichiers hors bornes pour l’outil. Le corps porte min et provided, ou max. |
| 400 | field_required | Champ obligatoire absent ou vide : ranges sur split-pdf, text sur watermark-pdf. Le corps porte field, et example quand la forme attendue n’est pas évidente. |
| 400 | invalid_rotation / invalid_page_range / invalid_quality / invalid_format | Paramètre hors des valeurs admises. Le corps porte ce qui est accepté (allowed, valid) et, pour une plage de pages, range avec total_pages. |
| 400 | password_too_short / password_too_long | Mot de passe hors bornes sur protect-pdf. Le corps porte min ou max. |
| 400 | bad_request | Corps multipart refusé par le parseur : nom de champ interdit, champ JSON invalide, ou corps coupé en vol (code: "malformed_multipart"). Le corps porte code. |
| 401 | missing_bearer_token / invalid_api_key / account_not_provisioned | Auth manquante, clé invalide ou révoquée, ou clé sans compte API rattaché. |
| 402 | plan_limit_files | Plus de fichiers que le plan n’en autorise par conversion : 1 sur le plan Dev, 20 sur les plans payants. Le corps porte plan et max_allowed — la limite réellement appliquée, plus haute sur un outil qui exige plusieurs fichiers (merge-pdf en accepte 2 même en Dev). |
| 402 | credits_expired | Crédits d’essai du plan Dev passés leur date de validité (12 mois depuis leur octroi), quel que soit le reliquat. Le corps porte expired_at et upgrade. |
| 403 | forbidden | Job appartient à une autre clé |
| 404 | tool_not_found / job_not_found | Outil ou job inexistant |
| 409 | job_not_ready | Le job existe mais n’a pas de sortie : conversion en cours, échouée ou rejetée. Le corps porte status (pending / failed / rejected). |
| 410 | file_expired / job_deleted | Ressource partie définitivement : TTL de 1 h dépassé, ou job supprimé via DELETE /v1/job/:jobId. Inutile de retenter. |
| 413 | file_too_large | Fichier au-delà de la limite du plan : 10 Mo sur le plan Dev, 200 Mo sur les plans payants. Quand un plan supérieur accepterait le fichier, la réponse porte upgrade avec ce plan, son prix mensuel HT et son plafond. |
| 413 | payload_too_large | Requête entière au-delà de 220 Mo, tous fichiers et champs confondus. Le corps porte max_bytes. |
| 413 | too_many_parts | Trop d’éléments dans le multipart : 20 fichiers, 10 champs, 32 parts au total. Le corps porte limit (la borne franchie) et max. |
| 415 | unsupported_media_type | Le Content-Type de la requête n’est pas parsable. Les conversions s’envoient en multipart/form-data ; tout le reste tombe ici — corps brut (application/pdf, application/octet-stream…), application/json, application/x-www-form-urlencoded, en-tête absent, ou multipart/form-data sans boundary. Le refus intervient avant la lecture du corps. La réponse porte le type reçu (received) et la liste des types parsables (accepted). |
| 415 | unsupported_content | Le contenu du fichier ne correspond pas à l’outil. Le type est déterminé au CONTENU, jamais à l’extension du nom : un PDF valide est accepté même sans extension, et un fichier renommé en .pdf est refusé. La réponse porte file, le type détecté (detected_type) et bytes. |
| 415 | unsupported_format | image-to-pdf : image dans un format que l’outil ne sait pas lire. Le corps porte received et accepted. |
| 422 | empty_file | Fichier vide (0 octet). Le corps porte file. |
| 422 | password_protected | Fichier protégé par mot de passe d’ouverture (chiffré) sur un outil qui ne sait pas le déchiffrer ; retirer la protection avant conversion. Le corps porte file. |
| 422 | needs_password / wrong_password | PDF chiffré sur un outil qui sait le traiter : mot de passe absent, ou refusé par le fichier. Envoyer le champ password. Ni job ni quota ne sont consommés. |
| 422 | pdf_not_protected / pdf_already_protected | unlock-pdf sur un PDF sans protection, ou protect-pdf sur un PDF déjà chiffré. |
| 422 | pdf_scanned_needs_ocr | PDF → Word : document scanné sans couche texte. L'OCR est réservé au site, pour les comptes Premium ; l'API renvoie toujours ce code. |
| 422 | pdf_too_many_pages / too_many_pages | PDF → Word : plus de 500 pages. Les autres outils PDF ont leur propre plafond, rendu dans max_pages. |
| 422 | unsupported_characters | watermark-pdf : le texte contient des caractères que les polices embarquées ne savent pas rendre. Le corps porte field. |
| 422 | output_too_large | La sortie dépasserait le plafond de l’outil (pdf-to-image sur un document trop lourd). Le corps porte max_bytes. |
| 422 | source_unreadable | Fichier du bon type, mais que le moteur n’arrive pas à ouvrir : corrompu, tronqué, ou structure hors norme. Le corps porte engine. |
| 429 | rate_limited | Débit dépassé : 20 conversions par minute et par clé sur POST /v1/convert/:tool, 300 requêtes par minute et par IP sur les autres endpoints. La réponse porte retry_after (secondes) et l’en-tête Retry-After ; le quota mensuel n’est pas décompté. |
| 429 | quota_exceeded | Quota atteint. Sur les plans payants, le corps porte quota_period_end, date du prochain rechargement : inutile de retenter avant. Sur le plan Dev, quota_period_end ET period_end valent null — les conversions offertes ne se renouvellent pas, et un essai n’est pas facturé — et le corps porte upgrade, le plan qui rouvre l’accès. |
| 500 | conversion_failed | Le moteur a échoué. Le corps porte job_id, status: "failed" et, quand il est identifié, engine. Le quota est remboursé : une panne de notre côté ne se facture pas. |
| 500 | internal_error | Panne hors conversion. Aucun détail n’est publié — les 5xx sont masqués côté serveur. |
| 503 | server_busy | File de conversion saturée (retry recommandé sous 5 s, header Retry-After) |
| 504 | conversion_timeout | Budget de temps du moteur dépassé. Le corps porte engine et timeout_ms, et le job est failed. Le quota est remboursé. |
Quotas et réinitialisation
Chaque compte a un quota selon son plan (voir tarifs API), partagé par toutes ses clés. Sur les plans payants, le quota est mensuel et se réinitialise à chaque échéance anniversaire (et non au 1er du mois) : le timestamp de la prochaine remise à zéro est renvoyé dans quota_period_end, et le compteur used repart de zéro. Sur le plan Dev, les 300 conversions offertes à l’inscription sont valables 12 mois depuis leur octroi (credits_expire_at) et ne se renouvellent pas (quota_period_end à null, comme period_end : un essai n’est pas facturé). Un email vous prévient à 80 % du quota puis à épuisement, sur tous les plans, et 30 jours avant l’expiration des crédits d’essai. Un léger dépassement est toléré (soft_cap_limit, +10 %) avant le blocage en 429.
Confidentialité
Aucun fichier (entrée ou sortie) n’est conservé au-delà d’une heure : cette API n’a aucune exception à cette règle. Une seule chose peut prolonger la vie d’un fichier, et elle passe par le site : depuis le tableau de bord, le titulaire du compte peut créer un lien de partage pour un job — y compris produit par l’API — auquel cas la copie partagée vit jusqu’à l’échéance du lien (sept jours au plus en Gratuit, trente en Premium) ou jusqu’à sa révocation. Aucun résultat n’est mis en cache. L’intégralité du traitement a lieu sur des serveurs en France (OVH Gravelines). Voir notre politique de confidentialité pour le détail.
Support
Pour toute question technique, utilisez notre formulaire de contact (sujet « Question technique »). Plans Business et Sur-mesure : support prioritaire avec SLA contractuel.