Developer API
Searchable PDF API
Send a scanned PDF or an image to the FastOCR REST API and get back a searchable PDF: the same pages with an invisible OCR text layer, so the file can be searched, selected and copied. It reads 100+ languages. To do this by hand instead, use Make PDF Searchable in your browser.
50 free pages a month, then from $12.00 per 1,000 pages.
How the searchable PDF API works
- 1
Upload the file
Create a document, then upload the scanned PDF (up to 1 GiB) or image (up to 20 MiB) straight to the presigned URL you get back.
- 2
Start and poll
Start the job and poll its status until it is completed, partial or failed. No webhook to host.
- 3
Download format=pdf
Ask for format=pdf to get a one-hour link to the searchable PDF. format=text gives the plain text of the same job.
Concurrency: 2 documents at a time; 10 for accounts with a prepaid API page allowance or API page credits.
Code: scanned PDF to searchable PDF
Each example reads your key from FASTOCR_API_KEY and writes searchable.pdf. Endpoint details are in the Document OCR reference.
Python SDK
# pip install fastocr-sdk
from fastocr_sdk import FastOCR
with FastOCR() as client:
job = client.documents.process("scan.pdf")
client.documents.download_searchable_pdf(job.id, "searchable.pdf")
print(job.id, job.status, job.pages_billed)cURL
export FASTOCR_API_KEY="your_api_key"
# 1. Create a document
RESPONSE=$(curl -sS --fail-with-body -X POST https://api.fastocr.org/v1/documents \
-H "Authorization: Bearer $FASTOCR_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"filename":"scan.pdf","size_bytes":'$(wc -c < scan.pdf | tr -d ' ')'}')
DOCUMENT_ID=$(echo "$RESPONSE" | jq -r .id)
UPLOAD_URL=$(echo "$RESPONSE" | jq -r .upload_url)
# 2. Upload the file to the presigned URL
curl -sS --fail-with-body -X PUT "$UPLOAD_URL" \
-H "Content-Type: application/pdf" \
--data-binary @scan.pdf
# 3. Start processing
curl -sS --fail-with-body -X POST https://api.fastocr.org/v1/documents/$DOCUMENT_ID/start \
-H "Authorization: Bearer $FASTOCR_API_KEY"
# 4. Poll until the status is completed, partial, or failed
while true; do
BODY=$(curl -sS --fail-with-body https://api.fastocr.org/v1/documents/$DOCUMENT_ID \
-H "Authorization: Bearer $FASTOCR_API_KEY") || exit 1
STATUS=$(echo "$BODY" | jq -r .status)
case "$STATUS" in completed|partial|failed) break;; esac
sleep 2
done
echo "Final status: $STATUS"
# 5. Get the download link, then download the searchable PDF (a failed document has no output)
RESULT_URL=$(curl -sS --fail-with-body "https://api.fastocr.org/v1/documents/$DOCUMENT_ID/output?format=pdf" \
-H "Authorization: Bearer $FASTOCR_API_KEY" | jq -r .url)
curl -sS --fail-with-body "$RESULT_URL" -o searchable.pdfNode.js 18+
// Node.js 18+, no dependencies. Save as quickstart.mjs and run: node quickstart.mjs
import { readFile, writeFile } from 'node:fs/promises';
import { randomUUID } from 'node:crypto';
const BASE = 'https://api.fastocr.org';
const auth = { Authorization: `Bearer ${process.env.FASTOCR_API_KEY}` };
async function api(path, init = {}) {
const response = await fetch(BASE + path, { ...init, headers: { ...auth, ...init.headers } });
const body = await response.json();
if (!response.ok) throw new Error(`${response.status} ${body.error?.code ?? body.message}`);
return body;
}
const pdf = await readFile('scan.pdf');
// 1. Create a document
const created = await api('/v1/documents', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Idempotency-Key': randomUUID() },
body: JSON.stringify({ filename: 'scan.pdf', size_bytes: pdf.length }),
});
// 2. Upload the file to the presigned URL
const upload = await fetch(created.upload_url, {
method: 'PUT',
headers: { 'Content-Type': 'application/pdf' },
body: pdf,
});
if (!upload.ok) throw new Error(`Upload failed: ${upload.status}`);
// 3. Start processing
await api(`/v1/documents/${created.id}/start`, { method: 'POST' });
// 4. Poll until the status is completed, partial, or failed
let document;
do {
await new Promise((resolve) => setTimeout(resolve, 2000));
document = await api(`/v1/documents/${created.id}`);
} while (!['completed', 'partial', 'failed'].includes(document.status));
if (document.status === 'failed') throw new Error(document.error.code);
// 5. Get the download link, then download the searchable PDF
const output = await api(`/v1/documents/${created.id}/output?format=pdf`);
const searchable = await fetch(output.url);
if (!searchable.ok) throw new Error(`Download failed: ${searchable.status}`);
await writeFile('searchable.pdf', Buffer.from(await searchable.arrayBuffer()));
console.log(document.status, document.pages_billed);What is in the PDF
- Your scanned pages as the visible layer.
- An invisible text layer placed on each OCR line, for search, selection and copy.
- Text order that keeps each column together on pages with running text in columns.
Right-to-left and CJK documents
Arabic, Persian, Urdu and Hebrew lines are drawn in the order viewers expect, and Chinese, Japanese and Korean text copies out as text. Measured results are on the OCR API page.
Frequently asked questions
What does the searchable PDF API return?
A PDF that looks like your scan, with an invisible OCR text layer on each page. Readers can search it with Ctrl+F or Cmd+F, select and copy text, and search tools can index it. The same document also gives plain text with format=text.
Which files can I send?
PDF files up to 1 GiB: scanned, photographed or mixed PDFs. PNG, JPG, JPEG, GIF, WebP and BMP images up to 20 MiB work too: each image counts as one page and comes back as a one-page searchable PDF.
Does downloading both the text and the searchable PDF cost extra?
No. Pages are counted once per document. You can call the output endpoint for format=pdf and format=text as often as you need while the result is stored.
Can I make Arabic, Hebrew, Chinese or Japanese PDFs searchable?
Yes. The API reads 100+ languages and detects the language itself. Right-to-left lines are drawn in the order PDF viewers expect, and Chinese, Japanese and Korean text uses CJK fonts in the text layer.
How much does the searchable PDF API cost?
Each account gets 50 free document pages per month. After that, prepaid API page packs start at $12.00 for 1,000 pages. There is no subscription.
Make your first PDF searchable
Any signed-in FastOCR account can create an API key and start right away. Each account gets 50 free document pages per month.
Also: PDF OCR API · OCR SDK for Python · Make PDF Searchable online