← Back to blog
·10 min read

Balance Sheet Parser: Extract Indian Financial Statements with AI

Parse Indian company balance sheets with AI. Extract assets, liabilities, and key ratios into structured JSON for lending, audit, and compliance agents.

balance sheet parserfinancial statement extractionai agentindian fintechdocument extractionfinancial analysistypescriptaudit automation

A company's balance sheet is the single most information-dense document in finance — yet it's almost always locked inside a PDF, formatted differently by every CA firm, Tally version, and statutory filing template in India. Pulling assets, liabilities, and equity figures out of these documents manually takes hours and introduces transcription errors that compound downstream.

Lekha's balance sheet parser extracts share capital, reserves, borrowings, fixed assets, current assets, and deferred tax positions from any Indian financial statement in under five seconds. The response is clean, typed JSON with all amounts as numbers in INR — ready for a credit underwriting model, audit checklist, or net worth dashboard without any cleanup.

This guide covers the structure of Indian balance sheets, how AI extraction outperforms template parsing, and how to build a financial health assessment agent using Lekha.

What's Inside an Indian Balance Sheet?

Indian companies file balance sheets under Schedule III of the Companies Act, 2013. The format is standardised but firms have enough discretion in sub-headings and groupings that no two look identical. Here's the canonical structure:

Equity & Liabilities side

| Line Item | Description | | ------------------------------ | ----------------------------------------------------------- | | Share Capital | Paid-up equity and preference capital | | Reserves & Surplus | Retained earnings, capital reserves, securities premium | | Long-Term Borrowings | Term loans, debentures, bonds maturing beyond 12 months | | Deferred Tax Liabilities (Net) | Timing differences between accounting and taxable income | | Long-Term Provisions | Gratuity, leave encashment, warranty provisions | | Short-Term Borrowings | CC limits, overdrafts, commercial paper | | Trade Payables | Amounts due to creditors for goods and services | | Other Current Liabilities | Advances from customers, statutory dues, current maturities | | Short-Term Provisions | Proposed dividend, income tax provision |

Assets side

| Line Item | Description | | --------------------------- | ------------------------------------------------------- | | Fixed Assets (Tangible) | Plant, machinery, land, buildings — net of depreciation | | Fixed Assets (Intangible) | Goodwill, patents, software, brands | | Capital Work-in-Progress | Assets under construction, not yet commissioned | | Non-Current Investments | Strategic equity stakes, long-term mutual funds | | Long-Term Loans & Advances | Security deposits, advance tax, MAT credit | | Inventories | Raw material, WIP, finished goods, stock-in-trade | | Trade Receivables | Debtors — broken into ≤6 months and >6 months overdue | | Cash & Cash Equivalents | Bank balances, FDs maturing within 3 months | | Short-Term Loans & Advances | Advances to suppliers, prepaid expenses |

A balance sheet for even a mid-size company can run across 10–15 pages once notes to accounts are included. Vision AI reads the entire document as a semantic unit; template-based parsers cannot.

Why AI Outperforms Template Parsing for Indian Balance Sheets

