Start here

Quick start & APIInstallOnline OCRCode generator

Models & pipelines

PP-OCRv6 modelsLanguagesPP-StructureV3PaddleOCR-VL

Deploy & integrate

Serving & APIPaddleOCR.jsMCP server

Fix & upgrade

TroubleshootingMigrate from 2.xReleases

Evaluate

Our benchmarkCompare OCR toolsLicense & cost

Tools

Online OCRInstall command builderCode generatorError fixer2.x → 3.x converterLanguage code finder

Language

English简体中文日本語Try OCR online
Deploy & integrate

PaddleOCR API: self-hosted serving or the hosted API

There are two PaddleOCR APIs. You can run your own HTTP server with paddlex --serve, which is free and keeps files on your machine. Or you can call Baidu's hosted API with an AI Studio access token, which has no setup and a daily free quota. We ran the self-hosted server, Docker included, and wrote down every request and error we saw.

Checked against PaddleOCR 3.7.0Updated 13 min read
On this page
  1. Self-hosted or hosted: which one?
  2. Self-hosted HTTP serving in five minutes
  3. Endpoints and the request/response format
  4. Client code: Python, curl, JavaScript
  5. Configure the server: models, speed, page limits
  6. Docker
  7. High-stability serving
  8. The official hosted API
  9. Doc mistakes and look-alikes to avoid
  10. Questions

Short answer. To self-host, run paddlex --install serving once, then paddlex --serve --pipeline OCR. You get POST http://localhost:8080/ocr. It takes JSON with file (a URL or Base64) and fileType (0 = PDF, 1 = image). To use the hosted API instead, get an access token from AI Studio (this is the "PaddleOCR API key"). Set it as PADDLEOCR_ACCESS_TOKEN and call the Python, TypeScript or Go SDK, or run paddleocr api. Baidu's quota doc gives each user 3,000 pages per model per day.1279

Self-hosted or hosted: which one?#

Self-hosted (PaddleX basic serving)Official hosted API
Setuppip install + an inference engine; models download on first startNone beyond an AI Studio account and token
Where files goYour machine onlyUploaded to Baidu's servers
AuthNone built in. Put it behind your own gateway.Authorization: Bearer <token>
Call styleSynchronous: one POST returns the resultAsynchronous: submit a job, poll, download JSONL
Cost / limitsYour hardware. Basic serving handles the first 10 PDF pages unless you change the config.3,000 pages per model per day free. Page caps per file conflict between docs (see limits).
ModelsAny pipeline: OCR, PP-StructureV3, PaddleOCR-VL, your own fine-tuned modelsOCR: PP-OCRv5, PP-OCRv6. Parsing: PP-StructureV3, PaddleOCR-VL, -1.5, -1.6
Browser callsNo CORS headers (we checked). Proxy it through your backend.Not documented

Rule of thumb: use the hosted API to prototype or for low volume when uploading files is acceptable. Self-host when documents are confidential, when you need more than the free quota, or when you want your own models. Not sure you need HTTP at all? The Python API needs no server, and PaddleOCR.js runs OCR inside the browser.

Self-hosted HTTP serving in five minutes#

PaddleOCR doesn't have its own HTTP server. The docs say it "recommends using PaddleX for serving". PaddleX is installed automatically with paddleocr. There are two options. Basic serving is easy to set up. High-stability serving runs on NVIDIA Triton Inference Server.1 Basic serving is a FastAPI app run by Uvicorn, so it is the "PaddleOCR FastAPI" server people search for. You don't have to write one.3

  1. Install PaddleOCR and an engine#

    bash
    python -m pip install paddlepaddle==3.2.0 paddleocr==3.7.0

    Pin the engine. In our install tests, a bare pip install paddlepaddle (3.3.1) crashes PaddleOCR 3.7.0 on CPU.

  2. Add the serving plugin#

    bash
    paddlex --install serving

    This pip-installs the serving extra of PaddleX: FastAPI, Uvicorn, Starlette, aiohttp, bce-python-sdk, filetype, pypdfium2, yarl and a pinned opencv-contrib-python==4.10.0.84. In our environment it took 18 seconds.34

  3. Start the server#

    bash
    paddlex --serve --pipeline OCR

    The official doc says to expect output like this. Ours matched:1

    text
    INFO:     Started server process [63108]
    INFO:     Waiting for application startup.
    INFO:     Application startup complete.
    INFO:     Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
  4. Check it#

    bash
    curl -s http://localhost:8080/health
    # {"logId":"9bce6482-...","errorCode":0,"errorMsg":"Healthy"}

    FastAPI also serves interactive docs at /docs and the schema at /openapi.json. On our OCR server the schema listed exactly two paths: /health and /ocr.4

