Entwickler-Hub

Entwickle mit der PDF-zu-Markdown-API

Ein vorhersehbarer Job-Lebenszyklus über eine REST-API und ein gleichwertiges gehostetes MCP: leg einen Job an, warte auf ready, hol dir das Markdown, gib den Slot frei. Die API und das MCP umgehen niemals die Produktlimits.

Auf einen Blick

Zwei Oberflächen, eine Engine

Wähle die Integration, die passt. Beide rufen dieselbe Konvertierungs-Engine auf und befolgen dieselben Slots, Limits und Aufbewahrung.

REST-API

HTTPS-Endpunkte mit einem Bearer-API-Schlüssel. Stabile DTOs, vorhersehbare Fehler, idempotentes Anlegen.

Den Lebenszyklus ansehen

Gehostetes MCP

Ein verwalteter Model-Context-Protocol-Endpunkt, der die Konvertierung als Agent-Tools bereitstellt: eine dünne Schicht über derselben API.

MCP verbinden

Custom GPT Actions

Importiere ein reduziertes OpenAPI-Spec in einen Custom GPT von ChatGPT, damit er PDFs als integriertes Tool konvertieren kann.

Die Action einrichten
Authentifizierung

Bearer-API-Schlüssel über HTTPS

Die API und das MCP nutzen Bearer-API-Schlüssel, getrennt von dem gerätesignierten Weg, den die Chrome-Erweiterung verwendet. Für das Erzeugen von Schlüsseln ist ein kostenloses Google-Konto erforderlich.

Hol dir einen Schlüssel

  • Melde dich mit Google an (kostenloses Konto).
  • Erzeuge einen API-Schlüssel in deinem Konto; er wird nur einmal angezeigt.
  • Sende ihn als Authorization: Bearer p2m_… bei jeder Anfrage.
  • Schlüssel sind Geheimnisse: speichere sie serverseitig, rotiere und widerrufe sie jederzeit.

Ehrliche Standardwerte

Schlüssel, keine Passwörter. Die Erweiterung bleibt anonym und gerätesigniert; API-/MCP-Schlüssel sind ein separates, kontogebundenes Credential.
Nur HTTPS. Sende Schlüssel immer über TLS; bette niemals einen Schlüssel in clientseitigen Code ein, der an Nutzer ausgeliefert wird.
Idempotentes Anlegen. Ein optionaler Idempotency-Key beim Anlegen lässt dich sicher erneut versuchen, ohne doppelte Jobs.

Scopes. Jeder API-Schlüssel trägt Scopes: jobs:create, jobs:read, jobs:download, jobs:delete (die Standardwerte), plus settings:read / settings:write. Erzeuge Schlüssel mit minimalen Rechten; sowohl die REST-API als auch die MCP-Tools setzen die Scopes des Schlüssels durch.

REST-API

Leg einen Job an, warte, hol Markdown, räum den Slot frei

Ein vorhersehbarer Lebenszyklus, zwei Wege ihn zu steuern: ruf die REST-API aus deinem eigenen Code auf, oder nutze die gleichwertigen Tools des gehosteten MCP. Beanspruche niemals ein Ergebnis vor status=ready.

REST-API Gehostetes MCP
1

Leg den Job an

Mach einen POST mit einer PDF-URL oder lade Bytes hoch. Du bekommst eine Job-ID und einen Slot zurück. Idempotency-Key wird beachtet, ist aber optional.

POST /api/v2/jobsmcp · pdf_to_markdown_create_job_from_url
2

Prüf den Status

Frag den Job ab, bis ready oder error, oder registriere statt des Abfragens einen signierten Webhook in den kostenpflichtigen Tarifen.

GET /api/v2/jobs/{id}mcp · pdf_to_markdown_get_job
3

Hol das Markdown

Lade das Ergebnis herunter, sobald es bereit ist. Lies truncated und pages, um zu wissen, ob ein langes Dokument nur teilweise zurückgegeben wurde.

GET /api/v2/jobs/{id}/downloadmcp · pdf_to_markdown_get_markdown
4

Löschen / Slot freiräumen

