All posts
Blog5 min read

How to fill PDF forms automatically with AI (from JSON, a spreadsheet, or Claude)

The short answer: call POST /api/v1/inspect (free) to get the form's exact field names, then POST /api/v1/fill with a JSON map of field → value. You get back a presigned link to the filled PDF. From Claude, it's the same two steps as MCP tool calls — no code at all.

The rest of this post covers why the obvious approaches fail, the exact requests, what happens to fields that don't match, and how to batch a hundred forms from one data source.

The problem: the receiving side wants their form

Insurance claims, government filings, KYC packets, HR onboarding — the official document is a fillable PDF, and it's non-negotiable. You can't send a nicely formatted re-creation; the county clerk wants the county clerk's form.

Meanwhile the answers already exist as structured data: in your CRM, in a spreadsheet, in an intake conversation your agent just had. The last mile is a human opening Acrobat and typing values into boxes, one by one, form after form.

Most tools in this space take one of two shapes:

  1. Browser bots — an AI "looks" at the rendered form, clicks into fields, and types. It works in a demo and breaks on the form with a two-column layout, a field the model mislabels, or a dropdown it can't see. And you can't run it headlessly at volume.
  2. LLM-only filling — hand the PDF and your data to a model and hope. The failure mode is silent: a value lands in the wrong box, or doesn't land at all, and nothing tells you.

A fillable PDF already knows its own structure. AcroForm fields have exact names, types, and (for dropdowns) allowed options. The reliable way to fill a form is to talk to those fields directly — deterministically — and use AI for the part it's actually good at: producing the values.

Step 1: inspect the form (free)

curl -s https://inkrun.dev/api/v1/inspect \
  -H "Authorization: Bearer sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "file_url": "https://example.com/claim-form.pdf" }'

The response's form.fields inventory lists every field's exact name and type — text, checkbox, radio group, dropdown — so you (or your agent) can look before you leap. Inspection costs nothing.

Step 2: fill it

curl -s https://inkrun.dev/api/v1/fill \
  -H "Authorization: Bearer sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "file_url": "https://example.com/claim-form.pdf",
    "fields": {
      "applicant.name": "Ada Lovelace",
      "policy_no": "PL-88121",
      "date_of_loss": "2026-07-02",
      "agree": true,
      "country": "PT"
    }
  }'
{
  "id": "ext_5e6f7a8b",
  "status": "filled",
  "filled": ["applicant.name", "policy_no", "date_of_loss", "agree", "country"],
  "warnings": [],
  "pages": 3,
  "url": "https://…presigned…",
  "credits_charged": 1
}

Text fields take strings or numbers; checkboxes take true/false (or "yes"/"no"); radio groups, dropdowns, and option lists validate the value against the field's actual options. Up to 200 fields per call.

The part that matters for trust: nothing is silently dropped. A field name the form doesn't have comes back as a warning. An invalid dropdown option comes back as a warning listing the valid ones. Signature and button fields can't be filled and say so. XFA forms (legacy Adobe XML) and encrypted PDFs are rejected up front rather than mangled. Check warnings and you know exactly what landed.

Doing it from Claude — no code

Inkrun's MCP server exposes the same two steps as tools (inspect_document, fill_form), so an agent can do the whole thing conversationally. Add https://inkrun.dev/api/mcp as a custom connector (setup guide), attach the form, and ask:

"Here's the intake conversation with the client. Fill out the attached claim form with their details."

Claude inspects the form's fields, maps the conversation onto them, calls fill_form, and hands you the download link — with warnings surfaced if anything didn't match. This is the right division of labor: the LLM interprets messy human context into values; the filling itself is deterministic.

Batch: a hundred forms from one spreadsheet

Because filling is one idempotent API call (an Idempotency-Key header is honoured), batching is a loop, not a product tier: iterate your rows, send one /api/v1/fill per record, collect the links. From an automation tool like n8n or Zapier it's a single HTTP Request node inside your existing workflow.

The killer combination: extract from one document, fill another

The answers often live in another PDF. Inkrun's extraction API closes that loop: pull structured, grounded data out of a signed contract with extract, push it into the registration form with fill_form — two calls, zero retyping, every value traceable to where it came from.

FAQ

What does it cost? 1 credit per filled PDF — the same "1 credit per produced document" rule as a render. Inspection is free. The free tier's monthly credits cover it; current numbers live on the pricing page.

Is my form stored? No. The source form bytes are processed in memory and never stored. Only the filled output is kept, on the same retention policy as any render, behind a presigned URL.

What about flat (non-fillable) PDFs? fill_form needs real AcroForm fields. If the "form" is just a printed layout, the round-trip endpoint (/api/v1/generate) is the better fit: extract the data and render it into your own template.

The filled values don't show in my PDF viewer. Some producers' forms ship stale field appearances. The values are always set, and the output flags NeedAppearances so conforming viewers redraw them — Acrobat, Preview, and Chrome all render correctly.

Give your agent a PDF tool.
Connect Inkrun in five minutes — the free tier includes 20 renders a month.
Get started