Server options#

OptionWhat it doesDefault
--pipelineRegistration name (OCR, PP-StructureV3, PaddleOCR-VL, …) or the path to a pipeline config filerequired
--deviceDevice to run on, e.g. cpu, gpu:0GPU if available, else CPU
--hostBind address0.0.0.0
--portPort8080
--use_hpipHigh-performance inference pluginoff
--hpi_configHigh-performance inference configuration—

The default binds to every interface with no authentication. On a cloud VM, 0.0.0.0:8080 is reachable by anyone who can reach the machine. Use --host 127.0.0.1 and put a reverse proxy with auth in front, or firewall the port.1

Endpoints and the request/response format#

Every pipeline uses JSON over POST. The path depends on the pipeline:25

Pipeline (--pipeline)EndpointResult key
OCRPOST /ocrresult.ocrResults[]
PP-StructureV3POST /layout-parsingresult.layoutParsingResults[]
PaddleOCR-VL (and -1.5, -1.6)POST /layout-parsingresult.layoutParsingResults[]
anyGET /healtherrorMsg: "Healthy"

Request body for POST /ocr#

FieldTypeMeaning
file requiredstringA URL the server can reach, or the Base64 of an image (TIFF included) or PDF. By default only the first 10 pages of a PDF or multi-page TIFF are processed.
fileType0 | 1 | null0 = PDF, 1 = image. If omitted, inferred from the URL.
useDocOrientationClassify, useDocUnwarping, useTextlineOrientationboolTurn the preprocessing models on or off for this request
textDetLimitSideLen, textDetLimitType, textDetThresh, textDetBoxThresh, textDetUnclipRatio, textRecScoreThreshnumber / stringSame as the text_det_* / text_rec_* arguments of predict()
visualizebool | nullReturn result images. If omitted, follows Serving.visualize in the config, and images are returned when neither is set.

Base64 needs fileType. When we sent Base64 without fileType, the server returned 422 with "File type cannot be determined". The docs only say the type is inferred "from the URL", and a Base64 string has no URL to infer from. A URL ending in .jpg worked without fileType.24

Response#

Success is HTTP 200 with logId, errorCode: 0, errorMsg: "Success" and result. On failure, errorCode equals the HTTP status.2 Here is a real response from our server, trimmed:

jsonPOST /ocr response (trimmed)
{
  "logId": "11288c77-b7c3-4060-a177-19ca9adafc42",
  "errorCode": 0,
  "errorMsg": "Success",
  "result": {
    "ocrResults": [{
      "prunedResult": {
        "model_settings": {"use_doc_preprocessor": false, "use_textline_orientation": false},
        "dt_polys": [[[243, 167], [604, 120], [608, 151], [247, 198]], "..."],
        "text_det_params": {"limit_side_len": 64, "limit_type": "min", "thresh": 0.3,
                            "max_side_limit": 4000, "box_thresh": 0.6, "unclip_ratio": 1.5},
        "rec_texts": ["HARBOR STREET COFFEE", "214 Harbor Street, Portland ME", "..."],
        "rec_scores": ["..."],
        "rec_polys": ["..."],
        "rec_boxes": ["..."]
      }
    }],
    "dataInfo": {"width": 900, "height": 1200, "type": "image"}
  }
}

prunedResult is the same dict predict() returns in Python, minus input_path and page_index. So rec_texts, rec_scores, rec_polys and rec_boxes mean what they mean in the Python API. With visualization on, each page also gets ocrImage, docPreprocessingImage and inputImage as Base64 JPEGs.2

Those images get big. For one 900×1200 receipt, the default response was 1.23 MB. With "visualize": false it was 4.3 KB, and the three image keys were left out entirely rather than set to null. Read them with .get().4

Errors we triggered#

RequestStatuserrorMsg
No file field422[{"type": "missing", "loc": "body.file", "msg": "Field required"}]
file is not valid Base64422Invalid input file
Base64 without fileType422File type cannot be determined
Browser CORS preflight (OPTIONS /ocr)405Method Not Allowed

Client code: Python, curl, JavaScript#

The Python client below is copied verbatim from the official docs. We ran it unchanged against our server and it printed the 27 receipt lines.24 The curl and JavaScript versions are derived by us from the documented request schema, because the OCR doc has no curl example. We tested both.

