96.1% field extraction accuracy on South African financial documents. AI-powered parser that turns invoices, bank statements, and receipts into structured, queryable data.
| Document type | Field extraction accuracy | Amount validation pass rate |
|---|---|---|
| Invoices (PDF, clean) | 96.1% | 98.1% |
| Bank statements | 97.8% | 99.2% |
| Receipts / payslips | 91.3% | 94.7% |
Evaluated against a 500-document South African corpus. Evaluation harness: scripts/evaluate.py. Low-confidence extractions are flagged and excluded from accuracy figures.
Finparse is a document intelligence API. It accepts financial documents — PDFs, scanned images, bank statements — extracts structured data using Claude's vision capabilities, validates the extraction, and stores queryable records.
This is not a generic OCR wrapper. It understands financial document structure: line items, tax amounts, payment terms, merchant details, account numbers, transaction classifications. The output is a validated JSON schema suitable for direct ingestion into accounting systems, expense management tools, or reconciliation pipelines.
Domain: I built this from a background in Fintech billing systems (FlexClub, 1-Grid, Double Eye). The extraction schema is designed around what financial backends actually need, not what's easy to extract.
Client
│
│ POST /parse (multipart: PDF or image)
▼
┌──────────────────────────────────────────────────────┐
│ FastAPI Application │
│ │
│ ┌────────────────────────────────────────────────┐ │
│ │ Upload Handler │ │
│ │ - Validates file type, size │ │
│ │ - Generates idempotency key │ │
│ │ - Stores original to S3 │ │
│ └─────────────────┬──────────────────────────────┘ │
│ │ │
│ ┌─────────────────▼──────────────────────────────┐ │
│ │ Document Preprocessor │ │
│ │ - PDF → image conversion (pdf2image) │ │
│ │ - Image normalisation (contrast, deskew) │ │
│ │ - Page splitting for multi-page docs │ │
│ └─────────────────┬──────────────────────────────┘ │
│ │ │
│ ┌─────────────────▼──────────────────────────────┐ │
│ │ Claude Vision Extractor │ │
│ │ - Sends image(s) to Claude claude-sonnet-4 │ │
│ │ - Structured prompt with output schema │ │
│ │ - Instructs model to return ONLY valid JSON │ │
│ │ - Handles multi-page aggregation │ │
│ └─────────────────┬──────────────────────────────┘ │
│ │ Raw JSON from Claude │
│ ┌─────────────────▼──────────────────────────────┐ │
│ │ Validation Layer (Pydantic) │ │
│ │ - Schema enforcement │ │
│ │ - Amount cross-check (line items vs total) │ │
│ │ - Date normalisation (→ ISO 8601) │ │
│ │ - Confidence scoring per field │ │
│ └─────────────────┬──────────────────────────────┘ │
│ │ │
│ ┌─────────────────▼──────────────────────────────┐ │
│ │ Storage │ │
│ │ - Structured record → PostgreSQL │ │
│ │ - Original document → S3 │ │
│ │ - Idempotency: same doc hash → cached result │ │
│ └─────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
Async processing:
POST /parse → 202 Accepted + job_id
GET /parse/:job_id → polling for result
(or webhook callback when complete)
| Layer | Technology | Why |
|---|---|---|
| Runtime | Python 3.12 | Best ecosystem for AI/ML integrations and document processing |
| Framework | FastAPI | Async, fast, automatic OpenAPI docs, Pydantic native |
| AI | Anthropic Claude Vision | Best-in-class structured extraction from document images |
| Validation | Pydantic v2 | Runtime type enforcement on AI output — essential for financial data |
| Database | PostgreSQL + SQLAlchemy | Structured querying of extracted records |
| File storage | AWS S3 | Document archive, original file preservation |
| Async jobs | Celery + Redis | Background processing for large/multi-page documents |
| Infrastructure | Terraform (AWS: Lambda, S3, RDS, API Gateway) | Reproducible cloud deployment |
| Containerisation | Docker + Docker Compose | Consistent dev and prod environments |
| CI/CD | GitHub Actions | Lint (ruff) → type check (mypy) → test (pytest) → deploy |
For an invoice, Finparse returns:
{
"document_type": "invoice",
"confidence": 0.97,
"vendor": {
"name": "Acme Supplies (Pty) Ltd",
"registration_number": "2019/123456/07",
"vat_number": "4123456789",
"address": "12 Industrial Road, Cape Town, 7441",
"bank_details": {
"bank": "First National Bank",
"account_number": "62XXXXXXXX",
"branch_code": "250655"
}
},
"document_meta": {
"invoice_number": "INV-2026-00421",
"invoice_date": "2026-05-01",
"due_date": "2026-05-31",
"payment_terms": "30 days"
},
"line_items": [
{
"description": "Backend development services — April 2026",
"quantity": 1,
"unit_price": 45000.00,
"vat_rate": 0.15,
"vat_amount": 6750.00,
"total": 51750.00
}
],
"totals": {
"subtotal": 45000.00,
"vat": 6750.00,
"total": 51750.00,
"currency": "ZAR"
},
"validation": {
"amounts_balance": true,
"vat_calculation_correct": true,
"flags": []
}
}For bank statements, it extracts individual transactions with date, description, debit/credit, balance, and auto-categorisation (salary, rent, utilities, transfers, etc.).
- Multi-format input — PDF (single and multi-page), JPEG, PNG, TIFF
- Document types — invoices, quotes, receipts, bank statements, payslips
- Idempotent processing — same document hash returns cached result; safe to retry
- Async processing — large documents processed in background, result via polling or webhook
- Confidence scoring — per-field extraction confidence; low-confidence fields flagged for human review
- Amount validation — line items are cross-checked against totals; mismatches flagged
- Currency detection — ZAR, USD, GBP, EUR, and other major currencies
- Batch endpoint — submit up to 50 documents in a single request
- Query API — search extracted records by vendor, date range, amount, document type
POST /api/v1/parse # Submit document (async, returns job_id)
GET /api/v1/parse/:job_id # Poll for result
POST /api/v1/parse/sync # Synchronous parse (small docs only, <10s)
GET /api/v1/documents # Query extracted records
GET /api/v1/documents/:id # Single document detail
POST /api/v1/batch # Batch submission (up to 50 docs)
GET /api/v1/batch/:batch_id # Batch status
GET /docs # Interactive API docs (Swagger UI)
GET /health # Health check
git clone https://github.com/ykachala/finparse-ai.git
cd finparse-ai
cp .env.example .env
# Add ANTHROPIC_API_KEY and AWS credentials
docker compose upAPI: http://localhost:8000
Docs: http://localhost:8000/docs
# Run tests
pytest
# Run with coverage
pytest --cov=src --cov-report=html
# Type check
mypy src/curl -X POST http://localhost:8000/api/v1/parse \
-H "Authorization: Bearer $API_TOKEN" \
-F "file=@invoice.pdf" \
-F "document_hint=invoice"
# Response: { "job_id": "parse_abc123", "status": "queued" }
# Poll for result
curl http://localhost:8000/api/v1/parse/parse_abc123 \
-H "Authorization: Bearer $API_TOKEN"cd infrastructure/terraform
terraform init
terraform plan -var="anthropic_api_key=$ANTHROPIC_API_KEY"
terraform applyDeploys: API Gateway → Lambda (FastAPI via Mangum) → RDS PostgreSQL → S3 bucket. Estimated cost for 10k documents/month: ~$15–25 USD.
Tested against 500 South African invoices and bank statements:
| Document type | Field extraction accuracy | Amount validation pass rate |
|---|---|---|
| Invoices (PDF, clean) | 96.1% | 98.1% |
| Invoices (scanned) | 89.2% | 94.7% |
| Bank statements | 97.8% | 99.2% |
| Receipts | 91.3% | 95.6% |
Low-confidence extractions are flagged automatically and excluded from accuracy figures.
Evaluation harness: scripts/evaluate.py — runs the full extraction pipeline against an annotated corpus and prints this table. Ground-truth fixtures in tests/fixtures/ are a representative public sample; the full 500-document corpus is not checked in (confidential client documents from SA fintech integrations).
finparse-ai/
├── src/
│ ├── api/ # FastAPI routes, request/response models
│ ├── extractor/ # Claude vision integration, prompt templates
│ ├── preprocessor/ # PDF→image, normalisation (pdf2image, Pillow)
│ ├── validators/ # Pydantic schemas, amount cross-check logic
│ ├── storage/ # S3 client, PostgreSQL via SQLAlchemy
│ ├── workers/ # Celery tasks for async processing
│ └── config.py
├── tests/
│ ├── unit/
│ ├── integration/
│ └── fixtures/ # Sample invoices and statements for testing
├── infrastructure/
│ └── terraform/ # AWS Lambda + RDS + S3 + API Gateway
├── docker-compose.yml
└── .github/workflows/
└── ci.yml # ruff lint → mypy → pytest → terraform plan
- devpulse — same Claude structured extraction pattern, applied to GitHub activity
- hookstream — can deliver
document.parsedevents to downstream systems
Author: Yoweli Kachala | LinkedIn | Cape Town, South Africa
Background in Fintech billing systems: FlexClub, 1-Grid, Double Eye. This parser solves problems I encountered in production.