From Quarterly Results PDFs to Structured Financial APIs
A production AI workflow for extracting, validating, and publishing financial statements from result-season PDFs before standardized XBRL data is available.
Ganesh Voona
Co-Founder11 min read

Results season is chaotic because it begins before clean data arrives.
When listed companies announce quarterly results, the first filing available to the market is usually a PDF document. It may be scanned, semi-structured, or digitally generated. The standardized XBRL-tagged filing or clean financial data feed may arrive later, sometimes after a few hours and sometimes after a few days.
That gap matters for fund management teams. Results season is not about reading one company in isolation. Teams are tracking a listed-company coverage universe, updating financial models, revising estimates, checking portfolio impact, and reacting while the market is still processing the numbers.
The challenge is that quarterly results PDFs are not built for automation. The key financial statements may be buried somewhere inside a long document. Many companies place standalone and consolidated numbers together, with latest quarter, previous quarter, year-ago quarter, half-year, and annual figures side by side. A simple parser breaks, and a simple LLM call can return clean-looking but wrong data.
We built a workflow to turn these quarterly results PDFs into structured financial statements before standardized XBRL data is available.
The core lesson was simple: the hard part was not using an LLM. The hard part was deciding what the LLM should not do.
At a Glance
Problem: Quarterly results PDFs often arrive before clean XBRL data, but analysts need the first read immediately.
Approach: Preserve table structure, identify the right statement and period, extract the reported statement as-is, map it into a standard schema, and verify the standardized output against the totals printed inside the filing.
Lesson: LLMs are useful for semantic mapping. Reliability comes from the workflow around them: scoped inputs, typed outputs, deterministic checks, repair loops, and explicit failure handling.
Sample table from quarterly results PDF: Human-readable, but not automation-friendly.
1. Why the Simple LLM Approach Fails
At first glance, this looks like a document extraction problem: take the PDF, convert it to text, send it to an LLM, and ask for structured financials. That works for a demo, but it does not work reliably in production.
Quarterly results PDFs are messy in ways that are easy to underestimate. If the document is scanned, the first challenge is OCR. But even when OCR works, the financial table can still be unusable if rows, columns, headers, and page context are lost.
A number is not meaningful by itself. It only means something because of the row it belongs to, the column it sits under, the reporting period, the unit, and whether the table is standalone or consolidated.
The bigger issue is that the model can return clean-looking JSON even when it has read the wrong thing. It may pick the wrong table, mix standalone and consolidated numbers, read the wrong period column, or treat year-to-date figures as quarterly figures.
For financial data, clean JSON is not the same as correct data.
2. The Workflow That Worked
The production workflow became a set of smaller steps:
- Convert the PDF into OCR output with table structure preserved.
- Build a statement index from the table-aware document.
- Identify where each relevant statement exists: page, table, reporting basis, period columns, and unit.
- Use only that specific page or table to extract the latest-quarter statement as reported by the company.
- Convert the reported statement into structured JSON without trying to standardize it too early.
- Map that reported JSON into a typed standardized financial schema.
- Run verification checks against the inline totals printed in the filing.
- Use a repair loop to fix mapping, roll-up, split, or classification errors where possible.
- Flag cases that still do not clear verification.
This separation matters.
The first extraction step is about fidelity: capture what the company reported from the right table and the right period. The second step is about standardization: map that reported statement into a consistent schema that downstream systems can use.
The verification step sits after standardization because that is where most transformation errors show up. A line item may have been rolled up incorrectly, split into the wrong bucket, duplicated, or missed. The inline totals in the filing give us a way to check whether the standardized statement still reconciles with what the company actually reported.
3. Design Decisions That Made It Work
3.1 Preserve Table Structure Before Reasoning
We stopped treating OCR as a plain text conversion step. The goal was not just to extract words from a PDF; it was to preserve the financial table as a table.
So before the LLM sees the document, we convert the PDF into a structured representation that keeps rows, columns, headers, page markers, and table blocks intact. OCR and layout extraction handle the scanned or semi-structured PDF layer. But the important part is what the rest of the pipeline receives: table structure, not a flattened text dump.
This matters because most extraction errors start before the model reasons about the document. If the table structure is broken, the model may still produce a confident answer, but it is reasoning from damaged input.
3.2 Index First, Extract Later
The next problem was scope. A quarterly results PDF can contain multiple tables: standalone results, consolidated results, notes, segment details, auditor text, balance sheet, cash flow, prior periods, and annexures. Sending the full document into every extraction call made the workflow slower, costlier, and less reliable.
So we added a statement index before extraction. The indexer’s job is not to extract financial values. Its job is to understand the document structure. It identifies candidate tables, statement types, page numbers, reporting basis, period columns, units, and whether a table should feed downstream extraction.
Once that map exists, extraction becomes a narrower problem. Instead of asking the model to “extract financials from this PDF,” we can ask it to extract a specific statement from a specific table, for a specific reporting basis, period, and unit.
That one change made the LLM much more useful. The model was no longer responsible for finding everything, understanding everything, and extracting everything in one step. It had a smaller job with clearer boundaries.
3.3 Extract The Reported Statement Before Standardizing
The first extraction step should stay close to what the company reported. Once we know the exact page or table, we extract the latest-quarter statement as reported by the company and convert it into structured JSON. At this stage, the goal is not to force the data into our standard schema. The goal is to capture the reported statement faithfully from the right table, right period, right unit, and right reporting basis.
This avoids mixing two hard problems too early. Raw extraction answers what the company reported; standardization answers how it should fit into our schema. Keeping those steps separate makes the workflow easier to verify and repair.
3.4 Standardization Is Not Just Renaming Line Items
Companies do not report financial statements in a single standard format.
The same economic item can appear under different names across companies. Sometimes the mapping is straightforward but often it is not just a rename.
A reported line item may need to be rolled up into a broader standardized field. A single company-reported number may need to be split or adjusted. Some items may need to move across sections to fit the standard schema. For example, if revenue is reported alongside an excise duty adjustment, the standardized output may need to adjust revenue and expenses so the final income statement still reflects the company’s reported totals correctly.
The same problem appears across the income statement, balance sheet, and cash flow statement. Companies may use their own labels, subtotals, ordering, and disclosure style. But downstream workflows need a consistent structure: revenue, expenses, assets, liabilities, equity, operating cash flow, investing cash flow, financing cash flow, and other standardized fields.
This is where LLMs are useful. The model can read company-reported line items in context and decide how they should map into the standardized schema.
But the model cannot be allowed to freely transform the statement without checks. It should not miss a reported item. It should not double count the same number. It should not force an ambiguous line item into the wrong bucket just to make the output look complete.
That is why standardization and verification have to work together. The LLM handles the messy semantic mapping. The system around it checks whether the transformed output still reconciles with what the company actually reported.
3.5 Typed Output Is Only The Beginning
Once the reported statement is standardized, the output has to be usable downstream. That means it cannot be arbitrary JSON.
We use typed schemas for different statement types and company contexts. The schema does not make the model perfect, but it changes the failure mode. Instead of getting open-ended output, we get structured data that can be verified, repaired, stored, and served through APIs.
This is one place where LLMs are useful. They are good at semantic mapping when the input is scoped and the output is constrained.
They are less useful when asked to do everything at once.
3.6 Verification Is Part Of Standardization
The most important production question was not whether the model could produce JSON; it was how we could know the standardized JSON was right. Quarterly results PDFs usually contain line items and their own reported totals inside the same table, so we use those inline totals as verification anchors. After the reported statement is mapped into the standardized schema, we compare the transformed output against the totals printed in the filing.
For Profit & Loss, we compare standardized income and expense line items with company-reported totals such as total income, total expenses, profit before tax, and profit after tax. For Balance Sheet, we check whether assets reconcile with liabilities and equity. For Cash Flow, we check whether operating, investing, and financing cash flows reconcile with the reported change in cash and the opening and closing cash balances.
These checks are deterministic. We are not asking the model whether it is confident; we are comparing the standardized output against the company’s own reported totals.
The verification layer compares standardized outputs with the totals printed in the filing, then either passes the statement forward, retries with mismatch feedback, or flags it for review.
When verification fails, the repair loop receives the current standardized output and the mismatch summary, not the full PDF again. It then tries to fix common issues: missed line items, duplicate mappings, incorrect roll-ups, or items placed in the wrong standardized field. If the statement still does not clear the checks, it is flagged instead of being quietly published as clean data.
For investment research workflows, this matters: a failed extraction should be visible, not hidden behind a polished JSON response.
4. What We Deliberately Did Not Let The Model Do
A useful way to think about the system is to look at what the LLM does not do. It does not perform OCR. It does not reconstruct tables from broken text. It does not decide on its own which pages matter. It does not do accounting math. It does not validate itself by saying it is confident. It does not publish failed statements.
Those responsibilities sit outside the model. The model is a bounded component inside the workflow. It handles the semantic parts of the problem. The system around it controls the inputs, outputs, verification, repair loops, and failure handling. That split is the real architecture.
5. What This Enables
The point of this workflow is not just to create a clean JSON file. Once quarterly results PDFs become structured statements, they can feed real research workflows: APIs for latest reported financials, webhooks when statements are processed, portfolio monitoring dashboards, alerts for margin or cash flow changes, and internal models that need normalized statement metrics.
Analysts still make the investment judgment. The system removes the repetitive work of rebuilding statements from PDFs when time matters most.
6. What We Learnt
The biggest lesson was that production AI workflows are less about one powerful prompt and more about boundaries. OCR quality matters, but table structure matters more. LLMs are useful, but only after the document has been narrowed to the right scope. Typed schemas help, but verification is what makes the output trustworthy. Repair loops are useful, but only when failures are explicit.
The pattern that worked was not “let the LLM process the PDF.” The pattern was: preserve structure, narrow scope, extract faithfully, standardize carefully, verify deterministically, and flag uncertainty. That is how AI becomes useful in production: not by replacing the workflow, but by becoming one controlled component inside it.