Asynchronous API Usage Guide
更新时间:2026-02-04
Asynchronous API Usage Guide
- Supports up to 1000 PDF pages per request.
- Supports file URLs. File size must not exceed 200 MB.
- Supports local file uploads. File size must not exceed 50 MB.
Complete Asynchronous API Call Example
Depending on the model, the fields in the returned result may differ slightly. Below are call examples for PaddleOCR-VL Series / PP-StructureV3 and PP-OCRv5 respectively.
1. PaddleOCR-VL-1.5, PaddleOCR-VL, PP-StructureV3 Call Examples
Applicable to PaddleOCR-VL-1.5, PaddleOCR-VL, and PP-StructureV3 models.
# Please make sure the requests library is installed
# pip install requests
import json
import os
import requests
import sys
import time
JOB_URL = "https://paddleocr.aistudio-app.com/api/v2/ocr/jobs"
TOKEN = ""
# Optional models: "PaddleOCR-VL-1.5", "PaddleOCR-VL", "PP-StructureV3"
MODEL = "PaddleOCR-VL-1.5"
file_path = "<local file path or file url>"
headers = {
"Authorization": f"bearer {TOKEN}",
}
optional_payload = {
"useDocOrientationClassify": False,
"useDocUnwarping": False,
"useChartRecognition": False,
}
print(f"Processing file: {file_path}")
if file_path.startswith("http"):
# URL Mode
headers["Content-Type"] = "application/json"
payload = {
"fileUrl": file_path,
"model": MODEL,
"optionalPayload": optional_payload
}
job_response = requests.post(JOB_URL, json=payload, headers=headers)
else:
# Local File Mode
if not os.path.exists(file_path):
print(f"Error: File not found at {file_path}")
sys.exit(1)
data = {
"model": MODEL,
"optionalPayload": json.dumps(optional_payload)
}
with open(file_path, "rb") as f:
files = {"file": f}
job_response = requests.post(JOB_URL, headers=headers, data=data, files=files)
print(f"Response status: {job_response.status_code}")
if job_response.status_code != 200:
print(f"Response content: {job_response.text}")
assert job_response.status_code == 200
jobId = job_response.json()["data"]["jobId"]
print(f"Job submitted successfully. job id: {jobId}")
print("Start polling for results")
jsonl_url = ""
while True:
job_result_response = requests.get(f"{JOB_URL}/{jobId}", headers=headers)
assert job_result_response.status_code == 200
state = job_result_response.json()["data"]["state"]
if state == 'pending':
print("The current status of the job is pending")
elif state == 'running':
try:
total_pages = job_result_response.json()['data']['extractProgress']['totalPages']
extracted_pages = job_result_response.json()['data']['extractProgress']['extractedPages']
print(f"The current status of the job is running, total pages: {total_pages}, extracted pages: {extracted_pages}")
except KeyError:
print("The current status of the job is running...")
elif state == 'done':
extracted_pages = job_result_response.json()['data']['extractProgress']['extractedPages']
start_time = job_result_response.json()['data']['extractProgress']['startTime']
end_time = job_result_response.json()['data']['extractProgress']['endTime']
print(f"Job completed, successfully extracted pages: {extracted_pages}, start time: {start_time}, end time: {end_time}")
jsonl_url = job_result_response.json()['data']['resultUrl']['jsonUrl']
break
elif state == "failed":
error_msg = job_result_response.json()['data']['errorMsg']
print(f"Job failed, failure reason:{error_msg}")
sys.exit()
time.sleep(5)
if jsonl_url:
jsonl_response = requests.get(jsonl_url)
jsonl_response.raise_for_status()
lines = jsonl_response.text.strip().split('\n')
output_dir = "output"
os.makedirs(output_dir, exist_ok=True)
page_num = 0
for line_num, line in enumerate(lines, start=1):
line = line.strip()
if not line:
continue
result = json.loads(line)["result"]
# Note: layoutParsingResults field is used here
for i, res in enumerate(result["layoutParsingResults"]):
md_filename = os.path.join(output_dir, f"doc_{page_num}.md")
with open(md_filename, "w", encoding="utf-8") as md_file:
md_file.write(res["markdown"]["text"])
print(f"Markdown document saved at {md_filename}")
for img_path, img in res["markdown"]["images"].items():
full_img_path = os.path.join(output_dir, img_path)
os.makedirs(os.path.dirname(full_img_path), exist_ok=True)
img_bytes = requests.get(img).content
with open(full_img_path, "wb") as img_file:
img_file.write(img_bytes)
print(f"Image saved to: {full_img_path}")
for img_name, img in res["outputImages"].items():
img_response = requests.get(img)
if img_response.status_code == 200:
# Save image to local
filename = os.path.join(output_dir, f"{img_name}_{page_num}.jpg")
with open(filename, "wb") as f:
f.write(img_response.content)
print(f"Image saved to: {filename}")
else:
print(f"Failed to download image, status code: {img_response.status_code}")
page_num += 12. PP-OCRv5 Call Example
Applicable to PP-OCRv5 model.
# Please make sure the requests library is installed
# pip install requests
import json
import os
import requests
import sys
import time
JOB_URL = "https://paddleocr.aistudio-app.com/api/v2/ocr/jobs"
TOKEN = ""
MODEL = "PP-OCRv5"
file_path = "<local file path or file url>"
headers = {
"Authorization": f"bearer {TOKEN}",
}
optional_payload = {
"useDocOrientationClassify": False,
"useDocUnwarping": False,
"useTextlineOrientation": False,
}
print(f"Processing file: {file_path}")
if file_path.startswith("http"):
# URL Mode
headers["Content-Type"] = "application/json"
payload = {
"fileUrl": file_path,
"model": MODEL,
"optionalPayload": optional_payload
}
job_response = requests.post(JOB_URL, json=payload, headers=headers)
else:
# Local File Mode
if not os.path.exists(file_path):
print(f"Error: File not found at {file_path}")
sys.exit(1)
data = {
"model": MODEL,
"optionalPayload": json.dumps(optional_payload)
}
with open(file_path, "rb") as f:
files = {"file": f}
job_response = requests.post(JOB_URL, headers=headers, data=data, files=files)
print(f"Response status: {job_response.status_code}")
if job_response.status_code != 200:
print(f"Response content: {job_response.text}")
assert job_response.status_code == 200
jobId = job_response.json()["data"]["jobId"]
print(f"Job submitted successfully. job id: {jobId}")
print("Start polling for results")
jsonl_url = ""
while True:
job_result_response = requests.get(f"{JOB_URL}/{jobId}", headers=headers)
assert job_result_response.status_code == 200
state = job_result_response.json()["data"]["state"]
if state == 'pending':
print("The current status of the job is pending")
elif state == 'running':
try:
total_pages = job_result_response.json()['data']['extractProgress']['totalPages']
extracted_pages = job_result_response.json()['data']['extractProgress']['extractedPages']
print(f"The current status of the job is running, total pages: {total_pages}, extracted pages: {extracted_pages}")
except KeyError:
print("The current status of the job is running...")
elif state == 'done':
extracted_pages = job_result_response.json()['data']['extractProgress']['extractedPages']
start_time = job_result_response.json()['data']['extractProgress']['startTime']
end_time = job_result_response.json()['data']['extractProgress']['endTime']
print(f"Job completed, successfully extracted pages: {extracted_pages}, start time: {start_time}, end time: {end_time}")
jsonl_url = job_result_response.json()['data']['resultUrl']['jsonUrl']
break
elif state == "failed":
error_msg = job_result_response.json()['data']['errorMsg']
print(f"Job failed, failure reason:{error_msg}")
sys.exit()
time.sleep(5)
if jsonl_url:
jsonl_response = requests.get(jsonl_url)
jsonl_response.raise_for_status()
lines = jsonl_response.text.strip().split('\n')
output_dir = "output"
os.makedirs(output_dir, exist_ok=True)
page_num = 0
for line_num, line in enumerate(lines, start=1):
line = line.strip()
if not line:
continue
result = json.loads(line)["result"]
# Note: PP-OCRv5 uses ocrResults field
for i, res in enumerate(result["ocrResults"]):
image_url = res["ocrImage"]
img_response = requests.get(image_url)
if img_response.status_code == 200:
# Save image to local
filename = f"output/img_output_{page_num}.jpg"
with open(filename, "wb") as f:
f.write(img_response.content)
print(f"Image saved to: {filename}")
else:
print(f"Failed to download image, status code: {img_response.status_code}")
page_num += 1API Documentation
Base URL: https://paddleocr.aistudio-app.com/
Submit Parsing Job
Path: /api/v2/ocr/jobs
Method: POST
Header:
- Authorization: Bearer {access_token}
- Content-Type: application/json (Set when passing file URL, automatically adapted in sample code)
- Content-Type: multipart/form-data (Set when uploading files, automatically adapted in sample code)
- Accept-Encoding: gzip, deflate, br
Request Parameter Description
| Parameter | Type | Required | Example | Description |
|---|---|---|---|---|
file |
bytes |
是(与 fileUrl 二选一) | 二进制文件数据 | |
fileUrl |
string |
是(与 file 二选一) | 文件链接 | |
model |
string |
Yes | PP-OCRv5 PP-StructureV3 PaddleOCR-VL PaddleOCR-VL-1.5 |
OCR Model Name |
optionalPayload |
object |
No | {"useDocOrientationClassify": false} | Parsing parameters, varying by model type, see: PP-OCRV5: Doc PP-StructureV3: Doc PaddleOCR-VL: Doc PaddleOCR-VL-1.5: Doc |
pageRanges |
string |
No | "2,4-6": Page 2, Pages 4 to 6 "2--2": Page 2 to the second to last page |
Specify the range of pages to parse |
batchId |
string |
No | Unique identifiable string | Batch ID, used for querying batch tasks |
Response Parameter Description
| Parameter | Type | Example | Description |
|---|---|---|---|
traceId |
string |
0b1eb3150f5bec03dab9e74b4264c615 | Request ID |
code |
int |
10002 | Interface status code, 0 for success, see "Error Code Description" for failure details |
msg |
string |
File URL unrecognized | Interface response message, see "Error Code Description" for failure details |
data |
object |
||
data.jobId |
string |
ocrjob-f4377241b695 | Job ID |
Get Parsing Result
Path: /api/v2/ocr/jobs/{jobId}
Method: GET
Header:
- Authorization: Bearer {access_token}
- Content-Type: application/json
Response Parameter Description
| Parameter | Type | Example | Description |
|---|---|---|---|
traceId |
string |
0b1eb3150f5bec03dab9e74b4264c615 | Request ID |
code |
int |
0 | Interface status code, Success: 0 |
msg |
string |
Success | Interface processing information, Success: "Success" |
data |
object |
||
data.jobId |
string |
ocrjob-f4377241b695 | Job ID |
data.state |
string |
done | Job processing status * done: Completed * pending: Queued * running: Parsing in progress * failed: Parsing failed (no partial success) |
data.errorMsg |
string |
File format not supported, please upload a file type that meets the requirements | Parsing failure reason, valid when state=failed |
data.resultUrl |
object |
Provides BOS short link { "jsonUrl": "https://***.com", "markdownUrl": "https://***.com"} |
Document parsing result, valid when state=done |
data.extractProgress |
object |
Document parsing progress, valid when state=running | |
data.extractProgress.startTime |
string |
2026-01-01T12:00:00+08:00 | Document parsing start time |
data.extractProgress.endTime |
string |
2026-01-01T12:00:00+08:00 | Document parsing end time |
data.extractProgress.totalPages |
string |
10 | Total number of pages in the document |
data.extractProgress.extractedPages |
string |
1 | Number of pages already parsed |
Batch Get Task Results
Path: /api/v2/ocr/jobs/batch/{batchId}
Method: GET
Header:
- Authorization: Bearer {access_token}
- Content-Type: application/json
- Accept-Encoding: gzip, deflate, br
Response Parameter Description
| Parameter | Type | Example | Description |
|---|---|---|---|
traceId |
string |
0b1eb3150f5bec03dab9e74b4264c615 | Request ID |
code |
int |
0 | Interface status code, Success: 0 |
msg |
string |
Success | Interface processing information, Success: "Success" |
data |
object |
||
data.batchId |
string |
batchid-202601210000 | Batch Task ID, custom format as passed by user. |
data.extractResult |
array |
List of inference results | |
data.extractResult.jobId |
string |
ocrjob-f4377241b695 | Job ID |
data.extractResult.state |
string |
done | Job processing status * done: Completed * pending: Queued * running: Parsing in progress * failed: Parsing failed (no partial success) |
data.extractResult.errorMsg |
string |
File format not supported, please upload a file type that meets the requirements | Parsing failure reason, valid when state=failed |
data.extractResult.resultUrl |
object |
Provides BOS short link { "jsonUrl": "https://***.com", "markdownUrl": "https://***.com"} |
Document parsing result, valid when state=done |
data.extractResult.extractProgress |
object |
Document parsing progress, valid when state=running | |
data.extractResult.extractProgress.startTime |
string |
2026-01-01T12:00:00+08:00 | Document parsing start time |
data.extractResult.extractProgress.endTime |
string |
2026-01-01T12:00:00+08:00 | Document parsing end time |
data.extractResult.extractProgress.totalPages |
int |
10 | Total number of pages in the document |
data.extractResult.extractProgress.extractedPages |
int |
1 | Number of pages already parsed |
Error Codes
| Error Code | Error Code Description | Suggestion |
|---|---|---|
| 401 | Token Invalid | Check token, get token from link: Link |
| 500 | System Error | Please contact official support or try again later |
| 10001 | Empty file (http status corresponds to 400) | Please check the file |
| 10002 | File URL unrecognized (http status corresponds to 400) | Please check the URL |
| 10003 | File size exceeds limit (http status corresponds to 400) | Please check the file |
| 10004 | File format not supported (http status corresponds to 400) | Please check the file |
| 10005 | File content cannot be parsed (http status corresponds to 400) | Please check the file |
| 10006 | Number of file pages exceeds limit (http status corresponds to 400) | Please check the file |
| 10007 | Model parameter error (http status corresponds to 400) | Model does not exist, please check the model name |
| 10008 | Request parameter error (http status corresponds to 400) | optionalPayload or extraFormats parameter error, please correct according to data.errorMsg prompt |
| 10009 | Only 100 tasks are allowed for the same batchId (http status corresponds to 400) | Please change batchId |
| 10010 | Job submission queue is full | Please try again later |
| 11001 | jobId does not exist (http status corresponds to 404) | Please check jobId |
| 11002 | job expired (http status corresponds to 400) | Please change JobId |
| 11003 | job parsing failed (http status corresponds to 200) | Parsing failed, specific reason see: data.errorMsg |
| 12001 | Daily page limit reached (http status corresponds to 403) | Exceeded daily quota, if you need to increase, please see Quota Description |
| 12002 | Request frequency too high (http status corresponds to 429) | Please try again later |
