← Back to blog
·9 min read

IDFC First Bank Statement Parser: AI-Powered Extraction

Parse IDFC First Bank statements into structured JSON with AI. Covers savings, salary, and credit card PDFs, edge cases, and TypeScript integration with Lekha.

idfc first bank statementbank statement parserfinancial document extractionai document parsingindian bankingfintech apitypescriptai agent

IDFC First Bank has quietly become one of India's most popular digital-first banks. Formed from the merger of IDFC Bank and Capital First in 2018, it now serves over 10 crore customers — most of them millennials and self-employed professionals drawn to zero-fee savings accounts, high FD rates, and a slick mobile app.

That popularity means one thing for fintech developers: you will encounter IDFC First Bank statements constantly. Whether you're building a loan underwriting platform, a personal finance tracker, or an automated KYC pipeline, IDFC First Bank PDFs will be in your queue.

This guide walks through how to extract structured JSON from any IDFC First Bank statement using Lekha — India's financial document intelligence API — including the specific format quirks that break generic parsers.

Why IDFC First Bank Statements Are Harder Than They Look

IDFC First Bank statements appear clean and well-formatted, but they have several traits that defeat standard OCR and regex-based parsers:

Three distinct PDF generators. Statements downloaded from the IDFC First Bank app, the net banking portal, and those issued at branches are produced by three separate systems. They share the bank's branding but differ in column widths, font encoding, and how multi-line narrations are wrapped. Merged narration fields. IDFC First Bank packs UPI reference IDs, counterparty VPAs, and remarks into a single free-text narration column. A single transaction can span three lines in the PDF, which OCR tools reading left-to-right will split into three separate phantom transactions. Capital First legacy accounts. Customers who held Capital First loans converted to IDFC First Bank accounts retain a slightly different statement format — including a loan account section appended after the transaction table. Parsers that assume a single transaction table structure will silently drop this data. Credit card billing cycles. IDFC First Bank credit card statements use a billing-period model that doesn't align with calendar months. The reward points section, minimum due, and credit limit all appear in a floating header block that overlaps the transaction table in the PDF coordinate space — a common failure point for bounding-box OCR. Inconsistent Dr/Cr notation. Some statement versions use Dr/Cr suffixes in the amount column; others use a separate debit/credit column with no suffix. The same account can generate either format depending on which branch or portal issued it.

Structured Output: What You Get

When you send an IDFC First Bank statement to Lekha, you get back clean, typed JSON — no amount strings, no DD/MM/YYYY dates, no phantom transactions:

{
  "bank": "IDFC First Bank",
  "account_number": "XXXXXXXX7834",
  "account_type": "Savings",
  "account_holder": "Arun Krishnamurthy",
  "ifsc": "IDFB0040123",
  "branch": "Indiranagar, Bengaluru",
  "statement_period": {
    "from": "2026-07-01",
    "to": "2026-07-31"
  },
  "opening_balance": 42680.5,
  "closing_balance": 67915.25,
  "currency": "INR",
  "transactions": [
    {
      "date": "2026-07-01",
      "description": "NEFT/RTGS-SALARY JULY 2026-ARUN K",
      "type": "credit",
      "amount": 88000.0,
      "balance": 130680.5,
      "reference": "NEFT2607011234567"
    },
    {
      "date": "2026-07-03",
      "description": "UPI-SWIGGY-Q123456789@icici-9876543210",
      "type": "debit",
      "amount": 340.0,
      "balance": 130340.5,
      "reference": "UPI/26703/1234567890"
    },
    {
      "date": "2026-07-05",
      "description": "EMI-IDFC FIRST CC-XXXX7892",
      "type": "debit",
      "amount": 12500.0,
      "balance": 117840.5,
      "reference": "ECS/26705/9876543"
    }
  ],
  "summary": {
    "total_credits": 93500.0,
    "total_debits": 68265.25,
    "transaction_count": 47
  }
}

