ExactPDF API v1
Headless PDF tools for AI agents. Same product as exactpdf.com — metered by API credits. New API users get 20 free test credits; create keys from the Max area. All JSON errors include support@exactpdf.com.
ChatGPT and custom GPT builders can import the OpenAPI spec at https://exactpdf.com/openapi.json. The hosted read-only MCP endpoint is live at https://exactpdf.com/mcp for ChatGPT Developer Mode testing. Public ChatGPT Apps directory distribution still requires OAuth/file handling and OpenAI review.
First successful API or MCP run
1. Create a key in Max Account, then call GET /api/v1/account or exactpdf_account.
2. Probe the PDF with POST /api/v1/pdf-info or exactpdf_pdf_info before extraction, conversion, or audio.
3. For RAG, use pdf-structured-markdown. For narration planning, use voice-preview and estimate_speech_cost.
4. Estimate audio credits, preview the voice, and keep jobs within the published launch limits.
Credits & pricing
merge-compress and images-to-pdf-compress also cost 1 credit on successful output. voice-preview is free and capped for short samples. English pdf-to-audiobook/pdf-to-speech MP3/M4B costs 15 credits per generated minute; presentation MP4 costs 20. Jobs are capped at 1 MB, 20 selected pages, 18,000 characters, 20 minutes, and one active job. translate-and-speak remains disabled. pdf-info, account, and job polling are 0 credits. Credits never expire. Top-ups: India — INR via Razorpay (UPI, cards) on Max → Account; international — USD via Polar.sh (Merchant of Record).Agent workflows
Invoice intake: merge vendor PDFs, extract text, then export structured Markdown for RAG indexing.
Portal packet builder: merge PDFs or convert photos into one PDF, then best-effort repack for a 1MB/2MB/5MB upload limit.
Target-size compression: pass target_bytes to compress for 100KB, 200KB, 500KB, or 1MB style upload checks, then read X-Target-Reached.
Audit extraction: run pdf-structured-markdown in academic mode to preserve page breaks for citations.
PDF JSON: run pdf-to-json for metadata, per-page text, full text, and extraction notes for agent pipelines.
Audio generation: preview the voice, estimate credits, then queue one bounded English PDF-to-speech/audiobook job.
Multilingual distribution: planned for the background audio worker after production reliability is proven.
Presentation narration: create a page-timed MP4 through the bounded background worker.
Internal workflow bots: use the MCP server from Cursor, Claude Desktop, or Codex with the same API key and credit balance.
Quickstart
1. Test your key
curl https://exactpdf.com/api/v1/account \
-H "Authorization: Bearer sk_live_..."
# {"ok":true,"credits_remaining":20,"credits_lifetime_used":0,"free_tier_resets_at":"2026-06-01T00:00:00.000Z","api_key":{"id":"...","label":"Agent workspace"}}2. Merge PDFs (curl)
curl https://exactpdf.com/api/v1/merge \ -H "Authorization: Bearer sk_live_..." \ -F "file=@a.pdf" -F "file=@b.pdf" \ -o merged.pdf
2b. Portal-ready merge under a limit
curl https://exactpdf.com/api/v1/merge-compress \ -H "Authorization: Bearer sk_live_..." \ -F "file=@cover.pdf" -F "file=@application.pdf" \ -F "target_bytes=2097152" \ -D headers.txt \ -o portal-ready.pdf # Check X-Output-Bytes and X-Target-Reached in headers.txt. # API compression is best-effort repack; strict image-heavy targets may need Max/browser exact-size compression.
2c. Photos to PDF under a limit
curl https://exactpdf.com/api/v1/images-to-pdf-compress \ -H "Authorization: Bearer sk_live_..." \ -F "file=@photo-1.jpg" -F "file=@photo-2.jpg" \ -F "target_bytes=1048576" \ -D headers.txt \ -o photos-upload-ready.pdf
3. Compress PDF (Node / TypeScript)
import { readFile, writeFile } from 'fs/promises'
const fd = new FormData()
fd.append('file', new Blob([await readFile('big.pdf')]), 'big.pdf')
fd.append('target_bytes', '512000')
const res = await fetch('https://exactpdf.com/api/v1/compress', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.EXACTPDF_API_KEY}` },
body: fd,
})
if (!res.ok) throw new Error(await res.text())
console.log(res.headers.get('x-output-bytes'), res.headers.get('x-target-reached'))
await writeFile('small.pdf', Buffer.from(await res.arrayBuffer()))4. Extract text (Python)
import os, requests
with open('contract.pdf', 'rb') as f:
r = requests.post(
'https://exactpdf.com/api/v1/extract-text',
headers={'Authorization': f"Bearer {os.environ['EXACTPDF_API_KEY']}"},
files={'file': f},
)
r.raise_for_status()
data = r.json()
print(f"{data['page_count']} pages, {len(data['text'])} chars")4b. PDF to JSON
curl https://exactpdf.com/api/v1/pdf-to-json \ -H "Authorization: Bearer sk_live_..." \ -F "file=@contract.pdf"
5. Preview a voice
curl https://exactpdf.com/api/v1/voice-preview \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"text":"ExactPDF turns PDFs into natural audio.","voice_style":"audiobook","language":"en"}' \
-o preview.mp36. PDF to speech / audiobook (async)
7. Translate and speak (async)
curl https://exactpdf.com/api/v1/translate-and-speak \ -H "Authorization: Bearer sk_live_..." \ -F "file=@training.pdf" \ -F "source_language=en" \ -F "target_language=hi" \ -F "voice_style=educational" \ -F "output_format=mp3"
OpenAPI for ChatGPT Actions
Use https://exactpdf.com/openapi.json when wiring ExactPDF into custom GPTs, ChatGPT Actions, or enterprise agent platforms that import OpenAPI. The first stable spec intentionally covers JSON-friendly document intelligence endpoints: account, PDF info, text extraction, and structured Markdown. Binary file-returning operations and the public ChatGPT Apps MCP endpoint are separate surfaces so review, auth, and file-handling stay clean.
curl https://exactpdf.com/openapi.json | jq '.info.title, .paths | keys'
Auth
or X-API-Key: sk_live_…
GET /api/v1/account
Returns credits remaining and key metadata. Does not consume a credit.
POST /api/v1/merge
multipart/form-data with two or more parts named file (PDF). Returns application/pdf on success. Consumes 1 credit only after a successful merge. Max total upload 20MB; max output 16MB.
POST /api/v1/split
One file (PDF). Default: application/zip with page-001.pdf, … (one PDF per page). Optional at_pages (split after those 1-based pages, e.g. 3,7) or ranges JSON ([[1,3],[4,10]]) for custom segments. 1 credit. Max 150 pages (per-page mode); max 25 segments (range modes); ZIP capped at 48MB.
POST /api/v1/rotate
file (PDF) plus form field angle: 90, 180, 270, -90, -180, or -270 (degrees, applied to every page). Returns application/pdf. 1 credit.
POST /api/v1/compress
One file (PDF). MVP rebuild with object streams — may reduce size for some PDFs; scanned files may not shrink much. Optional target_bytes reports measured fit through X-Target-Bytes, X-Output-Bytes, and X-Target-Reached. Returns application/pdf. 1 credit.
POST /api/v1/images-to-pdf
One or more file parts (PNG or JPEG only), order preserved. Returns application/pdf. 1 credit. Up to 25 images, 30MB total.
POST /api/v1/extract-text
One file (PDF). Returns JSON with text and page_count. 1 credit on success. Max upload 12MB for this endpoint.
POST /api/v1/pdf-to-json
One file (PDF). Returns metadata, pages with per-page text and character counts, full text, page_count, and extraction_mode. 1 crediton success. This is text-layer JSON; scanned PDFs need OCR first and table cell reconstruction is not guaranteed.
POST /api/v1/pdf-structured-markdown
One file (PDF). Optional field mode set to developer, academic, or rag (defaults to developer). Academic inserts --- between pages — ideal for auditors crawling long PDF audits. Rag collapses hyphen breaks + short-line fragments — ideal for embeddings. Use output_format=json for Markdown plus page/chunk provenance,markdown for a direct .md response, or jsonl for deterministic bounded RAG chunks. OCR is not run, images are not extracted, and tables remain reading-order text. 1 credit on success. Max upload 12MB — same safeguard as plain text extraction (CPU bound).
curl (Bearer key)
curl https://exactpdf.com/api/v1/pdf-structured-markdown \ -H "Authorization: Bearer sk_live_..." \ -F "mode=rag" -F "output_format=jsonl" \ -F "file=@paper.pdf"
RAG ingestion pattern
For retrieval pipelines, prefer pdf-structured-markdown with mode=rag. Keep the returned chunks or request output_format=jsonl. Store the stable chunk ID, page number, and page anchor with each embedding. Tables are reading-order text, not reconstructed cells.
Node: fetch Markdown, then split on headings
import { readFile } from 'node:fs/promises'
const form = new FormData()
form.append('mode', 'rag')
form.append('file', new Blob([await readFile('manual.pdf')]), 'manual.pdf')
const res = await fetch('https://exactpdf.com/api/v1/pdf-structured-markdown', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.EXACTPDF_API_KEY}` },
body: form,
})
if (!res.ok) throw new Error(await res.text())
const { chunks, warnings, capabilities } = await res.json()
for (const chunk of chunks) {
await vectorStore.upsert({
id: chunk.chunk_id,
text: chunk.text,
metadata: {
source: 'manual.pdf',
page: chunk.page_number,
anchor: chunk.page_anchor,
},
})
}
console.warn({ warnings, capabilities })Python: heading-aware chunks for vector databases
import os, re, requests
with open("manual.pdf", "rb") as f:
r = requests.post(
"https://exactpdf.com/api/v1/pdf-structured-markdown",
headers={"Authorization": f"Bearer {os.environ['EXACTPDF_API_KEY']}"},
files={"file": f},
data={"mode": "rag"},
)
r.raise_for_status()
payload = r.json()
chunks = [{
"id": chunk["chunk_id"],
"text": chunk["text"],
"metadata": {
"source": "manual.pdf",
"page": chunk["page_number"],
"anchor": chunk["page_anchor"],
},
} for chunk in payload["chunks"]]Use these chunks with LangChain, LlamaIndex, Haystack, or a custom vector pipeline. ExactPDF provides stable chunks and page provenance; your embedding layer should preserve that metadata. Table content remains reading-order text and should be verified against the source.POST /api/v1/pdf-info
One file (PDF). Returns JSON with page_count and document metadata (title, author, subject, keywords, producer, creator). 0 credits (does not deduct; still requires a valid API key).
POST /api/v1/voice-preview
JSON or multipart/form-data. Generates a short MP3/WAV voice sample before a paid background speech job. Fields: text (server-capped at 600 characters), output_format (mp3 or wav), voice_style, voice_id, language, and speed. Requires an API key but costs 0 credits.
curl https://exactpdf.com/api/v1/voice-preview \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"text":"Preview this narrator before generating the full audiobook.","voice_style":"professional","language":"en"}' \
-o preview.mp3POST /api/v1/pdf-to-audiobook
Compatibility aliases: POST /api/v1/pdf-to-speech and POST /api/v1/generate-audiobook. One file (PDF). This creates a background PDF-to-speech/audiobook job and returns HTTP 202 with job_id and status_url. Optional fields: output_format (mp3, m4b, mp4), voice_style, voice_id, language, speed, page_range, normalize_pauses, preserve_chapters, pronunciation_fixes, callback_url, and webhook_secret. Credits are estimated from selected PDF text before queueing: 15 credits/minute for MP3/M4B; 20 for MP4.
curl
curl https://exactpdf.com/api/v1/generate-audiobook \ -H "Authorization: Bearer sk_live_..." \ -F "file=@training.pdf" \ -F "voice_style=professional" \ -F "output_format=mp3"
GET /api/v1/jobs/:id
Speech compatibility aliases: GET /api/v1/speech-jobs/:id and GET /api/v1/speech-jobs/:id/download. Poll an async job created by pdf-to-speech, pdf-to-audiobook, generate-audiobook, translate-and-speak, or presentation-narration. Succeeded jobs include a temporary result_url for download. Failed jobs include error_code and error_message. Polling is free.
Webhooks are best-effort completion callbacks. If webhook_secret is supplied, ExactPDF sends x-exactpdf-timestamp, x-exactpdf-event, and x-exactpdf-signature. Verify the signature by computing HMAC-SHA256 over timestamp.body and comparing it with the header value after sha256=.
curl https://exactpdf.com/api/v1/speech-jobs/JOB_ID \ -H "Authorization: Bearer sk_live_..." curl -L https://exactpdf.com/api/v1/speech-jobs/JOB_ID/download \ -H "Authorization: Bearer sk_live_..." \ -o audiobook.mp3
POST /api/v1/translate-and-speak
One file (PDF) plus required target_language. When enabled, creates a background job that extracts PDF structure, translates the selected text, and generates native speech audio with chapter/page preservation. Sprint 4 live validation starts with hi, es, and fr; the worker is designed for additional Google Cloud TTS languages such as mr, de, ja, and ar. Pricing is 45 credits per estimated generated minute when the feature is eventually certified.
Optional fields: source_language, output_format, voice_style, speed, page_range, segmentation_mode (chapters or pages), translation_glossary, callback_url, and webhook_secret. Use segmentation_mode=pages when narrating presentation PDFs.
curl https://exactpdf.com/api/v1/translate-and-speak \ -H "Authorization: Bearer sk_live_..." \ -F "file=@report.pdf" \ -F "target_language=es" \ -F "voice_style=professional"
POST /api/v1/presentation-narration
One file (PDF) creates a page-timed presentation narration job. Each PDF page is treated as a slide and the default output is mp4. Pricing is 20 credits per estimated generated minute.
Optional fields: output_format, voice_style, speed, page_range, callback_url, and webhook_secret.
curl https://exactpdf.com/api/v1/presentation-narration \ -H "Authorization: Bearer sk_live_..." \ -F "file=@slides.pdf" \ -F "voice_style=presenter"
MCP (ChatGPT / Cursor / Claude / Codex)
Hosted MCP endpoint for ChatGPT Developer Mode: https://exactpdf.com/mcp. This first hosted surface is read-only: it helps ChatGPT choose ExactPDF workflows, set up OpenAPI actions, plan audio duration, and understand current capabilities without asking users to paste secrets in chat. It returns structured output through a CSP-declared app resource and does not receive files, access accounts, create jobs, process payments, or write request-level usage logs. Authenticated PDF processing remains available through OpenAPI/API-key actions while OAuth and file-reference handling are prepared for public ChatGPT Apps review.
Package @exactpdf/mcp is the ExactPDF stdio server for agent clients. Set EXACTPDF_API_KEY and wire stdio in your MCP client. Start with exactpdf_first_run_checklist, then exactpdf_account and exactpdf_pdf_info before paid work. Tools: exactpdf_account, exactpdf_pdf_info, exactpdf_merge_pdfs, exactpdf_split_pdf, exactpdf_rotate_pdf, exactpdf_compress_pdf, exactpdf_compress_pdf_to_target, exactpdf_compress_pdf_to_100kb, exactpdf_compress_pdf_to_200kb, exactpdf_compress_pdf_to_500kb, exactpdf_compress_pdf_to_1mb, exactpdf_pdf_to_images, exactpdf_images_to_pdf, exactpdf_extract_text, exactpdf_pdf_to_json, exactpdf_pdf_structured_markdown, exactpdf_ocr_pdf, exactpdf_estimate_speech_cost, exactpdf_voice_preview, exactpdf_pdf_to_speech, exactpdf_pdf_to_audiobook, exactpdf_generate_audiobook, exactpdf_translate_and_speak, exactpdf_presentation_narration, exactpdf_job_status, exactpdf_get_speech_job, exactpdf_download_audio. Optional: EXACTPDF_API_OUTPUT_DIR or EXACTPDF_MERGE_OUTPUT_DIR for saved PDF, ZIP, and audio outputs. English audio submission tools queue bounded paid jobs. Translate-and-speak intentionally remains disabled.
{
"mcpServers": {
"exactpdf": {
"command": "npx",
"args": ["-y", "@exactpdf/mcp"],
"env": { "EXACTPDF_API_KEY": "sk_live_..." }
}
}
}