Building a Lending Agent with India's Account Aggregator Network
How to combine Account Aggregator consent-based data with Lekhā's extraction API to build an AI lending agent that can assess loan eligibility in seconds.

What is Account Aggregator?
India's Account Aggregator (AA) framework is one of the most ambitious pieces of financial infrastructure built anywhere in the world. Regulated by the RBI and launched in September 2021, it creates a consent-based system for sharing financial data between institutions — without screen scraping, without PDF uploads, without the user manually downloading statements.
The architecture has three roles:
When a user applies for a loan through an AA-enabled app, the app sends a consent request specifying what data it needs (savings account transactions for the last 6 months, for example). The user approves the request on their AA app (Setu AA, Onemoney, Finvu, etc.). The FIP encrypts the data and delivers it through the AA to the FIU. The entire flow takes seconds.
Why this matters for agent developers: AA gives your lending agent real-time, consent-driven access to a user's financial data — no document uploads, no manual entry, no OCR. The data arrives as structured XML, ready for parsing. Combined with document extraction for salary slips and credit reports, you can build an agent that assesses loan eligibility in under a minute.
The AA Data Flow
The technical flow is straightforward:
FIDataFetch request to the AA, which forwards it to the FIPThe data comes as an FIDataFetch response containing one or more FI blocks. Each block represents a financial account and contains account details, a summary, and transactions. The FI types supported by the AA framework include:
DEPOSIT — savings and current accounts (transactions, balances)RECURRING_DEPOSIT — RD accounts (deposit amount, maturity, interest rate)TERM_DEPOSIT — FD accounts (principal, maturity, tenure)MUTUAL_FUNDS — MF holdings (NAV, units, valuation)INSURANCE_POLICIES — life and general insuranceEQUITIES — demat holdingsFor lending, DEPOSIT is the most valuable — it gives you the full transaction history that replaces a bank statement PDF entirely.
Lekha's /extract/aa Endpoint
Lekha's /extract/aa endpoint parses AA FI XML into structured JSON. Unlike the main /extract endpoint, this one does not use Claude or any AI model. It is pure XML parsing — deterministic, fast, and cheap.
const response = await fetch("https://lekhadev.com/api/v1/extract/aa", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": "lk_live_...",
},
body: JSON.stringify({
fi_data: fiDataBase64, // base64-encoded AA FI XML
fi_type: "DEPOSIT",
}),
});
const result = await response.json();
The response is structured identically to other Lekha extraction responses:
{
"success": true,
"extraction_id": "a1b2c3d4-...",
"document_type": "aa_deposit",
"data": {
"fi_type": "DEPOSIT",
"account_number": "XXXX4521",
"holder_name": "Priya Sharma",
"bank": "HDFC",
"account_type": "savings",
"summary": {
"current_balance": 245000,
"opening_balance": 180000,
"currency": "INR",
"ifsc": "HDFC0001234",
"branch": "Koramangala",
"status": "ACTIVE"
},
"transactions": [
{
"date": "2026-03-01",
"narration": "NEFT-ACME CORP-SALARY-MAR26",
"amount": 95000,
"type": "CREDIT",
"balance": 275000
},
{
"date": "2026-03-02",
"narration": "UPI-RENT-RAMESH-KUMAR",
"amount": 18000,
"type": "DEBIT",
"balance": 257000
}
],
"period": {
"from": "2026-01-01",
"to": "2026-03-31"
}
},
"validation": {
"balance_reconciled": true,
"anomalies": [],
"missing_pages_detected": false
},
"metadata": {
"pages_processed": 1,
"processing_time_ms": 12,
"template_used": "aa_parser_v1"
}
}
Notice the processing time: 12 milliseconds. No AI model inference, no image processing, no prompt tokens. The AA parser runs at pure computation speed — roughly 10x faster than vision-based extraction. For a lending agent making real-time decisions, this latency difference matters.
Building the Lending Agent
Here is a complete lending agent that combines AA data with document extraction. The agent has two tools: one for parsing AA XML (fast, deterministic) and one for extracting PDFs like salary slips and credit reports (AI-powered, higher latency).
import Anthropic from "@anthropic-ai/sdk"; import { Lekha } from "@lekha-dev/sdk"; import fs from "fs";, }, ];const anthropic = new Anthropic(); const lekha = new Lekha("lk_live_...");
// Define the agent's tools const tools: Anthropic.Tool[] = [ { name: "extract_aa_data", description: "Parse Account Aggregator FI XML data into structured JSON. " + "Use this for real-time bank account data received through the AA network. " + "Returns account details, transactions, and balances. Very fast (no AI needed).", input_schema: { type: "object" as const, properties: { fi_data: { type: "string", description: "Base64-encoded AA FI XML data", }, fi_type: { type: "string", enum: ["DEPOSIT", "RECURRING_DEPOSIT", "TERM_DEPOSIT"], description: "Type of financial information", }, }, required: ["fi_data", "fi_type"], }, }, { name: "extract_financial_document", description: "Extract structured data from a financial document (PDF/image). " + "Use this for salary slips, CIBIL reports, ITR forms, and other documents " + "that are not available through Account Aggregator.", input_schema: { type: "object" as const, properties: { document: { type: "string", description: "Base64-encoded document (PDF, PNG, JPEG)", }, type: { type: "string", enum: [ "auto", "bank_statement", "cas", "salary_slip", "itr", "cibil", "gst_invoice", "form_16", "form_26as", "gst_return", "balance_sheet", ], }, }, required: ["document"], }, }, ];
// Execute tool calls async function executeTool( name: string, input: Record
, ): Promise { if (name === "extract_aa_data") { const res = await fetch("https://lekhadev.com/api/v1/extract/aa", { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": "lk_live_...", }, body: JSON.stringify({ fi_data: input.fi_data, fi_type: input.fi_type, }), }); return JSON.stringify(await res.json()); } if (name === "extract_financial_document") { const result = await lekha.extract({ document: input.document, type: (input.type ?? "auto") as "auto", }); return JSON.stringify(result); }
return JSON.stringify({ error:
Unknown tool: ${name}}); }// The lending agent async function assessLoanEligibility( aaFiDataBase64: string, salarySlipPath: string, ): Promise
{ const salarySlipBase64 = fs.readFileSync(salarySlipPath, "base64"); const messages: Anthropic.MessageParam[] = [ { role: "user", content:
You are a lending assessment agent. A customer is applying for a personal loan.You have two data sources available:
- Their bank account data from Account Aggregator (use extract_aa_data tool)
- Their latest salary slip (use extract_financial_document tool)
Here are the inputs:
- AA FI Data (base64): ${aaFiDataBase64}
- Salary Slip (base64): ${salarySlipBase64}
Extract both, then perform a lending assessment:
- Verify income: does the salary credit in the bank match the salary slip?
- Calculate average monthly expenses (excluding salary credits)
- Identify existing EMIs from transaction narrations
- Compute the savings rate (income - expenses) / income
- Determine the maximum affordable EMI (40% of net income minus existing EMIs)
- Provide a loan eligibility verdict with reasoning
let response = await anthropic.messages.create({ model: "claude-sonnet-4-20250514", max_tokens: 4096, tools, messages, });
// Agent loop — let Claude call tools as needed while (response.stop_reason === "tool_use") { const toolBlocks = response.content.filter( (b): b is Anthropic.ToolUseBlock => b.type === "tool_use", );
const toolResults: Anthropic.MessageParam = { role: "user", content: await Promise.all( toolBlocks.map(async (block) => ({ type: "tool_result" as const, tool_use_id: block.id, content: await executeTool( block.name, block.input as Record
, ), })), ), }; messages.push({ role: "assistant", content: response.content }); messages.push(toolResults);
response = await anthropic.messages.create({ model: "claude-sonnet-4-20250514", max_tokens: 4096, tools, messages, }); }
// Print the final assessment const textBlock = response.content.find((b) => b.type === "text"); if (textBlock && textBlock.type === "text") { console.log(textBlock.text); } }
// Run it const aaData = fs.readFileSync("aa-fi-response.xml", "base64"); assessLoanEligibility(aaData, "salary-slip-march-2026.pdf");
The agent extracts both data sources in parallel (Claude will issue both tool calls simultaneously), then reasons over the combined data to produce a lending assessment.
A typical output looks like this:
## Loan Eligibility Assessment
Applicant: Priya Sharma
Monthly Net Salary: Rs 95,000 (verified — salary slip matches bank credit)
Income & Expense Analysis
Average monthly income: Rs 95,000
Average monthly expenses: Rs 52,340
Existing EMIs detected: Rs 8,500 (HDFC Home Loan), Rs 3,200 (Bajaj Finserv)
Current EMI burden: Rs 11,700 (12.3% of income)
Savings rate: 44.9%
Eligibility Verdict: APPROVED
Maximum affordable EMI: Rs 26,300 (40% of income minus existing EMIs)
Recommended loan amount: Rs 8,50,000 (at 10.5% for 36 months)
Risk flags: None — consistent salary credits, healthy savings rate, no missed EMIs
No human in the loop. No manual document review. The agent read the bank data and salary slip, cross-verified income, and produced a decision — all in seconds.
Combining AA + Document Extraction
Account Aggregator and document extraction are not competing approaches. They are complementary, and the strongest lending agents use both.
AA gives you real-time transactional data. Bank account transactions, balances, deposit maturity schedules. This data is machine-generated, structured at source, and delivered through encrypted channels. It is the most reliable source for cash flow analysis. Document extraction gives you everything AA does not cover. Salary slips provide component-level income breakdowns (basic pay, HRA, bonuses, deductions) that no bank transaction can reveal. CIBIL reports provide credit history and scores. ITR forms provide tax filing history. Form 16 provides employer-verified income. None of these are available through the AA network today.A lending agent that only uses AA data can verify cash flow but cannot confirm income components. An agent that only uses document extraction has to rely on static PDFs that may be outdated. Combine both and you get a complete, real-time financial picture: verified income from AA, income structure from salary slips, creditworthiness from CIBIL, tax compliance from ITR.
For processing multiple documents in a single application, use the async extraction endpoint for each document and poll for results:
// Submit salary slip and CIBIL report in parallel
const [salaryJob, cibilJob] = await Promise.all([
fetch("https://lekhadev.com/api/v1/extract/async", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": "lk_live_...",
},
body: JSON.stringify({ document: salarySlipBase64, type: "salary_slip" }),
}).then((r) => r.json()),
fetch("https://lekhadev.com/api/v1/extract/async", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": "lk_live_...",
},
body: JSON.stringify({ document: cibilReportBase64, type: "cibil" }),
}).then((r) => r.json()),
]);
// Poll both jobs
const pollJob = async (jobId: string) => {
while (true) {
const res = await fetch(https://lekhadev.com/api/v1/jobs/${jobId}, {
headers: { "x-api-key": "lk_live_..." },
});
const job = await res.json();
if (job.status === "completed") return job.result;
if (job.status === "failed") throw new Error(job.error);
await new Promise((r) => setTimeout(r, 1000));
}
};
const [salaryData, cibilData] = await Promise.all([
pollJob(salaryJob.job_id),
pollJob(cibilJob.job_id),
]);
Production Considerations
Building a lending agent that works in production requires attention to several operational details.
AA consent is time-limited. A consent artifact specifies how long the FIU can fetch data. Once the consent expires, you cannot re-fetch. Cache the extracted data for the duration of the loan assessment workflow. If the user's application takes multiple days to process, you may need to request fresh consent. Use webhooks for async processing. For loan applications that require multiple documents, register a webhook URL when creating your API key. Lekha will POST the extraction result to your endpoint when processing completes, instead of requiring you to poll. This is cleaner for production workloads with high concurrency.// Webhook payload your server receives
{
"event": "extraction.completed",
"extraction_id": "a1b2c3d4-...",
"document_type": "salary_slip",
"data": { / structured extraction result / },
"validation": { "balance_reconciled": true, "anomalies": [] }
}
Rate limiting matters at scale. Each extraction call (AA or document) consumes one credit against your API key. For a lending platform processing hundreds of applications per day, monitor your usage through the /usage endpoint and set up alerts before you hit plan limits. The dashboard at lekhadev.com shows real-time usage across all document types.
Privacy is non-negotiable. Lekha never stores documents or extracted data. Processing happens in memory only. For AA data, this aligns with the RBI's guidelines on data minimization — the FIU should only retain data for as long as the stated purpose requires. Log the extraction_id for audit trails, not the data itself.
Handle partial AA data gracefully. Not all FIPs respond at the same speed. A consent request covering 3 bank accounts may return data from 2 immediately while the third takes 30 seconds. Your agent should process available data and retry missing FIPs rather than blocking on all responses.
Comply with RBI guidelines on automated lending decisions. The RBI's digital lending guidelines (September 2022) require that loan decisions are explainable and that borrowers can access their assessment data. Build your agent's reasoning to be auditable — log the factors that contributed to approval or rejection, and surface them to the user.
What's Next
The complete lending agent code from this post is available as a runnable example in the examples directory on GitHub. Clone it, add your API key, and have a working lending agent in five minutes.
For the full API reference — including all 10 document types, async extraction, and webhook configuration — see the documentation.
We are actively working on multi-language document support for Hindi, Tamil, and Kannada financial documents. If your users receive bank statements in regional languages, reach out — we would like early testers.
Your agent just learned to lend.