Flatten a PDF
A filled-in form is not a finished document as long as its fields, checkboxes, and sticky-note comments remain live and editable. This flatten PDF API merges every form value and annotation permanently into the page content, turning an interactive PDF into a fixed, final one that looks the same to every viewer and cannot be silently changed after the fact.
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 flattening matters
A signed contract, a completed tax form, or an approved application should not still contain an editable text field with someone's name in it. As long as a PDF's AcroForm fields stay interactive, any reader with basic tooling can alter the values, retype a figure, or delete a checkmark, and the document will still open and print normally — nothing visibly warns that it changed. Flattening closes that gap by converting each field's current value, along with any highlights, stamps, or comment annotations, into ordinary, non-interactive page content.
What the request does
Call POST /pdf/flatten with your document and you get a task_id back immediately, since the work runs asynchronously rather than holding your connection open. Behind the scenes, each form field's current appearance is rendered directly onto the page and the underlying interactive widget is removed, and the same happens for annotation types like text notes, highlights, and stamps. What remains looks identical when opened, but there is no AcroForm left to edit and no annotation layer left to toggle off.
Interactive PDFs versus finished ones
PDF has supported live form fields and annotation layers since the format's early years, largely so paperwork could move through review cycles digitally — a reviewer highlights a clause, a signer fills a field, a manager stamps approval. That flexibility is exactly what makes flattening necessary once the cycle ends: the same mechanism that made a document collaborative during drafting becomes a liability once it is meant to be final. Flattening is the deliberate last step that closes an interactive document out.
Where it belongs in a workflow
Place this step at the end of any pipeline that fills, signs, or annotates PDFs, right after the last legitimate edit and before the file is archived, emailed, or handed to a counterparty. It pairs naturally with a form-fill step: fill the fields programmatically, then flatten immediately so the delivered copy is locked. Because each call is small and self-contained, it is easy to make flattening an automatic, non-optional stage rather than something a human has to remember to trigger.
Delivery and reliability
Flattened documents are returned by a signed webhook, the recommended path for automated pipelines, or via a signed link that stays valid for 24 hours. Source and output files are kept only for the retention window and then deleted, and nothing you send is used to train any model. If a document fails to process, it is retried three times before you receive a clear error, and you are never charged for a failed task.
What you can do with it
Lock a signed contract before delivery
After a signature and date field are filled programmatically, flatten the PDF so the counterparty receives a final copy where those values can no longer be edited.
Finalize a completed government or tax form
Once an application is filled and reviewed, flatten it before archiving so the stored record reflects exactly what was submitted and cannot be altered later.
Close out an annotated review copy
After legal or editorial comments and highlights have served their purpose, flatten the file so the mark-up becomes a permanent part of the page rather than a removable layer.
Prepare a document for print or archival storage
Flatten before sending a PDF to a print shop or a long-term archive, since some print workflows and viewers render interactive fields inconsistently, while flattened content is guaranteed to look the same everywhere.
FAQ
How do I flatten a PDF with an API?
Send the document to POST /pdf/flatten and you receive a task_id immediately. The flattened file, with form fields and annotations baked into the page, is delivered to your signed webhook or a signed link.
Is the flatten PDF API free?
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.
Does flattening remove the ability to fill the form later?
Yes, that is the point. Once flattened, the interactive AcroForm fields are gone and the values become static page content, so the document can no longer be filled, refilled, or resubmitted as a form.
Does it flatten annotations too, or only form fields?
Both. Form field values and annotation types such as highlights, text notes, and stamps are merged into the page content in the same pass, since leaving either one editable would defeat the purpose.
Will the flattened PDF look different from the original?
No. Flattening preserves the visual appearance exactly; only the underlying interactivity is removed, so a viewer sees the same page, just without any field or annotation left to edit.
Can I flatten many PDFs at once?
Yes. Each request is an independent asynchronous task with its own task_id, so you can submit large batches in parallel and collect each flattened file by webhook as it finishes.
Is flattening reversible?
No. Once the fields and annotations are merged into the page, that interactive layer is gone from the output file. Keep your pre-flatten original if you may need to edit the form again later.
Does flattening also compress or otherwise change file size significantly?
Flattening's purpose is to remove interactivity, not to reduce size; any change in file size is typically minor. Use a dedicated compression step if your goal is a smaller file.
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/flatten \
-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/flatten", {
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/flatten",
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/flatten", 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/flatten", 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.flatten",
"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. |