import base64
import requests

API_URL = "http://localhost:8080/ocr"
file_path = "./demo.jpg"

with open(file_path, "rb") as file:
    file_bytes = file.read()
    file_data = base64.b64encode(file_bytes).decode("ascii")

payload = {"file": file_data, "fileType": 1}

response = requests.post(API_URL, json=payload)

assert response.status_code == 200
result = response.json()["result"]
for i, res in enumerate(result["ocrResults"]):
    print(res["prunedResult"])
    ocr_img_path = f"ocr_{i}.jpg"
    with open(ocr_img_path, "wb") as f:
        f.write(base64.b64decode(res["ocrImage"]))
    print(f"Output image saved at {ocr_img_path}")
# GNU base64; -w0 disables line wrapping. Writing to a file avoids
# "argument list too long" on big images.
printf '{"file":"%s","fileType":1,"visualize":false}' "$(base64 -w0 demo.jpg)" > req.json

curl -s -X POST http://localhost:8080/ocr \
  -H "Content-Type: application/json" \
  -d @req.json | jq -r '.result.ocrResults[].prunedResult.rec_texts[]'

# Or pass a URL the server can reach (fileType is inferred from it):
curl -s -X POST http://localhost:8080/ocr -H "Content-Type: application/json" \
  -d '{"file":"https://example.com/invoice.pdf","visualize":false}'
// Node.js 18+ (global fetch). Tested on Node 22.
import { readFile } from "node:fs/promises";

const API_URL = "http://localhost:8080/ocr";
const bytes = await readFile("./demo.jpg");

const res = await fetch(API_URL, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    file: bytes.toString("base64"),
    fileType: 1,          // 0 = PDF, 1 = image; required for Base64 input
    visualize: false      // skip the Base64 result images
  })
});
const body = await res.json();
if (body.errorCode !== 0) throw new Error(`${body.errorCode}: ${body.errorMsg}`);

for (const page of body.result.ocrResults) {
  const { rec_texts, rec_scores } = page.prunedResult;
  rec_texts.forEach((t, i) => console.log(rec_scores[i].toFixed(3), t));
}

Don't copy the official Node.js example for OCR. In the OCR pipeline doc it posts to http://localhost:8080/layout-parsing and reads layoutParsingResults. Those belong to PP-StructureV3 and PaddleOCR-VL. Against an OCR server that path doesn't exist. Use /ocr and ocrResults as above.2

Calling from a web page: the server sends no CORS headers, and the browser's preflight OPTIONS request gets a 405. Send browser requests through your own backend or a same-origin reverse proxy. If you want OCR in the browser with no server, use PaddleOCR.js, as our online tool does.4

Configure the server: models, speed, page limits#

The default OCR pipeline in PaddleX 3.7.2 uses PP-OCRv6_medium for detection and recognition. It also turns on all three preprocessing models: document orientation (PP-LCNet_x1_0_doc_ori), unwarping (UVDoc) and text-line orientation.3 That is more work than the Python defaults most tutorials show. On our receipt, unwarping gave the same 27 lines but returned them in a different order. To change the defaults, export the config, edit it, and serve the file:5

bash
paddlex --get_pipeline_config OCR --save_path ./
# → "The pipeline config has been saved to: OCR.yaml"

This is the edited config we served, as a diff from the export: PP-OCRv6 small models, no preprocessing, no images by default, and no 10-page cap. The Serving keys come from the official docs.12

yamlocr_config.yaml (changes only)
use_doc_preprocessor: False      # was True
use_textline_orientation: False  # was True

SubModules:
  TextDetection:
    model_name: PP-OCRv6_small_det   # was PP-OCRv6_medium_det
  TextRecognition:
    model_name: PP-OCRv6_small_rec   # was PP-OCRv6_medium_rec

Serving:
  visualize: False          # requests can still send "visualize": true
  extra:
    max_num_input_imgs: null  # process every PDF page, not just the first 10
bash
paddlex --serve --pipeline ./ocr_config.yaml --device cpu --port 8080

With this config the server read all 27 receipt lines. There was one slip: 0rder (with a zero) for "Order", which matches what PP-OCRv6 small does in our benchmark. Which tier to pick is covered on the models page.4

Large responses? Images can be returned as pre-signed URLs instead of Base64 with Serving.return_urls: true. The only storage backend supported is bos (Baidu object storage).1

Docker#

We found no official Docker image for serving the plain OCR pipeline. The official images are for PaddleOCR-VL (below). This Dockerfile is ours. It only uses the documented commands. We built it, ran it, and got the same 27 lines back from /ocr. The image was 2.26 GB on disk.4

