Any document to JSON
Every document extraction project eventually hits the same wall: generic OCR gives you a wall of text, but your database wants fields. This endpoint takes a document and the schema you define, then returns JSON shaped exactly to that schema, so extraction stops being a text-parsing project and starts being a straightforward API call.
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 OCR and usable data
Plain OCR tells you what characters are on a page; it does not know that the third number in the top-right corner is an invoice total, or that the paragraph under 'Effective Date' is the field your contract system needs. Teams have historically closed that gap with regular expressions tuned to one document layout, which then break the moment a vendor changes their template. This endpoint closes the gap differently: you describe the fields you want, by name and type, and the extraction targets exactly those fields regardless of how the source document is laid out.
How you define what comes back
You send the document plus a schema describing the fields you need, whether that is a flat list like invoice_number and total_due or a nested structure with line items and their own sub-fields, to POST /ocr/to-json. You get a task_id right away, since matching document content to an arbitrary schema takes real processing time. When it finishes, the result is JSON that mirrors your schema, with fields populated where the document contains them and left empty or flagged where it does not, rather than forcing a value that was not actually there.
Why schema-driven extraction generalizes better
Fixed-template extractors have a long history in document automation and they still work well for a single unchanging form, but most real document flows involve dozens of vendor layouts, evolving contract templates, or handwritten variations that a rigid template cannot anticipate. Schema-driven extraction flips the logic: instead of teaching the system one layout, you tell it what a good answer looks like, and it reads any layout looking for that answer. That is what makes the same schema work across an invoice from one supplier and a completely different-looking invoice from another.
How it plugs into the rest of a pipeline
This endpoint is commonly the second step after document classification, since the right schema depends on knowing whether you are looking at an invoice, a lease, or a medical form. Once you have structured JSON, it drops directly into a database insert, a validation rule set, or a downstream key-points summary without any further text wrangling. Because each call carries its own schema, you can run different extractions against different document types in the same pipeline without maintaining separate integrations for each.
Pricing that matches the work involved
The cost is $0.010 per request plus $0.0575 per page, reflecting that extraction time scales with document length, not with how many fields your schema asks for. A task that fails is never charged, we retry automatically up to three times and then return a specific error if extraction genuinely cannot complete. There is no free tier or trial, access requires prepaid balance and calls without one return HTTP 402, which keeps throughput reliable for paying workloads instead of degraded by unmetered traffic.
What you can do with it
Invoice ingestion into an accounting system
An accounts payable team defines a schema with vendor, invoice number, line items, and total, then extracts every incoming invoice into that exact shape regardless of vendor layout.
Lease abstraction for property management
A property manager extracts rent amount, term dates, and renewal clauses from leases with wildly different formatting into one consistent JSON structure.
Insurance claim form digitization
An insurer extracts policyholder details, claim amounts, and incident dates from scanned claim forms directly into their claims database schema.
Medical intake form processing
A clinic extracts patient demographics and insurance information from handwritten intake forms into the exact fields their records system expects.
FAQ
How do I define what fields the document to JSON API extracts?
You send a schema describing the fields you want, by name and type, alongside the document, and the response mirrors that schema exactly, including nested structures like line items.
What happens if a field in my schema is not in the document?
The field is left empty or flagged rather than filled with a guessed value, so you can distinguish genuinely missing data from a parsing failure.
Does it work on scanned paper as well as native PDFs?
Yes, it processes both scanned and native digital documents, and pricing is per page regardless of source format.
Can the same schema work across documents from different vendors?
That is the core advantage over template-based extraction: a well-defined schema targets the same fields across differently laid-out documents without a per-vendor template.
Is there a free tier to test the document to JSON API?
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.
How much does document extraction cost?
It is $0.010 per request plus $0.0575 per page, and you are only charged for pages that are successfully processed.
How do I get the extracted JSON back?
You receive a task_id immediately, then the JSON result arrives via a signed webhook when ready or a signed link valid for 24 hours.
Can I run schema-based extraction on a large batch of documents?
Yes, each request is independent and billed per document, so you can send a single file or fan the same schema out across thousands of documents.
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/ocr/to-json \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"input":"…"}'const res = await fetch("https://api.kit.forhosting.com/ocr/to-json", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"input": "…"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/ocr/to-json",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"input": "…"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/ocr/to-json", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"input":"…"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"input":"…"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/ocr/to-json", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"input": "…"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "ocr.to_json",
"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 | 10 |
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. |
422 | task_failed | The task failed after 3 retries. You are never charged for it. |