Gib einen Slot frei, wenn du fertig bist. Das Löschen von Jobs in der Warteschlange oder in Bearbeitung ist destruktiv: bestätige es in nutzerseitigen Clients.

DELETE /api/v2/jobs/{id}mcp · pdf_to_markdown_delete_job
# 1. create a job from a PDF URL
curl -X POST https://pdf2md.dev/api/v2/jobs \
  -H "Authorization: Bearer p2m_…" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/report.pdf"}'
# → { "job_id": "job_9f3c…", "status": "queued" }

# 2. poll status
curl https://pdf2md.dev/api/v2/jobs/job_9f3c… \
  -H "Authorization: Bearer p2m_…"
# → { "status": "ready", "pages": 24, "truncated": false }

# 3. fetch the Markdown
curl https://pdf2md.dev/api/v2/jobs/job_9f3c…/download \
  -H "Authorization: Bearer p2m_…"

# 4. free the slot
curl -X DELETE https://pdf2md.dev/api/v2/jobs/job_9f3c… \
  -H "Authorization: Bearer p2m_…"

Fehler. Antworten verwenden stabile Strukturen und vorhersehbare HTTP-Codes (400 fehlerhafte Eingabe, 401 Auth, 404 unbekannter Job, 409 kein freier Slot / slots_full, 413 zu groß, 429 Rate-Limit). Das vollständige Schema findest du im OpenAPI-Spec.

Weitere Job-Endpunkte

Aus Datei anlegen (multipart)POST /api/v2/jobs
Deine Jobs auflistenGET /api/v2/jobs
Stapelweise anlegen (kostenpflichtig)POST /api/v2/jobs/batch

Create akzeptiert eine JSON-url oder eine multipart-file, plus optionale file_name, external_id, tags und callback_url / callback_secret für einen Webhook pro Job. Das stapelweise Anlegen ist Alles-oder-nichts und muss in deine freien Slots passen.

Das Job-Objekt

job_idstring
statusqueued · processing · ready · error
pages · output_sizeinteger
truncatedboolean
error_code · error_messageGrund (bei error)
download_urlstring (bei ready)
external_id · tagsdeine Metadaten
slot_usage · tierKontingent-Kontext

Konto und Nutzung. Prüf deinen Tarif, deine Limits und Nutzung zur Laufzeit mit GET /api/v2/me, /api/v2/limits und /api/v2/usage; verwalte Schlüssel unter /api/v2/api-keys und Webhooks unter /api/v2/webhooks.

Schnellstart

Konvertiere eine PDF in Python zu Markdown

Dieselben vier Aufrufe aus jeder Sprache. Hier mit requests. Für eine vollständige Schritt-für-Schritt-Anleitung mit Fehlerbehandlung siehe das Python-Tutorial.

# pip install requests
import time, requests

API = "https://pdf2md.dev/api/v2"
H = {"Authorization": "Bearer p2m_…"}

# 1. create a job from a PDF URL (or post a file with files={"file": ...})
job = requests.post(f"{API}/jobs", headers=H,
    json={"url": "https://example.com/report.pdf"}).json()
jid = job["job_id"]

# 2. poll until ready (or register a webhook instead)
while True:
    j = requests.get(f"{API}/jobs/{jid}", headers=H).json()
    if j["status"] in ("ready", "error"):
        break
    time.sleep(3)

# 3. download the Markdown
md = requests.get(f"{API}/jobs/{jid}/download", headers=H).text
print(md)
Mehr Rezepte: Datei-Upload und Node

Aus einer lokalen Datei anlegen (curl)

# multipart upload of a local PDF
curl -X POST https://pdf2md.dev/api/v2/jobs \
  -H "Authorization: Bearer p2m_…" \
  -F "[email protected]" \
  -F "file_name=document.pdf"

Node 18+ (globales fetch)

// create from URL, poll, download
const API = "https://pdf2md.dev/api/v2";
const H = { Authorization: "Bearer p2m_…" };

let job = await (await fetch(`${API}/jobs`, {
  method: "POST",
  headers: { ...H, "Content-Type": "application/json" },
  body: JSON.stringify({ url: "https://example.com/report.pdf" })
})).json();

