Registry
IRS Form 2848 — programmatic fill compatibility
Power of Attorney and Declaration of Representative · Internal Revenue Service (IRS) · Rev. January 2021. Tested 2026-08-06 on the unmodified upstream blank — every number below comes from a recorded run, not from documentation.
Verdict at a glance
| Tool | Version | Result | Detail |
|---|---|---|---|
| pdfops API | hosted, tested 2026-08-06 | verified + deterministic flatten | 91/91 supported fields landed; flatten=true byte-deterministic (sha256 bcaaacb06222…) |
| pdf-lib | 1.17.1 | verified (91/91) | 91 fields filled in-process; XFA layer dropped on save |
| @cantoo/pdf-lib (fork) | 2.6.5 | verified (91/91) | 91 fields filled in-process; XFA layer dropped on save |
| pypdf | 6.15.0 | text fields verified (70/70) | 70 text fields written and re-read (text fields only) |
| pdftk-java | 3.3.3 | verified (91/91) | 91 fields filled via FDF and re-dumped |
| qpdf --check | 11.9.0 | structurally clean | errors that qpdf cannot detect |
| poppler render check | 24.02.0 | values render (70/70) | 70/70 filled text values present in pdftotext output of the pdf-lib-filled file; page-1 raster sha256 7100c1e3f1ce… |
File facts
- Source: https://www.irs.gov/pub/irs-pdf/f2848.pdf (issuer page: here)
- Blank tested: irs-f2848.pdf · 139 KB · sha256
14377021f95856c453d903aae6a178d8371b3a96e65c28418862394d9f8c2d8e - License: US federal government work — public domain (17 U.S.C. § 105). The hash-verified blank is redistributed here unmodified.
- Structure: 2 pages · AcroForm + XFA layer (hybrid)
- Fields: 92 (70 text, 21 checkbox, 1 button)
Quirks & limitations
- Common in tax-practice automation: CPA and enrolled-agent tooling generates one per client engagement.
- Hybrid AcroForm/XFA, same fill-then-drop-XFA behavior as the other IRS forms.
- Contains a document-level 'Check Form for Common Errors' button backed by JavaScript — the button survives programmatic fill but its checks only run in viewers that execute AcroForm JavaScript (Adobe). Do not rely on it as validation in an automated pipeline.
- Signature lines are plain text fields, not digital-signature fields — filling them types a name; it does not cryptographically sign anything.
Tested request
This exact shape ran against the live API during the recorded test (values here shortened to two fields; the test filled all 91 supported fields). With flatten=true, two identical runs produced byte-identical output — sha256 bcaaacb06222c4904c95ffb6e7ec98a97ada96154d6a07e51c3a35033aa66789.
curl -X POST https://pdfops.dev/api/fill-form \
-F "pdf=@irs-f2848.pdf" \
-F 'fields={"topmostSubform[0].Page1[0].TaxpayerName[0]":"Jane Doe","topmostSubform[0].Page1[0].TaxpayerAddress[0]":"Jane Doe"}' \
-F "flatten=true" \
-o filled.pdf
Enumerate all 92 field names first with the inspector or POST /api/inspect.
Field schema
All 92 fields (name, type, maxLength, options)
| Field name | Type | maxLength | Options |
|---|---|---|---|
topmostSubform[0].Page1[0].CheckForm[0] | Button | ||
topmostSubform[0].Page1[0].TaxpayerName[0] | TextField | ||
topmostSubform[0].Page1[0].TaxpayerAddress[0] | TextField | ||
topmostSubform[0].Page1[0].TaxpayerIDSSN[0] | TextField | 11 | |
topmostSubform[0].Page1[0].TaxpayerIDITIN[0] | TextField | 11 | |
topmostSubform[0].Page1[0].TaxpayerIDEIN[0] | TextField | 10 | |
topmostSubform[0].Page1[0].TaxpayerTelephone[0] | TextField | ||
topmostSubform[0].Page1[0].TaxpayerPlanNumber[0] | TextField | ||
topmostSubform[0].Page1[0].RepresentativesName1[0] | TextField | ||
topmostSubform[0].Page1[0].RepresentativesAddress1[0] | TextField | ||
topmostSubform[0].Page1[0].SentCopies1[0] | CheckBox | ||
topmostSubform[0].Page1[0].CAFNumber1[0] | TextField | 11 | |
topmostSubform[0].Page1[0].PTIN1[0] | TextField | 11 | |
topmostSubform[0].Page1[0].TelephoneNo1[0] | TextField | ||
topmostSubform[0].Page1[0].FaxNo1[0] | TextField | ||
topmostSubform[0].Page1[0].NewAddress1[0] | CheckBox | ||
topmostSubform[0].Page1[0].NewTelephoneNo1[0] | CheckBox | ||
topmostSubform[0].Page1[0].NewFaxNo1[0] | CheckBox | ||
topmostSubform[0].Page1[0].RepresentativesName2[0] | TextField | ||
topmostSubform[0].Page1[0].RepresentativesAddress2[0] | TextField | ||
topmostSubform[0].Page1[0].SentCopies2[0] | CheckBox | ||
topmostSubform[0].Page1[0].CAFNumber2[0] | TextField | 11 | |
topmostSubform[0].Page1[0].PTIN2[0] | TextField | 11 | |
topmostSubform[0].Page1[0].TelephoneNo2[0] | TextField | ||
topmostSubform[0].Page1[0].FaxNo2[0] | TextField | ||
topmostSubform[0].Page1[0].NewAddress2[0] | CheckBox | ||
topmostSubform[0].Page1[0].NewTelephoneNo2[0] | CheckBox | ||
topmostSubform[0].Page1[0].NewFaxNo2[0] | CheckBox | ||
topmostSubform[0].Page1[0].RepresentativesName3[0] | TextField | ||
topmostSubform[0].Page1[0].RepresentativesAddress3[0] | TextField | ||
topmostSubform[0].Page1[0].CAFNumber3[0] | TextField | 11 | |
topmostSubform[0].Page1[0].PTIN3[0] | TextField | 11 | |
topmostSubform[0].Page1[0].TelephoneNo3[0] | TextField | ||
topmostSubform[0].Page1[0].FaxNo3[0] | TextField | ||
topmostSubform[0].Page1[0].NewAddress3[0] | CheckBox | ||
topmostSubform[0].Page1[0].NewTelephoneNo3[0] | CheckBox | ||
topmostSubform[0].Page1[0].NewFaxNo3[0] | CheckBox | ||
topmostSubform[0].Page1[0].RepresentativesName4[0] | TextField | ||
topmostSubform[0].Page1[0].RepresentativesAddress4[0] | TextField | ||
topmostSubform[0].Page1[0].CAFNumber4[0] | TextField | 11 | |
topmostSubform[0].Page1[0].PTIN4[0] | TextField | 11 | |
topmostSubform[0].Page1[0].TelephoneNo4[0] | TextField | ||
topmostSubform[0].Page1[0].FaxNo4[0] | TextField | ||
topmostSubform[0].Page1[0].NewAddress4[0] | CheckBox | ||
topmostSubform[0].Page1[0].NewTelephoneNo4[0] | CheckBox | ||
topmostSubform[0].Page1[0].NewFaxNo4[0] | CheckBox | ||
topmostSubform[0].Page1[0].Table_Line3[0].BodyRow1[0].Description1[0] | TextField | ||
topmostSubform[0].Page1[0].Table_Line3[0].BodyRow1[0].TaxForm1[0] | TextField | ||
topmostSubform[0].Page1[0].Table_Line3[0].BodyRow1[0].Years1[0] | TextField | ||
topmostSubform[0].Page1[0].Table_Line3[0].BodyRow2[0].Description2[0] | TextField | ||
topmostSubform[0].Page1[0].Table_Line3[0].BodyRow2[0].TaxForm2[0] | TextField | ||
topmostSubform[0].Page1[0].Table_Line3[0].BodyRow2[0].Years2[0] | TextField | ||
topmostSubform[0].Page1[0].Table_Line3[0].BodyRow3[0].Description3[0] | TextField | ||
topmostSubform[0].Page1[0].Table_Line3[0].BodyRow3[0].TaxForm3[0] | TextField | ||
topmostSubform[0].Page1[0].Table_Line3[0].BodyRow3[0].Years3[0] | TextField | ||
topmostSubform[0].Page1[0].SpecificUse[0] | CheckBox | ||
topmostSubform[0].Page1[0].AccessRecords[0] | CheckBox | ||
topmostSubform[0].Page1[0].AuthorizeDisclosure[0] | CheckBox | ||
topmostSubform[0].Page1[0].SubtituteOrAdd[0] | CheckBox | ||
topmostSubform[0].Page1[0].SignReturn[0] | CheckBox | ||
topmostSubform[0].Page1[0].AdditionalActs1[0] | TextField | ||
topmostSubform[0].Page1[0].AdditionalActs2[0] | TextField | ||
topmostSubform[0].Page1[0].AdditionalActs3[0] | TextField | ||
topmostSubform[0].Page1[0].OtherActs[0] | CheckBox | ||
topmostSubform[0].Page1[0].OtherActs1[0] | TextField | ||
topmostSubform[0].Page1[0].OtherActs2[0] | TextField | ||
topmostSubform[0].Page2[0].SpecificDeletions1[0] | TextField | ||
topmostSubform[0].Page2[0].SpecificDeletions2[0] | TextField | ||
topmostSubform[0].Page2[0].RetentionRevocation[1] | CheckBox | ||
topmostSubform[0].Page2[0].Title[0] | TextField | ||
topmostSubform[0].Page2[0].PrintName[0] | TextField | ||
topmostSubform[0].Page2[0].PrintNameTaxpayer[0] | TextField | ||
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow1[0].Designation1[0] | TextField | 1 | |
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow1[0].Jurisdiction1[0] | TextField | ||
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow1[0].Bar1[0] | TextField | ||
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow1[0].Signature1[0] | TextField | ||
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow1[0].Date1[0] | TextField | ||
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow2[0].Designation2[0] | TextField | 1 | |
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow2[0].Jurisdiction2[0] | TextField | ||
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow2[0].Bar2[0] | TextField | ||
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow2[0].Signature2[0] | TextField | ||
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow2[0].Date2[0] | TextField | ||
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow3[0].Designation3[0] | TextField | 1 | |
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow3[0].Jurisdiction3[0] | TextField | ||
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow3[0].Bar3[0] | TextField | ||
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow3[0].Signature3[0] | TextField | ||
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow3[0].Date3[0] | TextField | ||
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow4[0].Designation4[0] | TextField | 1 | |
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow4[0].Jurisdiction4[0] | TextField | ||
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow4[0].Bar4[0] | TextField | ||
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow4[0].Signature4[0] | TextField | ||
topmostSubform[0].Page2[0].Table_PartII[0].BodyRow4[0].Date4[0] | TextField |
Frequently asked
Can I fill the IRS Form 2848 programmatically?
Yes — the blank Rev. January 2021 IRS Form 2848 is a fillable AcroForm with 92 fields. In our tested run, all 91 supported fields were filled through the pdfops API and verified by re-inspecting the output; upstream pdf-lib also round-trips it, and pypdf handled its text fields. Field names are positional (e.g. topmostSubform[0].Page1[0].f1_01[0]) — enumerate them via inspection rather than guessing.
Is the IRS Form 2848 an XFA form?
It is a hybrid: the PDF carries both a standard AcroForm field tree and an XFA layer. Programmatic fillers in the pdf-lib family fill the AcroForm layer and drop the XFA layer on save, so the output is a plain AcroForm PDF — which every mainstream viewer renders. Only XFA-first viewers (older Adobe products) behave differently.
← All forms in the registry · Inspect your own PDF · Make a flat PDF fillable