PDF Repair Diagnostic
A damaged PDF often produces a confusing list of parser messages without explaining what can actually be repaired.
Run — free
This PDF repair diagnostic turns those structural findings into a practical report. Provide issues such as a missing cross-reference table, an unterminated stream, a bad length value, or a truncated file. Each item receives a consistent classification, risk level, recommendation, and place in an ordered plan. The result helps engineers decide whether an automated repair attempt is reasonable before changing the original file.
Turn validator messages into a repair decision
PDF validators are good at naming broken structures, but their output is rarely a complete decision aid. A message about a missing cross-reference table describes a navigation failure, while an unexpected end of file may mean that bytes are permanently absent. Treating those findings as equivalent can waste time or destroy evidence that a specialist could have recovered. This diagnostic normalizes each supplied description and compares it with explicit structural failure families. It marks recognized problems as fixable only when a bounded reconstruction technique exists. It also assigns a risk level and explains the recommended action. Unknown descriptions are deliberately classified as not fixable by this automated report, because a confident guess is dangerous when object boundaries and references may already be unreliable. Add an object number, byte offset, page, or trailer location when your validator provides one. That context is copied into the report so the repair operator can connect each recommendation to the original finding without searching through a separate log.
Understand what fixable means
A fixable classification means the damaged structural record can usually be rebuilt from information that remains elsewhere in the file. For example, indirect object markers can be scanned to reconstruct a missing cross-reference index, and encoded stream bytes can be measured to correct a Length mismatch. It does not mean every page, font, image, annotation, or form value is intact. An unterminated stream is classified as fixable with high risk because a reliable following object boundary may reveal where the stream ends, yet ambiguous binary data can still prevent a safe repair. By contrast, truncation is not fixable when missing bytes contained unique content, and an absent catalog is not automatically repairable because selecting a document root requires understanding intended relationships. Encryption failures also remain blocked until authorized credentials are available. Keep the original file immutable, perform work on a copy, and read the recommendation alongside the risk. The classifications are deterministic: identical issue descriptions produce identical results, with no network call, random choice, or language model interpretation.
Apply and verify the ordered plan
The generated plan includes only items classified as fixable and keeps them in discovery order. That ordering makes the report easy to compare with a validator log, but a repair tool may need to group related changes in one rewrite. Preserve object generations where possible, avoid reusing occupied identifiers, and update indirect references whenever an object is renumbered. If stream extents or object offsets change, rebuild the cross-reference data after those edits rather than before them. Every step includes a verification instruction that asks you to parse the output again and confirm that the target finding disappeared without introducing new structural failures. Final verification should use an independent parser, because testing only with the library that wrote the repair can hide shared assumptions. Compare the page count and reachable object graph with the source, open representative pages visually, and check interactive features when they matter. A green structural parse is necessary but does not prove that missing content has returned. If any item is classified as not fixable, retain it in the case record and escalate it instead of silently omitting it from the outcome.
What you can do with it
Triage a validator report
Convert raw structural findings into a consistent list of repairable and blocked problems before assigning engineering work.
Plan a recovery pipeline
Use ordered recommendations to choose reconstruction stages and the validation checks that follow each change.
Document a repair decision
Attach classifications, locations, risks, and recommendations to an incident or archival recovery record.
FAQ
Does this capability repair the PDF itself?
No. It classifies a supplied list of structural findings and produces a plan; it never receives or changes the PDF bytes.
What does fixable mean in the report?
It means a recognized structural repair can often be derived from surviving information. It is not a guarantee that all document content is recoverable.
What happens to an unfamiliar validator message?
It is classified as an unrecognized structural issue and not fixable automatically, with a recommendation for manual inspection.
Why is an empty issue list rejected?
A diagnostic without findings cannot classify anything or produce a meaningful repair plan, so the request returns an invalid input error.
How much does a report cost?
Each API request costs $0.002. The capability uses deterministic local processing and no external model or network service.
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, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/pdf/repair-report \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"issues":[{"description":"Missing cross-reference table","location":"file trailer"},{"description":"Unterminated stream","location":"object 18"}]}'const res = await fetch("https://api.kit.forhosting.com/pdf/repair-report", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"issues": [
{
"description": "Missing cross-reference table",
"location": "file trailer"
},
{
"description": "Unterminated stream",
"location": "object 18"
}
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/pdf/repair-report",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"issues": [
{
"description": "Missing cross-reference table",
"location": "file trailer"
},
{
"description": "Unterminated stream",
"location": "object 18"
}
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/pdf/repair-report", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"issues":[{"description":"Missing cross-reference table","location":"file trailer"},{"description":"Unterminated stream","location":"object 18"}]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"issues":[{"description":"Missing cross-reference table","location":"file trailer"},{"description":"Unterminated stream","location":"object 18"}]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/pdf/repair-report", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"issues": [
{
"description": "Missing cross-reference table",
"location": "file trailer"
},
{
"description": "Unterminated stream",
"location": "object 18"
}
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "pdf.repair_report",
"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_items | 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. |