Flatten PDF form fields into static page content
Ada (Countess) Lovelace typed in a text box on page 1 and a ticked box on page 2 become fixed page content, and the report confirms both were flattened. The form no longer has live fields anyone could edit. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Turn a completed interactive PDF form into a stable document representation whose entered values are part of the page content. This capability accepts page content together with filled field definitions, validates every field location and value, creates deterministic static appearance operations, removes the interactive field collection, and reports exactly which fields were flattened. It is designed for predictable automation after a PDF has been parsed, filled, and approved, with a clear error when the supplied form contains no fields.
What flattening changes in a filled form
A filled PDF can look finished while still containing editable controls. Text boxes, checkboxes, choices, radio buttons, and signature display values may remain separate from the ordinary drawing instructions on each page. That distinction matters when a completed document moves into delivery, printing, or an archive: a viewer can expose or modify the control, and different readers may render its appearance differently.
This capability takes the field values you provide and writes a static appearance operation into the content of the field’s page. The operation is clipped to the supplied field rectangle, uses stable numeric formatting, and escapes characters that have special meaning in PDF strings. After all fields are processed, the returned interactive field collection is empty.
The visible values therefore travel with the page-content model instead of depending on live form controls. The output also includes a field-by-field report, preserving input order, so a calling workflow can record exactly what changed rather than assuming every intended control was handled.
Prepare pages and field values correctly
Supply at least one page, identified by a unique positive page number, with its existing static content stream represented as text. Then provide every filled form field with a unique name, its page number, field type, string value, and rectangle coordinates in PDF points. Supported types cover text, checkbox, radio, choice, and signature fields.
Values are strings because flattening works from the displayed value: for example, a checked box may use “Yes,” while a choice field uses its selected label. Each field must reference a page that exists, and width and height must be greater than zero. The coordinates and all dimensions must be finite numbers.
Validation is intentionally strict. Duplicate names, duplicate pages, unknown types, invalid geometry, missing pages, or non-string values cause a clear input error instead of producing a partly flattened result. Most importantly, an empty fields array is rejected with an explicit message that the PDF form has no fields, preventing a successful-looking no-op from entering an automated document pipeline.
Use the report in a reliable document workflow
Place this transformation after field filling and human or programmatic approval, but before final delivery or archival packaging. The result contains pages ordered by page number, their original content followed by generated appearance operations, an empty fields collection, a flattened count, and a flattened-fields report. Each report entry includes the original name, page, type, and displayed value.
Compare the count with the number of fields your workflow expected, or store the report beside an audit record to make later troubleshooting straightforward. The capability models the form-flattening stage rather than parsing raw PDF bytes, so a binary PDF system should parse its pages and AcroForm fields first, call this operation, and then serialize the returned static page model back into its chosen PDF container.
What you can do with it
Finalize an approved application
Merge applicant values into page content after review and keep the returned field report with the submission record.
Stabilize forms before printing
Remove reliance on interactive controls so the supplied values are represented by deterministic page drawing operations.
FAQ
What does the capability cost?
The browser implementation uses the same deterministic transformation logic.
What happens if the form has no fields?
Empty forms are never reported as successfully flattened.
Which form field types are supported?
The accepted types are text, checkbox, radio, choice, and signature. The provided string is treated as the field's displayed value.
Does this parse a raw binary PDF file?
No. It transforms parsed page content and field values deterministically. A binary PDF pipeline should parse before this step and serialize afterward.
Will brackets or other symbols in a name break the page?
No. Characters that have a special meaning inside a PDF are protected when they are written, so a name like Ada (Countess) Lovelace appears exactly as it was filled in. Each value is also kept inside the rectangle of its own field.
Related tools
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/flatten-form \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"pages":[{"number":1,"content":"q 1 0 0 1 0 0 cm Q"}],"fields":[{"name":"full_name","page":1,"type":"text","value":"Ada Lovelace","x":72,"y":680,"width":220,"height":18}]}'const res = await fetch("https://api.kit.forhosting.com/pdf/flatten-form", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"pages": [
{
"number": 1,
"content": "q 1 0 0 1 0 0 cm Q"
}
],
"fields": [
{
"name": "full_name",
"page": 1,
"type": "text",
"value": "Ada Lovelace",
"x": 72,
"y": 680,
"width": 220,
"height": 18
}
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/pdf/flatten-form",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"pages": [
{
"number": 1,
"content": "q 1 0 0 1 0 0 cm Q"
}
],
"fields": [
{
"name": "full_name",
"page": 1,
"type": "text",
"value": "Ada Lovelace",
"x": 72,
"y": 680,
"width": 220,
"height": 18
}
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/pdf/flatten-form", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"pages":[{"number":1,"content":"q 1 0 0 1 0 0 cm Q"}],"fields":[{"name":"full_name","page":1,"type":"text","value":"Ada Lovelace","x":72,"y":680,"width":220,"height":18}]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"pages":[{"number":1,"content":"q 1 0 0 1 0 0 cm Q"}],"fields":[{"name":"full_name","page":1,"type":"text","value":"Ada Lovelace","x":72,"y":680,"width":220,"height":18}]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/pdf/flatten-form", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"pages": [
{
"number": 1,
"content": "q 1 0 0 1 0 0 cm Q"
}
],
"fields": [
{
"name": "full_name",
"page": 1,
"type": "text",
"value": "Ada Lovelace",
"x": 72,
"y": 680,
"width": 220,
"height": 18
}
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "pdf.flatten_form",
"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. |
Technical notes
Use the report in a reliable document workflow
Because the algorithm has no network access, random choices, clock reads, or mutable shared state, the same input always produces the same JSON output.
Integration use cases
Verify an automated document pipeline
Compare flattened_count and flattened_fields with the expected form schema before serialization, delivery, or archival.
Technical questions
Does the result identify flattened fields?
Yes. flattened_fields reports each field's name, page, type, and value, and flattened_count gives the total.