All amounts are numbers (not strings), all dates are ISO 8601, and multi-line narrations are merged into a single description field.

Quickstart: Parse Your First IDFC First Bank Statement

Install the Lekha SDK and send a file in under a minute:

npm install lekha

or

bun add lekha
import { LekhaClient } from "lekha";
import { readFileSync } from "fs";

const client = new LekhaClient({ apiKey: process.env.LEKHA_API_KEY, });

const pdfBuffer = readFileSync("./idfc-first-july-2026.pdf");

const result = await client.extract({ document: pdfBuffer, mimeType: "application/pdf", });

console.log(result.data.bank); // "IDFC First Bank" console.log(result.data.closing_balance); // 67915.25 console.log(result.data.transactions.length); // 47

That's it. Lekha classifies the document automatically — you don't need to specify the bank or format. Try it live at lekhadev.com/playground.

Handling Salary Accounts

IDFC First Bank salary accounts (often branded as IDFC First Bank Classic or Select salary accounts) have an additional section in the PDF listing employer details and the credited salary component. Lekha surfaces this in the response:

const result = await client.extract({
  document: pdfBuffer,
  mimeType: "application/pdf",
});

const data = result.data;

// Salary-specific fields (present when account_type is "Salary") if (data.account_type === "Salary") { console.log(data.employer_name); // "Infosys Ltd" console.log(data.salary_credits); // Array of salary credit transactions console.log(data.average_monthly_salary); // 88000 }

This is directly useful for loan underwriting workflows where you need to verify employer and income consistency across multiple months.

Parsing Credit Card Statements

IDFC First Bank credit cards (Wealth, Select, Classic, First Millennia) generate a different document structure. Lekha handles both in the same API call:

import { LekhaClient } from "lekha";

const client = new LekhaClient({ apiKey: process.env.LEKHA_API_KEY });

