Convertir un PDF en Markdown en Python
Un tutoriel pas à pas avec l'API REST : obtenez une clé, créez un travail, interrogez et téléchargez du Markdown propre, avec un exemple complet et copiable ainsi qu'une gestion des erreurs en bonne et due forme.
Une clé, trois appels
Pour convertir un PDF en Markdown en Python, vous appelez une petite API REST avec une clé bearer : POST /api/v2/jobs pour créer un travail, GET /api/v2/jobs/{id} pour interroger jusqu'à ce qu'il soit prêt, puis GET /api/v2/jobs/{id}/download pour le Markdown. Il n'y a rien à héberger ni de bibliothèque lourde à installer, juste requests. Le même cycle de vie est exposé sous forme de MCP hébergé pour les agents, et la sortie est le même Markdown que produisent l'extension et l'application web, vous pouvez donc prototyper dans le navigateur puis automatiser en toute confiance.
Configurez-le en quatre étapes
Obtenez une clé API
Connectez-vous avec un compte Google gratuit et créez une clé API dans votre compte ; elle s'affiche une seule fois. Envoyez-la comme Authorization: Bearer p2m_your_key.
Créez un travail
Faites un POST de l'URL du PDF (ou des octets téléversés) vers /api/v2/jobs. Vous obtenez un id de travail et un statut.
Interrogez jusqu'à ready
Faites GET /api/v2/jobs/{id} jusqu'à ce que status soit ready ou error.
Téléchargez le Markdown
Faites GET /api/v2/jobs/{id}/download pour le texte Markdown. Respectez truncated et pages.
Le script Python complet
Bibliothèque standard plus requests. Créez depuis une URL de PDF, interrogez, puis enregistrez le Markdown.
# pip install requests import requests, time API = "https://pdf2md.dev/api/v2" H = {"Authorization": "Bearer p2m_your_key"} # 1) create a job from a PDF URL r = requests.post(f"{API}/jobs", headers={**H, "Idempotency-Key": "report-2026-01"}, json={"url": "https://example.com/report.pdf"}) r.raise_for_status() jid = r.json()["job_id"] # 2) poll until ready or error while True: job = requests.get(f"{API}/jobs/{jid}", headers=H).json() if job["status"] in ("ready", "error"): break time.sleep(3) if job["status"] == "error": raise SystemExit(f"conversion failed: {job.get('error_code')} {job.get('error_message')}") # 3) download the Markdown md = requests.get(f"{API}/jobs/{jid}/download", headers=H).text if job.get("truncated"): print("note: partial result (hit the time budget)") open("report.md", "w").write(md)
Vous téléversez un fichier local au lieu d'une URL ? Faites un POST des octets en multipart/form-data avec un champ file vers le même endpoint. Les formes complètes de la requête et de la réponse sont dans la spécification OpenAPI.
Pour convertir plusieurs PDF, créez un travail par fichier et interrogez-les en parallèle jusqu'à votre limite d'emplacements (3 sur l'offre gratuite, plus sur les offres payantes). Conservez un Idempotency-Key distinct par fichier pour que les réessais ne dupliquent jamais le travail, et patientez en cas de 429 en utilisant l'en-tête Retry-After.
Erreurs, réessais et webhooks
Lisez le code d'erreur
Un travail échoué renvoie status: error avec un error_code lisible par machine (processing_timeout ou conversion_failed) et un error_message sûr : branchez selon le code, pas selon le texte.
Gérez truncated
Un document long peut revenir ready avec truncated=true. Vérifiez l'indicateur et divisez le fichier ou utilisez un budget payant plus élevé.
Idempotency-Key
Envoyez un en-tête Idempotency-Key pour qu'une création réessayée renvoie le même travail au lieu de dupliquer le travail.
Webhooks plutôt que l'interrogation
Sur les offres payantes, enregistrez un webhook ou passez callback_url et recevez un POST sur ready/error au lieu d'interroger.
Respectez le 429
En cas de 429, attendez les secondes de Retry-After avant de réessayer ; ne saturez pas la file d'attente.
Gardez les clés côté serveur
La clé est un secret : stockez-la côté serveur, envoyez-la par TLS, et faites-la tourner ou révoquez-la à tout moment.
Pas en Python ? Les mêmes trois appels
C'est une API HTTPS simple, donc n'importe quel langage fonctionne. Le même créer / interroger / télécharger en Node :
// Node 18+ (global fetch) const API = "https://pdf2md.dev/api/v2"; const H = { Authorization: "Bearer p2m_your_key" }; let r = await fetch(`${API}/jobs`, { method: "POST", headers: { ...H, "Content-Type": "application/json" }, body: JSON.stringify({ url: "https://example.com/report.pdf" }) }); let { job_id } = await r.json(); let job; do { await new Promise(s => setTimeout(s, 3000)); job = await (await fetch(`${API}/jobs/${job_id}`, { headers: H })).json(); } while (!["ready", "error"].includes(job.status)); const md = await (await fetch(`${API}/jobs/${job_id}/download`, { headers: H })).text();
Vous préférez les outils d'agent ou le RAG ?
Le même cycle de vie est un MCP hébergé pour ChatGPT, Claude et les frameworks d'agents. Pour l'ingestion et le chunking, consultez le guide RAG.
Questions fréquentes
Comment convertir un PDF en Markdown en Python ?
Appelez l'API REST avec une clé bearer : faites un POST du PDF vers /api/v2/jobs, interrogez GET /api/v2/jobs/{id} jusqu'à ready, puis faites GET de /download pour le Markdown. L'exemple complet avec requests est ci-dessus.
Ai-je besoin d'une clé API ?
Oui pour l'API. Un compte Google gratuit vous permet de créer une clé et d'utiliser le MCP hébergé. L'extension de navigateur et l'application web restent anonymes et n'ont pas besoin de clé.
Comment gérer les erreurs et les délais d'attente ?
Un travail échoué renvoie status: error avec un error_code lisible par machine (processing_timeout ou conversion_failed) et un error_message sûr. Un document long peut revenir ready avec truncated=true ; vérifiez cet indicateur.
Puis-je éviter l'interrogation ?
Sur les offres payantes, enregistrez un webhook ou passez callback_url lors de la création du travail, et le service vous fait un POST sur ready ou error pour que vous n'interrogiez pas.
Cela fonctionne-t-il depuis Node ou d'autres langages ?
Oui. C'est une API HTTPS simple, donc n'importe quel langage fonctionne. Un court exemple en Node est ci-dessus, et le contrat complet est dans la spécification OpenAPI.
Comment convertir un fichier local au lieu d'une URL ?
Faites un POST des octets du fichier en multipart/form-data avec un champ file vers /api/v2/jobs, au lieu d'un corps JSON avec une url. Les étapes d'interrogation et de téléchargement sont identiques.
Puis-je convertir plusieurs PDF à la fois ?
Créez un travail par fichier et interrogez-les en parallèle jusqu'à votre limite d'emplacements (3 sur l'offre gratuite, plus sur les offres payantes). Les offres payantes ajoutent un endpoint de création par lots et des webhooks pour que vous n'interrogiez rien.
La sortie est-elle la même que celle de l'extension et de l'application web ?
Oui. Chaque surface utilise le même moteur de conversion, donc l'API renvoie le même Markdown que vous obtiendriez dans le navigateur.
Est-ce gratuit ?
L'offre gratuite donne 3 emplacements, des fichiers de 10 Mo, un budget de temps de 15 minutes et une conservation d'1 heure. Les offres payantes augmentent chaque limite et ajoutent les webhooks et la création par lots.