Make a scan searchable
A scanned document is a photograph, not text, which means it cannot be searched, selected, or copied no matter how sharp the scan looks. This searchable PDF API reads the pixels, recognizes the words, and stamps an invisible text layer exactly on top of them, so the page still looks like the original scan but behaves like a real document underneath.
Run it online
Run this on our servers with your account. Free tools run in your browser; this one bills your KIT balance per the price above.
The gap between looking like text and being text
Open a scanned contract and you can read every word with your eyes, but try selecting a sentence or pressing Ctrl-F and nothing happens, because the page is one flat image. That gap between what a human sees and what software can parse is exactly what an OCR text layer closes. Recognition software identifies each character on the page, and instead of replacing the scan with plain text, it places transparent, precisely positioned text directly over the original image, so it stays invisible to the eye but fully present to search.
Who this quietly saves hours for
Anyone who has ever scrolled through a scanned PDF hunting for one clause knows the pain this solves. Law firms digitizing decades of paper files need to search across thousands of scanned pages without opening each one. Archives and libraries want their collections indexed by content, not just filename. Accounts-payable teams need to pull totals out of scanned invoices with a script instead of a person's eyes. In every case the scan itself is fine; what is missing is the machine-readable layer riding underneath it.
What happens when you call the endpoint
POST your scanned PDF to /pdf/ocr-layer and you get a task_id back immediately, since recognizing text across pages takes real processing time that should never block your request. The engine analyzes each page, detects text regions and reading order, recognizes the characters, and writes them as an invisible layer aligned to the original pixels. The finished, searchable PDF is delivered to your signed webhook or made available at a signed link for 24 hours, visually identical to what you sent, just no longer blind to search.
A format built to carry exactly this
PDF has supported invisible text rendering modes since its early specifications, which is precisely the mechanism OCR layering relies on: draw text with a render mode that paints nothing, positioned to match the glyphs in the image beneath it. That capability, largely dormant until OCR software matured enough to use it reliably, is why a scanned page can become searchable without a single visible pixel changing. It is a quiet, decades-old feature of the format doing exactly the job it was built for.
Dropping it into a pipeline
Because delivery is asynchronous and structured, the endpoint fits naturally after any scanning or intake step: a scanner or mobile capture app uploads a page, the webhook confirms the searchable version is ready, and your system indexes it or files it without a person ever touching the file. Access requires prepaid balance, keeping the service fast and abuse-free, and pricing is a flat $0.042 per request plus $0.0025 per page with no hidden units. Note: this endpoint is in final deployment and will begin accepting jobs shortly.
What you can do with it
Digitizing legal archives
A law firm scans decades of paper case files and runs each batch through the endpoint so every page becomes full-text searchable, letting associates find a clause in seconds instead of hours.
Indexing library and museum collections
An archive processes scanned periodicals and manuscripts so its catalog can be searched by content rather than by title and date alone.
Automating invoice data capture
An accounts-payable system adds an OCR layer to incoming scanned invoices so downstream scripts can extract totals and vendor names by parsing text instead of reading pixels.
Making mobile-captured forms usable
A field-service app photographs completed paper forms and converts them to searchable PDFs so office staff can pull up any submission by keyword.
FAQ
How do I make a scanned PDF searchable with an API?
Send a POST to /pdf/ocr-layer with your scanned file. The searchable pdf api returns a task_id right away and delivers the PDF with an invisible text layer to your webhook or a signed link once it finishes.
Is this API free to use?
There's no free tier — free tiers get abused and slow everyone down. Access runs on a prepaid ForHosting KIT balance: top up from $10.00 (it never expires) and each request is charged at its published price, so a call with no balance returns HTTP 402. No subscription, no tokens, no invented credits, and a failed task is never charged.
Is the API accepting jobs right now?
The endpoint is in final deployment and not yet live for requests, but its behavior and pricing are published now so it is ready to integrate the moment it opens.
Will the OCR text layer change how the page looks?
No. The recognized text is invisible and positioned exactly over the original scan, so the page renders identically while becoming selectable, searchable, and copyable underneath.
Does it work on handwriting?
It is built for printed and typed text on scanned pages. Handwritten content is far less predictable to recognize and results on it will vary.
Can I add a text layer to hundreds of scanned PDFs in bulk?
Yes. Each document is submitted as its own POST and processed independently, so you can run a large batch through the endpoint and collect results by webhook as each finishes.
How does this compare to converting a scan into plain text?
Plain-text extraction discards the original page image; this endpoint keeps the scan exactly as it is and layers invisible text on top, preserving the document's original appearance for viewing or printing.
What happens to my scanned document afterward?
The file and its result are deleted after the retention window and are never used to train anything. Delivery is by signed webhook or a signed link valid for 24 hours.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, and soon from our app, email and Telegram.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/pdf/ocr-layer \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"pdf":"https://ejemplo.com/documento.pdf"}'const res = await fetch("https://api.kit.forhosting.com/pdf/ocr-layer", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"pdf": "https://ejemplo.com/documento.pdf"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/pdf/ocr-layer",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"pdf": "https://ejemplo.com/documento.pdf"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/pdf/ocr-layer", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"pdf":"https://ejemplo.com/documento.pdf"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"pdf":"https://ejemplo.com/documento.pdf"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/pdf/ocr-layer", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"pdf": "https://ejemplo.com/documento.pdf"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "pdf.ocr_layer",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_mb | 25 |
max_pages | 200 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
413 | input_too_large | The file exceeds the size limit. |