textDockerfile
FROM python:3.12-slim

# OpenCV (pulled in by the serving plugin) needs these system libraries
RUN apt-get update \
 && apt-get install -y --no-install-recommends libgl1 libglib2.0-0 libgomp1 \
 && rm -rf /var/lib/apt/lists/*

RUN python -m pip install --no-cache-dir paddlepaddle==3.2.0 paddleocr==3.7.0 \
 && paddlex --install serving -y

COPY ocr_config.yaml /app/ocr_config.yaml
EXPOSE 8080
CMD ["paddlex", "--serve", "--pipeline", "/app/ocr_config.yaml", "--device", "cpu"]
bash
docker build -t paddleocr-serve .
# keep downloaded models between restarts
docker run -d -p 8080:8080 -v paddlex-models:/root/.paddlex paddleocr-serve
curl -s localhost:8080/health

Models are not baked in. They download into /root/.paddlex/official_models on first start (from Hugging Face by default), so mount that directory as a volume. For a GPU image, swap the engine for paddlepaddle-gpu from PaddlePaddle's own index, as shown on the install page.

Official images: PaddleOCR-VL#

For PaddleOCR-VL, Baidu publishes images on ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/. They need Docker ≥ 19.03, an NVIDIA GPU and a driver that supports CUDA 12.6+. The full API service is two containers, a VLM server plus the pipeline. You start it with docker compose up using the compose.yaml and .env from deploy/paddleocr_vl_docker/accelerators/nvidia-gpu/, and it listens on port 8080.6

bash
# Must be executed in the directory containing the compose.yaml and .env files
docker compose up

The docs say this setup "can handle only one request at a time". For concurrent requests they point to deploy/paddleocr_vl_docker/hps/.6

High-stability serving#

High-stability serving is built on NVIDIA Triton. The PaddleOCR docs send you to the PaddleX serving guide for it. They also warn that it "may not match the performance of the 2.x version based on PaddleServing". Clients use the same request format as basic serving. Start with basic serving. Move to Triton when you need GPU batching, several instances, or more stability than one Uvicorn process gives you.1

The official hosted API#

The "PaddleOCR official API" is Baidu's hosted service, linked from paddleocr.com, which redirects to AI Studio. In the docs' words, the SDKs "submit local files or file URLs to hosted PaddleOCR services, poll asynchronous jobs, and parse typed results. They do not run local PaddleOCR inference."7

1 · SubmitPOST /api/v2/ocr/jobsFile upload or fileUrl, plus model. Returns a jobId.
2 · Baidu serversJob queueYour file is processed on paddleocr.aistudio-app.com.
3 · PollGET /jobs/{jobId}state: pending → running → done or failed.
4 · FetchresultUrl.jsonUrlA JSONL file with one result per page.

Compare self-hosting: there, one POST /ocr to your own server returns the result directly and nothing leaves your network.

Get the "API key" (access token)#

There is no separate API key product. Sign in to AI Studio and copy the token from the Access Token page. All SDKs and the CLI read it from one environment variable:7

export PADDLEOCR_ACCESS_TOKEN="your-access-token"

PADDLEOCR_BASE_URL overrides the service URL, for example to route through your own proxy.7

SDKs and CLI#

ClientInstallVersion (Oct 2026)Default models
Python (PaddleOCRClient, AsyncPaddleOCRClient)part of paddleocr, no extrapaddleocr 3.7.0OCR: PP-OCRv6
Parsing: PaddleOCR-VL-1.6
TypeScript (Node.js 18+)npm install @paddleocr/api-sdk0.2.3
Go (Go 1.21)go get github.com/PaddlePaddle/PaddleOCR/api_sdk/gov0.2.0
CLIpaddleocr api, ships with paddleocr3.7.0
from paddleocr import PaddleOCRClient, Model

client = PaddleOCRClient()
result = client.ocr(
    file_url="https://example.com/invoice.pdf",
    model=Model.PP_OCRV5,
)
print(result.job_id, len(result.pages))
client.close()
import { Model, PaddleOCRClient } from "@paddleocr/api-sdk";

const client = new PaddleOCRClient();
const result = await client.ocr({
  fileUrl: "https://example.com/invoice.pdf",
  model: Model.PPOCRv5,
});
console.log(result.jobId, result.pages.length);
client, err := paddleocr.NewClient()
if err != nil {
	return err
}

result, err := client.OCR(ctx, &paddleocr.OCRRequest{
	Model:   paddleocr.PPOCRv5,
	FileURL: "https://example.com/invoice.pdf",
})
if err != nil {
	return err
}
fmt.Println(result.JobID, len(result.Pages))
paddleocr api \
  --model_type ocr \
  --model PP-OCRv5 \
  --file_path ./invoice.pdf \
  --request_timeout 300 \
  --poll_timeout 600 \
  --output ocr-result.json

These snippets are verbatim from the official SDK docs.7 Use file_path / filePath / FilePath for a local file, and pass exactly one of URL or path. Each OCR page in the Python result has pruned_result plus image URLs. For PDFs with tables, use parse_document() or --model_type doc_parsing, which return Markdown per page. Errors are typed (AuthError, RateLimitError, PollTimeoutError, …) and all inherit from PaddleOCRAPIError.7

Raw HTTP (derived from the SDK source)#

Calling it from another language? Here is the protocol the Python SDK speaks, read from its source.8 We have not run this ourselves because we didn't use a token for this page. Treat it as a map of the protocol, not a tested recipe.

bashhosted-api.sh (derived, untested)
BASE=https://paddleocr.aistudio-app.com/api/v2/ocr/jobs

# 1. Submit a local file (multipart). JSON with "fileUrl" instead of a file also works.
curl -s -X POST "$BASE" \
  -H "Authorization: Bearer $PADDLEOCR_ACCESS_TOKEN" \
  -F model=PP-OCRv6 -F 'optionalPayload={}' -F file=@invoice.pdf
#   → {"code": 0, "data": {"jobId": "..."}}

# 2. Poll until data.state is "done" (or "failed")
curl -s "$BASE/<jobId>" -H "Authorization: Bearer $PADDLEOCR_ACCESS_TOKEN"

# 3. Download data.resultUrl.jsonUrl: JSONL, one line per page

Quota, limits and the conflicting page caps#

LimitValueSource
Daily free quota3,000 pages per model per day; over that, HTTP 429Quota doc9
Pages per file"Recommended" max 100; beyond that "the API will only parse the first 100 pages"Quota doc (2026-02-10)9
Pages per request"Supports up to 1000 PDF pages per request"Async guide (2026-02-04)10
File sizeURLs ≤ 200 MB; uploads ≤ 50 MBAsync guide10
More quotaA questionnaire to "apply for a free quota increase"Quota doc9
PriceNot stated on any page we could read—

100 or 1000 pages? Two official AI Studio pages disagree, and the newer one (the quota doc) says 100. Split large PDFs into chunks of 100 pages or fewer, or use --page_ranges / page ranges in the SDK, until Baidu clarifies. Error codes from the quota doc: 403 invalid token, 413 too large, 422 bad parameter, 429 daily cap, 503 too many requests, 504 gateway timeout.910

Privacy. With the hosted API, every file, or every URL you hand it, is processed on Baidu's servers. Results come back as links to stored files. Don't send documents you aren't allowed to share with a third-party processor. Use self-hosting or in-browser OCR for those. Also note: the AI Studio PP-OCRv5 API page says the hosted service "corresponds to PaddleX version 3.3.12". That is older than the 3.7 stack you would self-host.

Doc mistakes and look-alikes to avoid#

  • Wrong endpoint in the OCR Node.js example: it uses /layout-parsing instead of /ocr (OCR.en.md:2471–2487).2
  • Mislabelled API reference links. The "PP-OCRv5 API" link in the SDK docs opens the PaddleOCR-VL page, and the PP-OCRv5 page is behind the "PP-StructureV3 API" label. Go by the page title, not the link text.12
  • npm look-alikes. The unscoped paddleocr and paddleocr-js packages are not from the PaddleOCR team. The official ones are scoped: @paddleocr/api-sdk (hosted API, Node.js) and @paddleocr/paddleocr-js (browser).11
  • PaddleHub serving (deploy/hubserving) is still in the repo from the 2.x era, but the 3.x serving guide recommends PaddleX. We have not checked whether hubserving works with 3.x. If you are upgrading old code, start with the migration guide.

Hooking OCR into an AI agent? The PaddleOCR MCP server can use your self-hosted server as its backend (basic serving only).

Questions#

Is there a free PaddleOCR API?

Yes, two kinds. Self-hosting with paddlex --serve is free and open source (Apache-2.0). You only pay for hardware. The hosted official API has a free quota of 3,000 pages per model per day, according to Baidu's quota doc. We found no published price beyond that.

Where do I get a PaddleOCR API key?

The hosted API uses an AI Studio access token, from aistudio.baidu.com/account/accessToken. Export it as PADDLEOCR_ACCESS_TOKEN. The self-hosted server has no key at all, so add authentication in a reverse proxy if it's reachable from outside.

Why does my request return 422 "File type cannot be determined"?

You sent Base64 without fileType. Add "fileType": 1 for images or 0 for PDFs. Only URLs can be type-sniffed.

Why does the server only read the first 10 pages of my PDF?

Basic serving caps PDFs and multi-page TIFFs at 10 pages by default. Add Serving: extra: max_num_input_imgs: null to your pipeline config and serve that file.

Do I need to write a FastAPI wrapper around PaddleOCR?

Usually not. PaddleX basic serving already is a FastAPI app on Uvicorn, with /health, /docs and a documented JSON schema. Write your own only if you need custom routes or auth inside the same process.

Can I call the self-hosted server from browser JavaScript?

Not directly from another origin. It sends no CORS headers, and the preflight gets a 405. Route the call through your backend or a same-origin proxy, or run OCR in the browser with PaddleOCR.js.

Is there an official PaddleOCR Docker image for the API?

Only for PaddleOCR-VL (GPU, CUDA 12.6+). For the plain OCR pipeline we found none documented. The Dockerfile on this page is our own, and we built and tested it.

Sources

  1. Serving guide (basic serving, CLI options, high-stability serving, URL return): docs/version3.x/inference_deployment/serving/serving.en.md, lines 7–118.
  2. General OCR pipeline, section 3 "Development Integration/Deployment" (POST /ocr, request and response schema, Python client at lines 2144–2165, Node.js example at lines 2471–2487): docs/version3.x/pipeline_usage/OCR.en.md.
  3. PaddleX 3.7.2 source (installed with PaddleOCR 3.7.0): basic serving runs FastAPI on Uvicorn (paddlex/inference/serving/basic_serving/_server.py), exposes GET /health (_app.py:205); default OCR pipeline config paddlex/configs/pipelines/OCR.yaml; serving extra dependencies from the wheel METADATA.
  4. Our test, 2026-10-27/28: Linux x86-64, 4 vCPU, Python 3.13, paddlepaddle==3.2.0, paddleocr==3.7.0, paddlex==3.7.2; paddlex --install serving, paddlex --serve --pipeline OCR, requests sent with the official Python client, curl and Node.js 22 fetch; Docker image built from python:3.12-slim. The machine was shared with other jobs, so we do not publish server timings.
  5. PaddleOCR and PaddleX (pipeline registration names, paddlex --get_pipeline_config): docs/version3.x/paddleocr_and_paddlex.en.md, lines 41–80. Layout parsing endpoint POST /layout-parsing: PP-StructureV3.en.md:3082 and PaddleOCR-VL.en.md:2290.
  6. PaddleOCR-VL service deployment with Docker Compose, images and requirements: docs/version3.x/pipeline_usage/PaddleOCR-VL.en.md, lines 274–309 and 2004–2050.
  7. Official API SDK docs: overview, Python, TypeScript, Go and CLI pages (paddleocr_official_api/*.en.md).
  8. Official API client source: paddleocr/_api_client/_http.py (base URL https://paddleocr.aistudio-app.com, path /api/v2/ocr/jobs, Bearer header, JSON and multipart submit) and _core.py (job states, jobId, resultUrl.jsonUrl).
  9. AI Studio, "API Quota Rules and Error Code Description" (updated 2026-02-10): ai.baidu.com/ai-doc/AISTUDIO/pmjcld5qm, read 2026-10-27.
  10. AI Studio, "Asynchronous API Usage Guide" (updated 2026-02-04): ai.baidu.com/ai-doc/AISTUDIO/Mml7n69e7, read 2026-10-27.
  11. npm registry, 2026-10-27: @paddleocr/api-sdk 0.2.3 (published 2026-06-11); search results for "paddleocr" showing unscoped look-alike packages. Go proxy: api_sdk/go v0.2.0.
  12. AI Studio page titles behind the "Official API Reference" links, read 2026-10-27: Dmh4onssk = PaddleOCR-VL_API_en, 7mfz6dgx9 = PP-OCRv5_API_en, Vmkz2nz1p = PaddleOCR-VL-1.5_API_en, fml7mozw5 = the Chinese async API guide. The repo labels them differently (python.en.md:122–125).
Updated October 27, 2026·How we verify facts