How to Build a document extraction Agent Using CrewAI in TypeScript for payments
A document extraction agent for payments reads invoices, remittance advices, bank statements, and payment instructions, then turns them into structured data your back office can trust. It matters because every bad extraction becomes a failed reconciliation, a delayed settlement, or a compliance issue that someone has to clean up manually.
Architecture
- •
Input ingestion layer
- •Accepts PDFs, images, and email attachments from S3, blob storage, or an internal queue.
- •Normalizes file metadata: source system, tenant, jurisdiction, and retention policy.
- •
OCR / text extraction tool
- •Converts scanned documents into text before the agent reasons over them.
- •In payments, this needs confidence scores and page-level provenance.
- •
Extraction agent
- •Uses CrewAI
Agentto map raw text into a strict payment schema. - •Produces fields like invoice number, amount, currency, beneficiary name, IBAN, SWIFT/BIC, due date, and tax references.
- •Uses CrewAI
- •
Validation + compliance layer
- •Uses a second
Agentor deterministic checks to verify schema completeness and payment rules. - •Enforces country-specific constraints, sanctions screening hooks, and audit logging.
- •Uses a second
- •
Workflow orchestrator
- •Uses CrewAI
TaskandCrewto coordinate extraction and validation in sequence. - •Routes low-confidence documents to human review instead of auto-posting.
- •Uses CrewAI
- •
Persistence + audit store
- •Stores extracted JSON, model output, confidence metadata, and source document hashes.
- •Keeps an immutable trail for audits and disputes.
Implementation
1) Install the SDK and define the payment schema
CrewAI’s TypeScript package gives you the same core pattern as Python: define Agent, Task, and Crew, then run tasks through the crew. For payments, keep the schema narrow and explicit so the model cannot invent fields you do not use.
npm install @crew-ai/crew-ai zod dotenv
import "dotenv/config";
import { z } from "zod";
export const PaymentDocumentSchema = z.object({
documentType: z.enum(["invoice", "remittance_advice", "bank_statement", "payment_instruction"]),
supplierName: z.string().min(1),
invoiceNumber: z.string().optional(),
currency: z.string().length(3),
totalAmount: z.number().positive(),
dueDate: z.string().optional(),
iban: z.string().optional(),
bicSwift: z.string().optional(),
taxId: z.string().optional(),
confidence: z.number().min(0).max(1),
});
export type PaymentDocument = z.infer<typeof PaymentDocumentSchema>;
2) Create the extraction agent with strict instructions
The important part is not “summarize this document.” The instruction is “extract only these fields, preserve uncertainty, and do not guess.” In payments workflows that difference decides whether you can auto-post or need manual review.
import { Agent } from "@crew-ai/crew-ai";
export const extractionAgent = new Agent({
role: "Payment Document Extractor",
goal: "Extract structured payment data from financial documents without hallucinating missing fields.",
backstory:
"You process invoices and remittance documents for AP and treasury teams. You only return facts present in the source text.",
verbose: true,
});
3) Define the extraction task and run a crew
This example uses one task to extract data from OCR text. In production you usually add a second validation task that checks amounts, identifiers, and policy constraints before anything reaches ERP or payment rails.
import { Crew, Task } from "@crew-ai/crew-ai";
import { extractionAgent } from "./agent";
import { PaymentDocumentSchema } from "./schema";
const ocrText = `
Invoice No: INV-20491
Supplier: Northwind Trading Ltd
Currency: USD
Total Due: 18420.55
Due Date: 2026-05-01
IBAN: GB29NWBK60161331926819
BIC/SWIFT: NWBKGB2L
Tax ID: GB123456789
`;
const extractTask = new Task({
description:
"Extract payment-relevant fields from the OCR text. Return only values supported by the document. If a field is missing, omit it.",
expectedOutput:
"A JSON object matching the payment document schema with confidence between 0 and 1.",
});
const crew = new Crew({
agents: [extractionAgent],
tasks: [extractTask],
});
async function main() {
const result = await crew.kickoff({
inputs: {
documentText: ocrText,
schemaHint: PaymentDocumentSchema.toString(),
},
});
console.log(result.raw);
}
main();
4) Validate output before downstream posting
Do not trust model output just because it looks structured. Parse it with Zod, reject malformed payloads, then route low-confidence cases to review. That is how you keep automation safe in payments.
import { PaymentDocumentSchema } from "./schema";
function validateExtraction(rawJson: unknown) {
const parsed = PaymentDocumentSchema.safeParse(rawJson);
if (!parsed.success) {
return {
ok: false,
reason: parsed.error.flatten(),
};
}
if (parsed.data.confidence < 0.85) {
return {
ok: false,
reason: "Low confidence; send to human review",
};
}
return {
ok: true,
data: parsed.data,
}
}
Production Considerations
- •
Data residency
- •Keep OCR text and extracted payloads in-region if documents contain PII or bank account data.
- •If your deployment spans regions, pin tenants to approved jurisdictions and log every cross-border transfer.
- •
Auditability
- •Persist the original document hash, OCR output version, prompt version, model version, and final JSON.
- •
Guardrails
- •Reject any output that contains unsupported fields or inferred values like “likely supplier” or “probably IBAN.”
- •
Monitoring
Monitor extraction accuracy by document type and country. Track manual review rate, field-level failure rate for IBAN/BIC/currency/date parsing.
Common Pitfalls
- •Using one generic prompt for all documents
Payments docs vary by format. An invoice extractor will miss remittance-specific fields unless you separate document types early.
- •Letting the model infer missing payment details
If an IBAN is absent or unreadable, mark it missing. Never let the agent guess account numbers or amounts.
- •Skipping deterministic validation
LLM output must be checked against schema rules and business rules. Without that layer you will eventually post bad payables or fail reconciliation.
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
By Cyprian Aarons, AI Consultant at Topiax.
Want the complete 8-step roadmap?
Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.
Get the Starter Kit