Introduction
Filling the same PDF form by hand — a signup sheet, an onboarding form, an application — is slow and easy to get wrong. This post builds a command-line workflow that reads a blank PDF form, fills its fields from a small JSON file, and writes out a finished copy, then wraps the whole thing into a reusable aux4 command that downloads a form and fills it in one step.
Install the packages
aux4 aux4 pkger install aux4/pdf aux4/curl
aux4/pdf uses qpdf under the hood; the installer pulls it in for you.
Step 1: download the form
You rarely start with the form on disk — it lives behind a URL. aux4 curl request fetches it, and a redirect writes the bytes to a file:
aux4 curl request https://example.com/forms/signup.pdf > form.pdf
file form.pdf
form.pdf: PDF document, version 1.4, 1 pages
The download is byte-for-byte identical to the source, so the form you fill is exactly the form the sender published.
Step 2: see what fields the form has
You can't fill a field you can't name. aux4 pdf parse lists every field with its name, type, and current value:
aux4 pdf parse form.pdf
[
{
"page": 1,
"fields": [
{ "name": "name", "value": "", "type": "TextField" },
{ "name": "email", "value": "", "type": "TextField" },
{ "name": "subscribe", "value": "Off", "type": "CheckBox" }
]
}
]
Now you know the field names (name, email, subscribe) and their types — a text field takes a string, a checkbox takes a boolean. (parse reports a few more details per field, such as the on-page bounding box; the name, type, and value are what you need to fill it.)
Step 3: fill it
aux4 pdf fill reads a JSON array of { name, value, type } on standard input and writes a new PDF with --out. Text values are strings; a checkbox is a real boolean:
echo '[
{ "name": "name", "value": "Sally Ride", "type": "TextField" },
{ "name": "email", "value": "sally@example.com", "type": "TextField" },
{ "name": "subscribe", "value": true, "type": "CheckBox" }
]' | aux4 pdf fill form.pdf --out filled.pdf
PDF filled and saved to filled.pdf
The original form.pdf is untouched; the filled copy is a brand-new file.
Step 4: confirm it worked
Parse the filled file and read the values back — proof the fill landed, without opening a viewer:
aux4 pdf parse filled.pdf
[
{
"page": 1,
"fields": [
{ "name": "name", "value": "Sally Ride", "type": "TextField" },
{ "name": "email", "value": "sally@example.com", "type": "TextField" },
{ "name": "subscribe", "value": "Yes", "type": "CheckBox" }
]
}
]
The text fields carry the values you set, and the checkbox flipped from Off to Yes.
Step 5: make it a reusable command
Keep the field values in a file — values.json — so anyone can fill the form without hand-writing JSON on the command line:
[
{ "name": "name", "value": "Sally Ride", "type": "TextField" },
{ "name": "email", "value": "sally@example.com", "type": "TextField" },
{ "name": "subscribe", "value": true, "type": "CheckBox" }
]
Then define a form fetch command in a local .aux4 file that downloads a form and fills it in one shot:
{
"profiles": [
{
"name": "main",
"commands": [
{
"name": "form",
"execute": [
"profile:form"
],
"help": {
"text": "PDF form helpers"
}
}
]
},
{
"name": "form",
"commands": [
{
"name": "fetch",
"execute": [
"nout:aux4 curl request ${url} > form.pdf",
"cat ${data} | aux4 pdf fill form.pdf --out ${out}"
],
"help": {
"text": "download a PDF form and fill it from a JSON data file",
"variables": [
{ "name": "url", "text": "URL of the blank PDF form" },
{ "name": "data", "text": "JSON file with the field values" },
{ "name": "out", "text": "where to write the filled PDF", "default": "filled.pdf" }
]
}
}
]
}
]
}
Now the whole workflow is one command:
aux4 form fetch --url https://example.com/forms/signup.pdf --data values.json --out filled.pdf
PDF filled and saved to filled.pdf
Conclusion
You went from a blank form behind a URL to a finished PDF without touching a mouse: aux4/curl downloads it, aux4 pdf parse reveals the field names, and aux4 pdf fill writes the values from a JSON file — verifiable by parsing the result. Wrapped as aux4 form fetch, it's a repeatable step you can drop into onboarding scripts, batch runs, or any pipeline that has to fill the same form again and again.