while (job.status === "queued" || job.status === "processing") {
  await new Promise(s => setTimeout(s, 2000));
  job = await (await fetch(`${API}/jobs/${job.job_id}`, { headers: H })).json();
}

if (job.status === "ready") {
  const md = await (await fetch(`${API}/jobs/${job.job_id}/download`, { headers: H })).text();
  console.log(md);
}

Die Verifizierung der Webhook-Signatur steht im Abschnitt Webhooks; die MCP-Client-Konfiguration steht im Abschnitt MCP. Vollständiges Schema: OpenAPI.

Gehostetes MCP

Konvertierung als Agent-Tools

Verbinde einen kompatiblen Agenten mit unserem verwalteten MCP-Endpunkt. Die Tools sind eine dünne Schicht über der REST-API, also befolgt jeder Aufruf dieselben Slots, Limits und Aufbewahrung.

1

Richte den Agenten auf den Endpunkt

JSON-RPC 2.0 über Streamable HTTP mit deinem API-Schlüssel als Bearer-Token. Kein lokaler Server zum Ausführen. Methoden: initialize, tools/list, tools/call, ping.

POST https://pdf2md.dev/api/v2/mcp
2

Ruf die Tools auf

Derselbe Lebenszyklus plus Limits, bereitgestellt als sieben Tools. Jedes respektiert die Scopes des Schlüssels; die Antworten von tools/call enthalten slot_usage und tier.

create_job_from_url · create_job_from_upload (jobs:create)list_jobs · get_job (jobs:read)get_markdown (jobs:download) · delete_job (jobs:delete)get_limits
3

Befolge die Regeln

Warte auf ready, bevor du die Ausgabe verwendest; bestätige, bevor du Jobs in der Warteschlange/in Bearbeitung löschst; behandle truncated und 429 Retry-After. (Die Tool-Namen tragen das Präfix pdf_to_markdown_.)

// MCP client config (hosted, no local process)
{
  "mcpServers": {
    "pdf2md": {
      "url": "https://pdf2md.dev/api/v2/mcp",
      "headers": {
        "Authorization": "Bearer p2m_…"
      }
    }
  }
}
OpenAPI und Custom GPT Actions

Importiere das Spec, erhalte ein integriertes Tool

Wir veröffentlichen zwei Specs: das vollständige OpenAPI für Entwickler und ein reduziertes Action-Spec mit der sicheren, minimalen Teilmenge für KI-Clients und Custom GPT Actions von ChatGPT.

Vollständiges OpenAPI

Der komplette Vertrag: jeder Endpunkt, Parameter, DTO und Fehler. Generiere Clients oder erkunde es in deinem Tooling.

Das vollständige Spec öffnen

Reduziertes Spec für Custom GPT

Eine minimale Action-Teilmenge (anlegen, Status, abrufen) für Custom GPT Actions von ChatGPT. Importiere die URL, setz deinen API-Schlüssel als Auth, und dein GPT konvertiert PDFs nativ.

Das reduzierte Spec öffnen

Das reduzierte Spec ist eine Bequemlichkeit für KI-Clients, keine Sicherheitsgrenze: es gelten dieselbe Auth, dieselben Scopes und Limits wie bei der vollständigen API.

Limits und Rate-Limits

Limits pro Tarif, gleichermaßen auf API und MCP angewandt

Limits kommen aus deinem Tarif und gelten identisch auf jeder Oberfläche. Die aktuellen Werte stehen auf der Preisseite.

Gratis-Tarif (mit einem Konto)

Aktive Slots (Warteschlangentiefe)3
Maximale PDF-Größe10 MB
Zeitbudget pro Dokument15 min
Aufbewahrung des fertigen Ergebnisses1 Stunde

Kostenpflichtige Tarife erhöhen Slots, Dateigröße, Zeitbudget, Aufbewahrung und Rate-Limits und fügen Webhooks und stapelweises Anlegen hinzu. Tarife vergleichen →

Rate-Limits und Gegendruck

