REST-API
HTTPS-Endpunkte mit einem Bearer-API-Schlüssel. Stabile DTOs, vorhersehbare Fehler, idempotentes Anlegen.
Den Lebenszyklus ansehenEin 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.
Wähle die Integration, die passt. Beide rufen dieselbe Konvertierungs-Engine auf und befolgen dieselben Slots, Limits und Aufbewahrung.
HTTPS-Endpunkte mit einem Bearer-API-Schlüssel. Stabile DTOs, vorhersehbare Fehler, idempotentes Anlegen.
Den Lebenszyklus ansehenEin verwalteter Model-Context-Protocol-Endpunkt, der die Konvertierung als Agent-Tools bereitstellt: eine dünne Schicht über derselben API.
MCP verbindenImportiere ein reduziertes OpenAPI-Spec in einen Custom GPT von ChatGPT, damit er PDFs als integriertes Tool konvertieren kann.
Die Action einrichtenDie 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.
Authorization: Bearer p2m_… bei jeder Anfrage.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.
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.
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.
Frag den Job ab, bis ready oder error, oder registriere statt des Abfragens einen signierten Webhook in den kostenpflichtigen Tarifen.
Lade das Ergebnis herunter, sobald es bereit ist. Lies truncated und pages, um zu wissen, ob ein langes Dokument nur teilweise zurückgegeben wurde.
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.
# 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.
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.
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.
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)
# 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"
// 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.
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.
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.
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.
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_…"
}
}
}
}
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.
Der komplette Vertrag: jeder Endpunkt, Parameter, DTO und Fehler. Generiere Clients oder erkunde es in deinem Tooling.
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 ist eine Bequemlichkeit für KI-Clients, keine Sicherheitsgrenze: es gelten dieselbe Auth, dieselben Scopes und Limits wie bei der vollständigen API.
Limits kommen aus deinem Tarif und gelten identisch auf jeder Oberfläche. Die aktuellen Werte stehen auf der Preisseite.
Kostenpflichtige Tarife erhöhen Slots, Dateigröße, Zeitbudget, Aufbewahrung und Rate-Limits und fügen Webhooks und stapelweises Anlegen hinzu. Tarife vergleichen →
429 mit einem Retry-After-Header: warte ab und versuch es erneut.409 zurück. Gib einen Slot mit delete frei, oder warte, bis ein Job fertig ist.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.
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.
Wir machen einen POST mit JSON und den Headern X-P2M-Event, X-P2M-Timestamp, X-P2M-Delivery und X-P2M-Signature.
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)
Pack diese Regeln in den System-Prompt eines Agenten, damit er die Tools korrekt steuert und niemals Ergebnisse erfindet.
Beanspruche oder fasse niemals ein Ergebnis vor status=ready zusammen. Solange es queued oder processing ist, frag weiter ab oder warte auf den Webhook.
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.
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.
Bei einem 429 warte die Sekunden aus Retry-After ab, bevor du es erneut versuchst. Hämmere nicht auf die Warteschlange ein.
Lösche abgeschlossene Jobs, die du nicht mehr brauchst, damit du deine Slots nicht erschöpfst.
Starte mit /llms.txt und dem OpenAPI-Spec, statt Endpunkte aus dem Fließtext zu erraten.
Alles, was ein Agent braucht, um sich ohne Lesen des Quellcodes zu integrieren: eine kompakte Capabilities-Datei, eine detaillierte Kontextdatei und das OpenAPI-Spec.