Template-based OCR fixes column positions and keyword patterns — it breaks the moment a CA firm deviates from the expected layout. Indian balance sheets break template parsers because:

  • Tally vs SAP vs Zoho Books generate completely different table structures
  • Consolidated vs standalone financials mix subsidiary data in non-standard ways
  • Older Schedule VI format (pre-2013) still circulates for historical comparisons
  • Scanned physical copies introduce skew, low DPI, and coffee-stain noise
  • Regional language annotations appear in some state-level filings
  • Lekha uses vision AI that reads documents semantically — the way a CA does — rather than positionally. It correctly maps line items to the right category regardless of font, column width, or page layout variation.

    Quick Start: Parse Your First Balance Sheet

    Install the Lekha SDK:

    bun add @lekhadev/sdk
    

    or: npm install @lekhadev/sdk

    Send a balance sheet PDF:

    import Lekha from "@lekhadev/sdk";
    import { readFileSync } from "fs";
    

    const lekha = new Lekha({ apiKey: process.env.LEKHA_API_KEY });

    const pdfBuffer = readFileSync("./balance_sheet.pdf");

    const result = await lekha.extract({ document: pdfBuffer, type: "balance_sheet", });

    console.log(result.data);

    The response is structured JSON — no regex, no manual mapping:

    {
      "company": {
        "name": "Sunrise Manufacturing Pvt Ltd",
        "cin": "U74999MH2015PTC261482",
        "period_end": "2024-03-31",
        "auditor": "M/s Shah & Co., Chartered Accountants",
        "is_consolidated": false
      },
      "equity_and_liabilities": {
        "share_capital": 10000000,
        "reserves_and_surplus": 48250000,
        "long_term_borrowings": 35000000,
        "deferred_tax_liabilities": 1200000,
        "long_term_provisions": 850000,
        "short_term_borrowings": 12000000,
        "trade_payables": 8450000,
        "other_current_liabilities": 3200000,
        "short_term_provisions": 600000,
        "total": 119550000
      },
      "assets": {
        "tangible_fixed_assets": 52000000,
        "intangible_fixed_assets": 1500000,
        "capital_wip": 3800000,
        "non_current_investments": 5000000,
        "long_term_loans_and_advances": 2200000,
        "inventories": 18500000,
        "trade_receivables": 22000000,
        "cash_and_equivalents": 6500000,
        "short_term_loans_and_advances": 8050000,
        "total": 119550000
      }
    }
    

    All amounts are in INR as plain numbers. Dates are ISO 8601. The total fields on both sides match — if they don't, Lekha flags the discrepancy.

    Building a Financial Health Assessment Agent

    Here is a complete agent that parses a balance sheet, computes standard financial ratios, and produces a creditworthiness summary — useful for lending underwriters, NBFC credit teams, and CA audit workflows:

    import Lekha from "@lekhadev/sdk";
    import { readFileSync } from "fs";
    

    const lekha = new Lekha({ apiKey: process.env.LEKHA_API_KEY });

    interface FinancialRatios { current_ratio: number; debt_to_equity: number; debt_to_assets: number; working_capital: number; equity_multiplier: number; net_worth: number; }

    interface CreditSummary { company: string; period_end: string; ratios: FinancialRatios; flags: string[]; rating: "strong" | "adequate" | "weak" | "distressed"; }

    function computeRatios(data: any): FinancialRatios { const ea = data.equity_and_liabilities; const assets = data.assets;

    const current_assets = assets.inventories + assets.trade_receivables + assets.cash_and_equivalents + assets.short_term_loans_and_advances;

    const current_liabilities = ea.short_term_borrowings + ea.trade_payables + ea.other_current_liabilities + ea.short_term_provisions;

    const total_debt = ea.long_term_borrowings + ea.short_term_borrowings; const net_worth = ea.share_capital + ea.reserves_and_surplus; const total_assets = assets.total;

    return { current_ratio: current_assets / current_liabilities, debt_to_equity: total_debt / net_worth, debt_to_assets: total_debt / total_assets, working_capital: current_assets - current_liabilities, equity_multiplier: total_assets / net_worth, net_worth, }; }

    function rateCompany( ratios: FinancialRatios, ): "strong" | "adequate" | "weak" | "distressed" { const score = [ ratios.current_ratio >= 2 ? 2 : ratios.current_ratio >= 1.2 ? 1 : 0, ratios.debt_to_equity <= 1 ? 2 : ratios.debt_to_equity <= 2 ? 1 : 0, ratios.working_capital > 0 ? 1 : 0, ].reduce((a, b) => a + b, 0);

    if (score >= 4) return "strong"; if (score >= 3) return "adequate"; if (score >= 1) return "weak"; return "distressed"; }

    async function assessFinancialHealth( pdfBuffer: Buffer, ): Promise { const result = await lekha.extract({ document: pdfBuffer, type: "balance_sheet", });

    const { company, equity_and_liabilities: ea } = result.data; const ratios = computeRatios(result.data); const flags: string[] = [];

    if (ratios.current_ratio < 1) flags.push( Current ratio ${ratios.current_ratio.toFixed(2)} — current liabilities exceed current assets, );

    if (ratios.debt_to_equity > 3) flags.push(High leverage: D/E ratio ${ratios.debt_to_equity.toFixed(2)});

    if (ea.reserves_and_surplus < 0) flags.push("Negative reserves — accumulated losses exceed paid-up capital");

    if (ratios.working_capital < 0) flags.push( Negative working capital ₹${Math.abs(ratios.working_capital).toLocaleString("en-IN")}, );

    return { company: company.name, period_end: company.period_end, ratios, flags, rating: rateCompany(ratios), }; }

    // Assess a batch of applicants in parallel const files = ["company_a.pdf", "company_b.pdf", "company_c.pdf"];

    const summaries = await Promise.all( files.map((f) => assessFinancialHealth(readFileSync(f))), );

    summaries.forEach((s) => { console.log(${s.company} (${s.period_end}): ${s.rating.toUpperCase()}); if (s.flags.length) console.log(" Flags:", s.flags.join(" | ")); });

    Running this across a portfolio of loan applicants gives your credit team a first-pass view in seconds — before a human analyst touches a single PDF.

    Key Financial Ratios and What They Mean

    | Ratio | Formula | Healthy Range | What it Tells You | | ----------------- | ------------------------------------ | ------------- | -------------------------------------------- | | Current Ratio | Current Assets ÷ Current Liabilities | 1.5 – 3.0 | Short-term liquidity — can it pay its bills? | | Debt-to-Equity | Total Debt ÷ Net Worth | < 2.0 | Financial leverage — how much borrowed? | | Debt-to-Assets | Total Debt ÷ Total Assets | < 0.5 | What fraction of assets is debt-funded? | | Working Capital | Current Assets − Current Liabilities | Positive | Buffer for day-to-day operations | | Equity Multiplier | Total Assets ÷ Net Worth | 1.5 – 4.0 | Asset base relative to shareholder equity | | Net Worth | Share Capital + Reserves & Surplus | Growing YoY | Absolute shareholder value in the business |

    Lekha extracts all the raw line items; your agent computes the ratios. That separation means you can update your credit model without touching the extraction layer.

    Multi-Year Trend Analysis

    A single year's balance sheet is a snapshot. Trend analysis across three years reveals whether a company is deleveraging, accumulating losses, or burning through working capital. Because Lekha returns a consistent schema for every year, diffing is straightforward:

    async function trendAnalysis(yearlyBuffers: Buffer[]) {
      const results = await Promise.all(
        yearlyBuffers.map((buf) =>
          lekha.extract({ document: buf, type: "balance_sheet" }),
        ),
      );
    

    return results.map((r) => ({ period: r.data.company.period_end, net_worth: r.data.equity_and_liabilities.share_capital + r.data.equity_and_liabilities.reserves_and_surplus, total_debt: r.data.equity_and_liabilities.long_term_borrowings + r.data.equity_and_liabilities.short_term_borrowings, current_ratio: computeRatios(r.data).current_ratio, })); }

    const [fy22, fy23, fy24] = await trendAnalysis([buf22, buf23, buf24]); const net_worth_growth = ((fy24.net_worth - fy22.net_worth) / fy22.net_worth) * 100; console.log(3-year net worth growth: ${net_worth_growth.toFixed(1)}%);

    Common Use Cases

    NBFC credit underwriting — Parse three years of balance sheets for each loan applicant, compute leverage ratios, and flag distressed cases before they reach the credit committee. Reduces manual underwriting time by up to 80%. CA firm audit prep — Extract balance sheet figures automatically for the preliminary analytical review stage. Cross-check totals, flag balance-sheet imbalances (assets ≠ liabilities + equity), and pre-populate working papers. Equity research — Aggregate financial statement data across a coverage universe. Build a structured database of balance sheet metrics without manually entering data from annual report PDFs. Vendor due diligence — Before signing large procurement contracts, run a quick financial health check on the vendor. Flag companies with negative net worth or a current ratio below 1 as potential supply-chain risks. Bank covenant monitoring — NBFCs and banks impose financial covenants on borrowers (e.g., D/E ratio must stay below 2). Parse quarterly balance sheets automatically and alert the relationship manager when a covenant is approaching a breach.

    Test with the Lekha Playground

    Before writing any code, upload a balance sheet PDF at lekhadev.com/playground and see the extracted JSON instantly — no API key required. It's the fastest way to verify extraction quality against your specific documents.

    Full schema reference, including all extracted fields for each balance sheet variant, is at lekhadev.com/docs.

    FAQ

    Does Lekha support both standalone and consolidated balance sheets? Yes. The is_consolidated flag in the response indicates whether the figures represent standalone or consolidated financials. Subsidiary line items that appear only in consolidated statements — minority interest, goodwill on consolidation — are extracted separately when present. Can Lekha handle older Schedule VI format balance sheets (pre-2013)? Yes. Lekha handles both Schedule III (Companies Act 2013) and the legacy Schedule VI format. If you're working with historical filings, both formats are supported and the output schema is normalised to the same structure regardless of source format. What if the balance sheet spans multiple pages with notes to accounts? Lekha processes the entire multi-page document as a single extraction. Notes to accounts (depreciation schedules, debt maturity profiles, related-party disclosures) are extracted where they contain quantitative data that populates the core schema fields. How accurate is the extraction on scanned physical balance sheets? Accuracy on clean digital PDFs is very high. Scanned documents at 150+ DPI are handled well; very low-quality scans (below 100 DPI, heavy skew, water damage) may produce lower confidence. The response includes a confidence score so you can route low-confidence extractions for human review.
    Ready to automate balance sheet analysis? Sign up at lekhadev.com and get your API key in 60 seconds. The free tier includes 50 extractions per month — enough to validate extraction quality across your entire document set before committing.