Fill a PDF Form from the Command Line

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.

See Also