A Form 990 parser for a registrations firm
Jul 1 – Sep 12, 2026
A small firm that files state charitable registrations for nonprofits needed the figures on their clients' IRS Form 990s to reach their records system without anyone typing them in. Returns arrive digital or scanned, in three variants of the form, sometimes behind e-file cover pages.
What was built
A parser for the Form 990, 990-EZ and 990-PF that detects which form it has, skips cover pages, reads digital and scanned returns, and records the page each field came from. Two more parsers read two states' charitable registration statements. A hosted service puts it behind a browser upload page and an API, so results can go straight into the firm's records.
What made it hold up
The standard I held it to: a figure reaches the firm marked verified only when the form's own arithmetic confirms that exact figure, and a value it cannot read is flagged, never treated as zero. A passing sum proves the total, not the lines inside it, because two misreads by opposite amounts still add up.
Review before each release caught where that rule leaked, including an officer subtotal read as one officer's pay and then checked against itself. Each was fixed as a rule across every form.
Real returns found the rest. One scanned signature page could send a whole digital return down the path meant for scans, which on one return cut a 36-name officer roster to 26. That shows the failure existed, not how often; the fix was confirmed live. On a client return, a checked box extracted as the digit 4 and was read as gross receipts. The client merged that fix on September 12.
Beyond the parser
The firm also asked about automating the state filings themselves. Before scoping anything, I walked Tennessee's charity portal one screen at a time and submitted, paid and signed nothing. For the organization I used, the state refused to open a renewal, which it allows only within 90 days of the date in its own records, and refused an extension without giving a reason, so a system must know each client's dates and treat a refusal as normal. The filed renewal I read carries two signatures under penalty of perjury, so any design has to leave a person on the final screens.
I then sized a full system, and the firm decided not to build it for now. I agreed with that call. What I took from it: size the work to the client, and check what it would save them before sizing anything.
Clayton was great to work with. He ensured the project was done well and that we were happy. He created a great solution and showed us the right way to do things.
Client, UpworkJul 1 – Sep 12, 2026
Scope. Four milestones between July 1 and September 12, 2026: the Form 990 extractor and its tie-out checks; the short-form, private-foundation and first state parsers; the hosted service; and the second state parser. All four were paid, and the client closed the contract on September 12. The code and hosting sit in the client's own accounts. The Tennessee walk was one session, and no filing system was commissioned or delivered.