MarkifyDoc Developer API Reference
Enterprise-grade RESTful API and event-driven Webhook architecture, engineered for RAG knowledge bases, batch document cleansing, and financial report automation.
Overview & Base URL
MarkifyDoc provides modern RESTful APIs designed for cloud-native workflows. Programmatically convert multi-column papers and financial PDFs into clean Markdown, KaTeX formulas, and image assets in seconds.
https://api.markifydoc.comAuthentication & API Keys
All requests to /api/v1/* require a valid Bearer API Key in the HTTP Authorization header. You can create and manage up to 5 keys in the dashboard.
Authorization: Bearer mkd_xxxxxxxxxxxxxxxxxxxxxxxx
Your API Key grants full access to parse documents and spend wallet credits. Keep it confidential in server environment variables (.env). Never commit it to client code or public git repos.
Rate Limits & Priorities
Adaptive rate limiting and GPU priority queues are applied based on account tier:
| Tier | Rate Limit (RPM) | Max Concurrency | GPU Queue Priority |
|---|---|---|---|
| Free Tier | 10 RPM | 1 task | Normal queue (Cloud workers) |
| Pay-As-You-Go | 60 RPM | 3 tasks | Normal queue (Instant start) |
| Pro / API Tier | 300 RPM | 10+ tasks | High priority (Private GPU cluster) |
Standard Parsing Workflow
To guarantee high reliability for large research reports, MarkifyDoc uses direct presigned uploads followed by asynchronous processing:
1. Request Presigned Upload URL
Call /api/v1/upload-url with filename and size to obtain an authorized S3/R2 direct upload URL and task_id.
2. Client Direct Upload
Upload the raw PDF stream via HTTP PUT directly to object storage without burdening the application gateway.
3. Trigger Parse Task
Call /api/v1/parse to queue the document into GPU workers, optionally supplying a callback_url.
4. Retrieve Artifacts via Poll or Webhook
Poll /api/v1/tasks/{id} or let our webhook push the result download links once processing completes.
REST API 核心端点规范
/api/v1/upload-urlObtain a secure, temporary presigned URL for direct PDF upload (valid for 15 minutes).
Body
| Field | Type | Required | Description |
|---|---|---|---|
| filename | string | Required | 待上传的 PDF 文件全名(例如 nature_paper.pdf,必须以 .pdf 结尾) |
| file_size | integer | Optional | 文件字节大小,用于阶梯前置容量校验(最大限制 50MB) |
curl -X POST https://api.markifydoc.com/api/v1/upload-url \
-H "Authorization: Bearer mkd_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"filename": "quantum_physics_paper.pdf",
"file_size": 3145728
}'客户端直接上传源文件(PUT 请求)
# 客户端使用 PUT 方法直接上传原始 PDF 二进制流 curl -X PUT "<upload_url>" \ -H "Content-Type: application/pdf" \ --data-binary "@./quantum_physics_paper.pdf"
/api/v1/parseQueue the uploaded PDF into the AI visual multimodal pipeline for deep structural parsing.
Body
| Field | Type | Required | Description |
|---|---|---|---|
| r2_source_key | string | Required | 第一步获取到的 R2 存储路径(例如 uploads/task_uuid/source.pdf) |
| original_filename | string | Required | 文档原始名称 |
| pages_estimated | integer | Required | 预估解析页数,用于预扣点数校验(1 点/页,多扣失败页自动退还) 默认值: 1 |
| callback_url | string | Optional | 解析完毕后的 Webhook 异步回调地址 |
| options | object | Optional | 解析可选配置:enable_formula (默认 true), enable_table (默认 true) |
curl -X POST https://api.markifydoc.com/api/v1/parse \
-H "Authorization: Bearer mkd_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"r2_source_key": "uploads/0c1d2e3f-4567/source.pdf",
"original_filename": "quantum_physics_paper.pdf",
"pages_estimated": 12,
"callback_url": "https://api.yourdomain.com/webhook/pdf-parsed",
"options": {
"enable_formula": true,
"enable_table": true
}
}'/api/v1/tasks/{task_id}Fetch parsing progress, page statistics, error breakdown, credit billing, and artifact download links.
Path Params
| Field | Type | Required | Description |
|---|---|---|---|
| task_id | string (UUID) | Required | 提交任务时系统生成的唯一任务标识 |
curl -X GET https://api.markifydoc.com/api/v1/tasks/0c1d2e3f-4567 \ -H "Authorization: Bearer mkd_live_xxxxxxxxxxxxxxxxxxxxxxxx"
/api/v1/tasksRetrieve paginated history of all document parse tasks created under your account.
Query Params
| Field | Type | Required | Description |
|---|---|---|---|
| page | integer | Optional | 页码编号 默认值: 1 |
| page_size | integer | Optional | 每页任务数量(最大 100) 默认值: 20 |
| status | string | Optional | 按状态过滤:QUEUED, PROCESSING, SUCCESS, PARTIAL_SUCCESS, FAILED |
curl -X GET "https://api.markifydoc.com/api/v1/tasks?page=1&page_size=10&status=SUCCESS" \ -H "Authorization: Bearer mkd_live_xxxxxxxxxxxxxxxxxxxxxxxx"
/api/v1/tasks/{task_id}/retryReschedule failed or partial tasks without re-uploading the original source file.
Path Params
| Field | Type | Required | Description |
|---|---|---|---|
| task_id | string (UUID) | Required | 需重试的目标任务 ID |
curl -X POST https://api.markifydoc.com/api/v1/tasks/0c1d2e3f-4567/retry \ -H "Authorization: Bearer mkd_live_xxxxxxxxxxxxxxxxxxxxxxxx"
Webhook Asynchronous Notifications
By specifying callback_url when creating a task, your server will receive an HTTP POST payload as soon as processing finishes.
Trigger Conditions
Dispatched whenever task status transitions to SUCCESS, PARTIAL_SUCCESS, or FAILED.
{
"event": "document.parsed",
"task_id": "0c1d2e3f-4567",
"status": "SUCCESS",
"timestamp": 1788100875,
"data": {
"markdown": "https://r2.markifydoc.com/artifacts/0c1d2e3f-4567/output.md?expires=...",
"zip": "https://r2.markifydoc.com/artifacts/0c1d2e3f-4567/bundle.zip?expires=...",
"docx": "https://r2.markifydoc.com/artifacts/0c1d2e3f-4567/output.docx?expires=...",
"latex": "https://r2.markifydoc.com/artifacts/0c1d2e3f-4567/latex_bundle.zip?expires=..."
}
}Reliability & Exponential Backoff
If your receiver returns a non-2xx status code or times out, MarkifyDoc retries up to 3 times (5s, 30s, and 300s delays).
RAG Pipeline Cleansing Guide
Integrate MarkifyDoc with LangChain, LlamaIndex, or custom Python ETL scripts for high-precision document chunking and vector storage.
import os
import time
import requests
MARKIFY_API_KEY = os.getenv("MARKIFY_API_KEY", "mkd_live_xxxxxx")
BASE_URL = "https://api.markifydoc.com/api/v1"
HEADERS = {"Authorization": f"Bearer {MARKIFY_API_KEY}"}
def parse_and_ingest_pdf(file_path: str):
file_size = os.path.getsize(file_path)
file_name = os.path.basename(file_path)
# 1. 申请 S3/R2 直传临时链接
presign_res = requests.post(
f"{BASE_URL}/upload-url",
headers={**HEADERS, "Content-Type": "application/json"},
json={"filename": file_name, "file_size": file_size}
).json()["data"]
# 2. 客户端直接流式上传
with open(file_path, "rb") as f:
requests.put(presign_res["upload_url"], data=f, headers={"Content-Type": "application/pdf"})
# 3. 提交多模态视觉解析任务
task_res = requests.post(
f"{BASE_URL}/parse",
headers={**HEADERS, "Content-Type": "application/json"},
json={
"r2_source_key": presign_res["r2_source_key"],
"original_filename": file_name,
"pages_estimated": 10,
}
).json()["data"]
task_id = task_res["task_id"]
# 4. 轮询状态(或由 Webhook 异步唤醒)
while True:
status_res = requests.get(f"{BASE_URL}/tasks/{task_id}", headers=HEADERS).json()["data"]
status = status_res["status"]
if status == "SUCCESS":
md_url = status_res["download_urls"]["markdown"]
raw_markdown = requests.get(md_url).text
print(f"Parsed {len(raw_markdown)} characters of Markdown with KaTeX formulas.")
return raw_markdown
elif status == "FAILED":
raise RuntimeError(f"Parse failed: {status_res.get('failed_pages_detail')}")
time.sleep(3)
if __name__ == "__main__":
markdown = parse_and_ingest_pdf("./nature_paper.pdf")
# 下游直接对接 LangChain / LlamaIndex:
# chunks = RecursiveCharacterTextSplitter().split_text(markdown)
# vectorstore.add_texts(chunks)Error Codes & Troubleshooting
All API responses adhere to standardized code structures. Non-zero codes signify exceptional conditions with human-readable error messages.
| Code | HTTP Status | Meaning | Resolution |
|---|---|---|---|
| 0 | 200 OK | 成功完成 | 请求执行成功,数据已下发 |
| 40001 | 400 Bad Request | 缺少关键入参 | 检查请求体中是否遗漏 r2_source_key 或 filename |
| 40002 | 400 Bad Request | 文件格式不支持 | 仅支持 PDF 格式文档解析,检查文件扩展名 |
| 40003 | 400 Bad Request | 文件体积超限 | 单文件上限 50MB,超过需先进行切分压缩 |
| 40101 | 401 Unauthorized | API Key 无效或已停用 | 检查请求头 Authorization: Bearer mkd_... 是否正确或在控制台中被禁用 |
| 40301 | 403 Forbidden | 账户点数余额不足 | 前往工作台充值加油包或订阅 Pro 会员 |
| 40304 | 403 Forbidden | 超出游客解析页数限制 | 注册账号即可立领 50 点完整解析额度 |
| 40401 | 404 Not Found | 任务不存在 | 确认传入的 task_id 是否有效,任务满 24 小时后会被自动物理擦除 |
| 42901 | 429 Too Many Requests | 请求频次超限 | 触发每分钟调用上限 (RPM),按 Retry-After 标头等待后重试 |
| 50000 | 500 Internal Error | 服务端内部异常 | 服务器处理遇到临时问题,若已扣点会自动全额退还 |