Convert PDF to Excel
The numbers you need are sitting in a table, and retyping them is where errors start. This endpoint reads a page you send as an image, finds the tabular data on it, and rebuilds it as actual spreadsheet cells — rows, columns and values you can sum, sort and filter, not a screenshot pasted into a grid.
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.
Why tables in a PDF are stuck
A PDF doesn't store a table the way a spreadsheet does — it stores lines, boxes and positioned text, and a human brain reconstructs the grid on sight. Copy-pasting such a table into Excel usually gives you one column of jumbled text or numbers that lose their decimal alignment. This is the specific, narrow problem this endpoint is built to solve: reading the visual structure of a table on a page and turning it back into rows and columns Excel actually understands.
Who needs a table back, not a document
Analysts pulling figures out of a page of a vendor's report, accountants reconciling a bank statement that only arrives as a scan, researchers digitizing a table from a published paper or a government filing, procurement teams comparing a supplier price list sent as a static image. Anywhere the source data is trapped as a picture-like table and the destination needs to be a working spreadsheet, this is the bridge.
What comes back
Send the page as an image, receive a task_id right away, and the job reads the table on that page and writes it into an XLSX with values in real cells — ready for a SUM formula, a pivot table or a VLOOKUP, not just readable text. If the page holds more than one table, each is detected and written out. It processes one page per request today; a sharp, digitally rendered page reads cleanest, and a scan or phone photo works too, with results that depend on image quality.
Fitting into a data pipeline
Because results land by webhook, this slots into ingestion pipelines without polling: a finance system watches an inbox for incoming pages, fires a conversion request per page image, and loads the resulting XLSX straight into its reconciliation process the moment the webhook confirms it's ready.
A note on where PDF tables come from
PDF was designed in the early 1990s to preserve exactly how a page looks when printed, which is precisely why it's so bad at preserving what a table structurally is. Spreadsheets, by contrast, have stored tabular data as literal rows and columns since the earliest electronic versions in the late 1970s. Converting one into the other is really translating between two different ideas of what a table is — visual layout versus structured data.
What you can do with it
Vendor report reconciliation
A page of a supplier's quarterly report holds a pricing table; sending it as an image returns an XLSX so finance can reconcile against internal records without retyping.
Bank statement analysis
A bank statement page holds the transaction table; converting that page to Excel enables filtering and categorizing without manual entry.
Research data digitization
A researcher needs a table from a page of a published paper in spreadsheet form to run further analysis.
Price list comparison
Procurement receives a supplier price-list page and converts it to XLSX to compare line items side by side.
FAQ
Is the PDF to Excel API live?
Yes, it's live now and ready to accept jobs.
How is it priced?
$0.010 per request plus $0.0575 per page, so a single page comes to $0.0675 — table extraction is the more processing-heavy step, which is reflected in the per-page rate.
Can I convert a whole multi-page PDF at once?
Not in one call yet — each request handles a single page sent as an image. Splitting a multi-page PDF into page images needs container-based rasterization, which is on the roadmap; for now, render each page to an image and send them individually.
Does it work on scans or photos?
Yes — send the page as an image, and a scan or a phone photo works, though results depend on image quality. A sharp, digitally rendered page extracts most reliably.
What if the page has no table?
If the page has no detectable tabular structure, you get a clear error rather than garbled output.
Do I get real spreadsheet cells or just text?
Real cells — rows and columns you can sum, sort, and reference in formulas, not text pasted into a grid.
Is there a free tier?
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 do I get the XLSX file?
By signed webhook when the job finishes, or from a signed link that stays valid for 24 hours.
Am I charged for a failed extraction?
No. Failed tasks retry automatically up to three times and are never billed — you get a clear error instead.
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/doc/pdf-to-excel \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"image":"https://ejemplo.com/libro.xlsx"}'const res = await fetch("https://api.kit.forhosting.com/doc/pdf-to-excel", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"image": "https://ejemplo.com/libro.xlsx"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/doc/pdf-to-excel",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"image": "https://ejemplo.com/libro.xlsx"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/doc/pdf-to-excel", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"image":"https://ejemplo.com/libro.xlsx"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"image":"https://ejemplo.com/libro.xlsx"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/doc/pdf-to-excel", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"image": "https://ejemplo.com/libro.xlsx"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "doc.pdf_to_excel",
"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. |
422 | task_failed | The task failed after 3 retries. You are never charged for it. |