Developer docs
Convert PDF, DOCX, PPTX, XLSX, CSV and JSON into clean, AI-ready Markdown three ways: inside Claude and Cursor with the MCP server, from your terminal with the CLI, or from your code with the REST API. Same engine, same token savings.
Get an API key
The API is available on the Pro plan. Create and manage keys on the API keys page. A key is shown once at creation, so store it securely.
Use it in Claude, Cursor & other MCP clients
PackForAI ships an open-source MCP server, listed on the MCP Registry. Add it to Claude Desktop (Settings → Developer → Edit Config) or Cursor (.cursor/mcp.json), then ask your assistant to convert a document and it returns clean Markdown inline.
{
"mcpServers": {
"packforai": {
"command": "npx",
"args": ["-y", "packforai-mcp"],
"env": { "PACKFORAI_API_KEY": "YOUR_API_KEY" }
}
}
}Published as packforai-mcp on npm. After adding it, try: “Convert ~/Downloads/report.pdf to clean Markdown.”
Command line
Convert from your terminal or shell scripts with the zero-dependency CLI. Markdown goes to stdout so you can pipe it; progress and token savings go to stderr.
export PACKFORAI_API_KEY="YOUR_API_KEY"
npx packforai-cli report.pdf # print clean Markdown
npx packforai-cli https://example.com/spec.docx -o spec.md
npx packforai-cli scan.pdf --ocr # OCR a scanned PDFPublished as packforai-cli on npm. Run npx packforai-cli --help for all options.
Authentication
Pass your key as a bearer token on every request:
Authorization: Bearer YOUR_API_KEYBase URL: https://packforai.com/api/v1
POST /convert
Submit a document as multipart/form-data. Fields: file (required), ocr (optional, true/false, Pro OCR for scanned PDFs), webhook (optional, a public https URL notified when the job finishes). Returns a job id.
curl -X POST https://packforai.com/api/v1/convert \
-H "Authorization: Bearer $PACKFORAI_API_KEY" \
-F "file=@report.pdf" \
-F "ocr=false"
# -> { "id": "…", "status": "queued", "statusUrl": "https://packforai.com/api/v1/jobs/…" }GET /jobs/{id}
Poll the job until status is completed or failed. On completion you get the compact Markdown inline plus token estimates. Add ?format=full to receive the full document.md (e.g. complete spreadsheet tables) instead of the compact version.
curl https://packforai.com/api/v1/jobs/JOB_ID \
-H "Authorization: Bearer $PACKFORAI_API_KEY"
# while status is "queued"/"processing", poll again every ~2s.
# when "completed":
# { "id": "…", "status": "completed",
# "tokens": { "original": 24532, "compact": 8586, "savingsPercent": 65 },
# "markdown": "# Quarterly Report\n## Financial Summary\n- Revenue: $4.2M …" }POST /batch
Submit up to 25 files in one request (repeat the file field). Optional ocr and webhook apply to every file. Each file becomes its own job, reported individually.
curl -X POST https://packforai.com/api/v1/batch \
-H "Authorization: Bearer $PACKFORAI_API_KEY" \
-F "file=@a.pdf" -F "file=@b.docx" -F "file=@c.xlsx"
# -> { "jobs": [ { "id": "…", "fileName": "a.pdf", "status": "queued" }, … ] }
# Each file is reported individually; jobs count against your plan limits.Webhooks (skip polling)
Pass a webhook URL to POST /convert or /batch and PackForAI will POST a JSON notification when the job finishes, so you don't have to poll:
// PackForAI POSTs this JSON to your webhook URL:
{
"event": "job.completed", // or "job.failed"
"id": "JOB_ID",
"status": "completed",
"tokens": { "original": 24532, "compact": 8586, "savingsPercent": 65 },
"statusUrl": "https://packforai.com/api/v1/jobs/JOB_ID"
}Deliveries are signed: verify the X-PackForAI-Signature header with your signing secret (from the API keys page).
import hmac, hashlib
def verify(secret: str, body: bytes, header: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header) # header = X-PackForAI-SignatureAs a rule of thumb, treat the webhook as a trigger: when it arrives, call GET /jobs/{id} with your key to fetch the result. The URL must be public https.
Example — Python
import time, requests
API = "https://packforai.com/api/v1"
KEY = "YOUR_API_KEY"
headers = {"Authorization": f"Bearer {KEY}"}
# 1. submit a document
with open("report.pdf", "rb") as f:
r = requests.post(f"{API}/convert", headers=headers, files={"file": f})
r.raise_for_status()
job_id = r.json()["id"]
# 2. poll until completed
while True:
s = requests.get(f"{API}/jobs/{job_id}", headers=headers).json()
if s["status"] in ("completed", "failed"):
break
time.sleep(2)
# 3. use the clean Markdown
if s["status"] == "completed":
print(s["markdown"])
print("saved", s["tokens"]["savingsPercent"], "% tokens")Example — JavaScript / Node
const API = "https://packforai.com/api/v1";
const KEY = process.env.PACKFORAI_API_KEY;
const headers = { Authorization: `Bearer ${KEY}` };
const form = new FormData();
form.append("file", fileBlob, "report.pdf");
const { id } = await fetch(`${API}/convert`, { method: "POST", headers, body: form }).then((r) => r.json());
let job;
do {
await new Promise((r) => setTimeout(r, 2000));
job = await fetch(`${API}/jobs/${id}`, { headers }).then((r) => r.json());
} while (job.status === "queued" || job.status === "processing");
if (job.status === "completed") console.log(job.markdown);Limits & notes
- Pro plan required; usage counts against your plan (100 conversions/day).
- API uploads up to 30 MB per file. For larger files, use the web app.
- Formats: pdf, docx, pptx, xlsx, csv, json.
- OCR (
ocr=true) covers scanned/broken PDFs within your monthly OCR page cap. - Documents and outputs are stored in the EU and never used to train AI.