Rate-Limits pro Tarif. Anfragen werden pro Schlüssel limitiert; überschreitest du sie, bekommst du 429 mit einem Retry-After-Header: warte ab und versuch es erneut.
Slot-Druck. Sind alle Slots belegt, gibt create 409 zurück. Gib einen Slot mit delete frei, oder warte, bis ein Job fertig ist.
Priorität bei kostenpflichtigen. Kostenpflichtige Jobs laufen mit höherer Warteschlangenpriorität in einem dedizierten kostenpflichtigen Konvertierungs-Pool, sodass sie nicht hinter dem Gratis-Backlog warten.
Webhooks

Lass dich benachrichtigen, statt abzufragen

In den kostenpflichtigen Tarifen registriere einen signierten Webhook (oder übergib einen callback_url pro Job), und wir machen einen POST an dich bei jedem nennenswerten terminalen Ereignis: job.ready, job.error, job.truncated und job.deleted. Das Ereignis ist eine Benachrichtigung, keine Zustellung: es enthält keinen Dokumentinhalt, hol dir das Markdown also nach dem Empfang über die API.

1

Registriere einen Endpunkt

Mach einen POST mit einer HTTPS-URL (SSRF-geschützt) und einem optionalen events-Filter. Das Signaturgeheimnis whsec_… wird nur einmal zurückgegeben. Oder setz callback_url + callback_secret bei einem einzelnen Job.

POST /api/v2/webhooksGET /api/v2/webhooks/deliveries
2

Empfang des Ereignisses

Wir machen einen POST mit JSON und den Headern X-P2M-Event, X-P2M-Timestamp, X-P2M-Delivery und X-P2M-Signature.

3

Verifizieren, dann handeln

Berechne die Signatur neu, bestätige mit 2xx und sei idempotent (Zustellungen können mit Backoff erneut versucht werden). Lade dann das Markdown herunter.

# delivery → your endpoint
X-P2M-Event: job.ready
X-P2M-Timestamp: 1718900000
X-P2M-Signature: sha256=9a8b7c…

{
  "event": "job.ready",
  "job": {
    "job_id": "job_9f3c…",
    "status": "ready",
    "pages": 24, "truncated": false,
    "download_url": "/api/v2/jobs/job_9f3c…/download"
  }
}

# verify (Python): signature = sha256= + hex(HMAC(secret, "ts.rawbody"))
import hmac, hashlib
def verify(secret, ts, raw_body, sig):
    expected = "sha256=" + hmac.new(
        secret.encode(), f"{ts}.".encode() + raw_body,
        hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig)
Prompts und Sicherheit

Portable Anweisungen für Agenten

Pack diese Regeln in den System-Prompt eines Agenten, damit er die Tools korrekt steuert und niemals Ergebnisse erfindet.

Warte auf ready

Beanspruche oder fasse niemals ein Ergebnis vor status=ready zusammen. Solange es queued oder processing ist, frag weiter ab oder warte auf den Webhook.

Bestätige Löschvorgänge

Das Löschen eines queued- oder processing-Jobs ist destruktiv. Frag den Nutzer, bevor du pdf_to_markdown_delete_job bei einem nicht abgeschlossenen Job aufrufst.

Behandle Kürzung

Wenn truncated=true, sag dem Nutzer, dass das Dokument bis zum Zeitbudget des Tarifs nur teilweise zurückgegeben wurde, und biete einen höheren Tarif oder das Aufteilen der Datei an.

Respektiere 429

Bei einem 429 warte die Sekunden aus Retry-After ab, bevor du es erneut versuchst. Hämmere nicht auf die Warteschlange ein.

Räum Slots frei

Lösche abgeschlossene Jobs, die du nicht mehr brauchst, damit du deine Slots nicht erschöpfst.

Lies die Discovery

Starte mit /llms.txt und dem OpenAPI-Spec, statt Endpunkte aus dem Fließtext zu erraten.

Maschinenlesbare Discovery

Alles, was ein Agent braucht, um sich ohne Lesen des Quellcodes zu integrieren: eine kompakte Capabilities-Datei, eine detaillierte Kontextdatei und das OpenAPI-Spec.