async function parseCreditCardStatement(pdfBuffer: Buffer) { const result = await client.extract({ document: pdfBuffer, mimeType: "application/pdf", });

const cc = result.data;

return { cardNumber: cc.card_number, // "XXXX XXXX XXXX 4521" billingPeriod: cc.statement_period, // { from: "2026-07-01", to: "2026-07-31" } totalDue: cc.total_amount_due, // 28450.75 minimumDue: cc.minimum_amount_due, // 1500.0 creditLimit: cc.credit_limit, // 300000.0 availableCredit: cc.available_credit, // 271549.25 rewardPoints: cc.reward_points, // 4820 transactions: cc.transactions, // Typed transaction array }; }

Processing Multiple Months in Parallel

For loan eligibility checks or financial analysis, you typically need 6–12 months of statements. Lekha is stateless and handles concurrent requests gracefully:

import { LekhaClient } from "lekha";

const client = new LekhaClient({ apiKey: process.env.LEKHA_API_KEY });

async function analyzeIncomeTrajectory(statementBuffers: Buffer[]) { // Parse all months concurrently const results = await Promise.all( statementBuffers.map((buf) => client.extract({ document: buf, mimeType: "application/pdf" }), ), );

// Sort by statement period start date const sorted = results .map((r) => r.data) .sort( (a, b) => new Date(a.statement_period.from).getTime() - new Date(b.statement_period.from).getTime(), );

// Calculate average monthly inflow over the period const monthlyCredits = sorted.map((s) => s.summary.total_credits); const avgMonthlyInflow = monthlyCredits.reduce((sum, v) => sum + v, 0) / monthlyCredits.length;

// Check salary regularity (credit on roughly the same day each month) const salaryCreditDays = sorted.map((s) => { const salaryTx = s.transactions.find( (t) => t.type === "credit" && (t.description.toLowerCase().includes("salary") || t.description.toLowerCase().includes("neft") || t.description.toLowerCase().includes("rtgs")), ); return salaryTx ? new Date(salaryTx.date).getDate() : null; });

return { avgMonthlyInflow, monthlyCredits, salaryCreditDays, isIncomeRegular: new Set(salaryCreditDays.filter(Boolean)).size <= 3, }; }

Common Edge Cases and How Lekha Handles Them

| Edge Case | What Breaks | How Lekha Handles It | | ------------------------------- | ----------------------------------------- | ------------------------------------------------------------------ | | Capital First legacy format | Extra loan section confuses table parsers | Detected as separate section; loan data extracted independently | | UPI narration spanning 3 lines | OCR splits into 3 phantom transactions | Layout-aware model merges multi-line narrations | | Dr/Cr suffix vs. split column | Amount sign inferred incorrectly | Reads both column structure and context to determine direction | | Credit card billing cycle | Date range doesn't match calendar month | Period extracted from header block, not inferred from transactions | | Password-protected PDFs | Parse fails entirely | Lekha returns a clear error; unlock before submission | | Cheque dishonour reversal pairs | Counted as 2 separate debit events | Reversal transactions flagged with is_reversal: true |

Embedding in an AI Agent

If you're building an AI agent that needs to understand a user's financial situation from their IDFC First Bank statement, you can wire Lekha directly into your agent's tool layer:

import { LekhaClient } from "lekha";

const client = new LekhaClient({ apiKey: process.env.LEKHA_API_KEY });

// Tool definition for your AI agent framework export const parseStatementTool = { name: "parse_bank_statement", description: "Extract structured financial data from an IDFC First Bank PDF statement. Returns account details, all transactions, and summary statistics.", parameters: { type: "object", properties: { documentBase64: { type: "string", description: "Base64-encoded PDF of the bank statement", }, }, required: ["documentBase64"], }, execute: async ({ documentBase64 }: { documentBase64: string }) => { const buffer = Buffer.from(documentBase64, "base64"); const result = await client.extract({ document: buffer, mimeType: "application/pdf", }); return result.data; }, };

Pair this with tools for CAS statements, salary slips, and ITR for a full financial profile. See the Lekha docs for the complete list of supported document types.

Accuracy Benchmarks

We ran Lekha against 200 IDFC First Bank statements collected across all major format variants (net banking, app download, branch-issued, credit card):

| Format Variant | Field Accuracy | Transaction Accuracy | | ------------------------------------ | -------------- | -------------------- | | Net banking savings (standard) | 99.1% | 98.7% | | App-downloaded savings | 98.8% | 98.4% | | Branch-issued PDF | 97.6% | 96.9% | | Capital First legacy | 96.8% | 96.2% | | Credit card (all variants) | 98.2% | 97.9% | | Salary account with employer section | 98.5% | 98.1% |

Field accuracy measures account-level fields (holder name, account number, IFSC, opening/closing balances). Transaction accuracy counts correctly extracted, correctly attributed transactions as a share of total transactions in the ground-truth.

FAQ

Does Lekha work with password-protected IDFC First Bank PDFs? No — you need to unlock the PDF before submitting it to Lekha. IDFC First Bank net banking lets you download unlocked statements by default; password protection is typically applied only when a statement is emailed. Use a library like pdf-lib or pikepdf to unlock before sending. Can Lekha handle IDFC First Bank statements older than 2020 (pre-rebranding)? Yes. Lekha recognises both IDFC Bank (pre-merger) and Capital First legacy formats in addition to the current IDFC First Bank format. The bank field in the response will reflect the name shown on the original document. How many months of statements can I send in one request? Lekha processes one statement per API call. For multi-month analysis, send statements in parallel using Promise.all() as shown in the code example above. There is no per-request page limit, so a 12-month statement exported as a single PDF works fine. What happens if a transaction has no reference number? The reference field is null for transactions without a reference ID. This is common for ATM withdrawals and some internal bank transfers. All other fields are still extracted.

Ready to start parsing IDFC First Bank statements? Sign up at lekhadev.com for free API credits and test with your own documents in the playground. The full API reference is at lekhadev.com/docs.