Benchmarks: Answer 99.16% of DocVQA Without Images in QA: Agentic Document ExtractionRead more

Immigration Financial Audits in 60 seconds with LandingAI + Bedrock

Parfait Tedom Tedom

Parfait Tedom Tedom

Share On :
Immigration Financial Audits in 60 seconds with LandingAI + BedrockImmigration Financial Audits in 60 seconds with LandingAI + Bedrock

TL;DR

Canadian immigration officers manually review 6 months of bank statements per applicant. That process takes 2 to 4 hours and must apply different rules across 10 distinct IRCC programs. Openomi compresses it to about 60 seconds by chaining LandingAI Agentic Document Extraction for structured document extraction with an AWS Bedrock Agent running Claude 3.5 Sonnet for compliance reasoning and fraud detection. Before each audit begins, the agent queries a RAG knowledge base for the exact fund thresholds and statement history requirements tied to the applicant's specific program, so FSW-EE rules apply to FSW-EE applications and Quebec rules apply to Quebec applications, never crossed. IRCC processed more than 7 million decisions in 2024 (IRCC Departmental Results Report, 2025) while investigating about 9,000 suspected fraud cases per month, and document fraud, particularly in bank statements, is rising.

The Daemon Craft team built and shipped the full working system, which has since grown into a production SaaS platform at openomi.io, now live and serving Regulated Canadian Immigration Consultants (RCICs) across Canada and immigration candidates worldwide. You can explore the source code on GitHub and see the core extraction workflow run end to end in the demo video.

The Problem: Manual Financial Audits Don't Scale Across Programs

IRCC processed more than 7 million decisions across all immigration streams in 2024, while investigating approximately 9,000 suspected fraud cases per month (IRCC Visa Integrity briefing, March 2025). Visitor visa refusals for misrepresentation rose 251% in 2024 compared to 2023. The forgery problem is getting worse, not better: template-based document fraud rose 49.8% from 2023 to 2024, and bank statements account for 59% of all fraudulent documents detected by AI fraud systems (Inscribe AI 2025 Document Fraud Report).

For any automated system, the hard part is not volume. It is staying consistent across programs that follow very different rules:

  • Federal Skilled Worker (FSW-EE): Minimum CAD $15,263 for a single applicant, 6 months of consecutive statements required, any single deposit over $5,000 within 60 days without documentation triggers rejection
  • Canadian Experience Class (CEC-EE): No proof of funds required at all, so flagging a CEC applicant for missing bank statements is a false rejection
  • Quebec Skilled Worker (QSW-ARRIMA): Only CAD $3,462 minimum for a single applicant, only 3 months of statements required, documents must be in French or accompanied by translation
  • Family Sponsorship: No proof of funds for the applicant. It is the sponsor's income that gets audited, under a completely different framework

Mixing these rulesets produces incorrect verdicts. An automated system must know which ruleset applies before it checks anything.

Architecture: Three Layers, One Workflow

This walkthrough covers the open-source build in the GitHub repository, the foundation the production platform grew from. That build splits the work into three concerns:

  1. Document intelligence: LandingAI ADE extracts structured JSON from uploaded PDFs and images
  2. Compliance reasoning: AWS Bedrock Agent (Claude 3.5 Sonnet) queries program-specific rules from a RAG knowledge base, then applies fraud detection logic across all extracted documents
  3. Orchestration and UI: Streamlit frontend handles program selection, file upload, and report rendering; Amazon S3 stores documents between the UI and the Lambda extraction tool

LandingAI Agentic Document Extraction does not do the reasoning; it handles extraction. The Bedrock Agent does not parse documents; it calls the Lambda tool that wraps Agentic Document Extraction. Each layer has one job.

Document Extraction with Agentic Document Extraction

The extraction pipeline in src/openomi_logic.py runs two steps for every uploaded file:

# Step 1: Parse document to markdown\
parse_response = ade_client.parse(
    document_url=str(local_file_path),
    model="dpt-2-latest"
)


# Step 2: Extract structured JSON from markdown
json_data = ade_client.extract(
    schema=SCHEMA_JSON,
    markdown=parse_response.markdown,
    model="extract-latest"
)

The parse step (dpt-2-latest) converts a PDF or image to markdown, handling multi-column layouts, handwritten annotations, bank stamps, and non-standard formatting. The extract step (extract-latest) maps the markdown to a typed Pydantic schema:

class Transaction(BaseModel):
    date: str
    description: str
    amount: float  # negative for withdrawals\


class BankStatementSchema(BaseModel):
    account_holder: str
    open_balance: float
    ending_balance: float
    currency: str
    transactions: list[Transaction]

The schema is the contract between ADE and the Bedrock Agent. The agent does not receive raw text. It gets a clean, typed JSON object it can reason over directly.

This separation matters for real documents. Bank statements vary a lot across institutions. Some use three-column formats, others embed transaction tables in image layers, and some include branch stamps that overlap text. The parse model (dpt-2-latest) is built for layout understanding. The extract model (extract-latest) is built for schema-aligned field extraction. Separating the steps lets each model focus on what it does best.

(Rendered from the inline Markdoc SVG chart in the source file; exported as a static PNG for this package.)

Wiring LandingAI ADE as a Bedrock Agent Action Group

The Lambda function in src/openomi_logic.py connects the Bedrock Agent to LandingAI ADE. AWS Bedrock's Action Group pattern lets you expose any callable as a tool the agent can invoke mid-reasoning. The connection is declared via an OpenAPI schema (openapi_schema.json) rather than custom routing code, so the agent understands the tool's interface declaratively.

The SAM deployment in template.yaml configures the Lambda:

OpenomiExtractionToolFunction
   Type: AWS::Serverless::Function  
   Properties:    
      Handler: openomi_logic.lambda_handler    
      Runtime: python3.11    
      MemorySize: 2048    
      Timeout: 600    
      Layers:      
        - !Ref OpenomiDependenciesLayer    
      Environment:      
         Variables:        
            S3_UPLOADS_BUCKET: !Ref UploadBucketName        
            VISION_AGENT_API_KEY: !Ref LandingAIApiKey

The 2048MB memory allocation and 600-second timeout reflect real document processing requirements. Multi-page bank statement PDFs are large, and ADE's parse step handles layout complexity that should not be rushed. The Lambda Layer bundles landingai-ade, pydantic, and boto3 separately from the function code, keeping deployment packages small.

When the Bedrock Agent decides to extract a document, it calls /extract_document with a file_key, the S3 object key for a previously uploaded file. The Lambda downloads the file, runs the two-step ADE pipeline, and returns structured JSON. The agent repeats this call for every statement in the batch, then aggregates balances and transaction histories before starting compliance analysis.

Program-Specific Compliance via RAG

The most important design decision in Openomi is not document extraction. It is keeping compliance rules out of the agent's system prompt.

The agent's instructions tell it to query the RAG knowledge base for three specific things at the start of every audit:

Query 1: "What are the financial requirements for [Program Code] with family size [X]?"
Query 2: "What are the high-priority red flags for [Program Code]?"
Query 3: "What are acceptable sources of funds for [Program Code]?"

The knowledge base (ircc-all-programs-financial-requirements.md) holds the actual IRCC program rules. When IRCC updates fund thresholds, which happens by regulatory cycle rather than by product roadmap, the knowledge base document gets updated. Nothing else changes.

The anti-pattern is hardcoding thresholds in the system prompt. When "$15,263 for FSW-EE single applicant" is baked into the agent's instructions, a regulatory change requires a code change and a redeployment. In a RAG-backed setup, it is a document update. For any compliance system where rules are externally governed, this separation is not optional.

The fund thresholds vary widely across programs, which is why the RAG lookup runs before any document is analyzed:

ProgramMinimum Funds (Single Applicant)Statement History
FSW-EECAD $15,2636 months consecutive
FST-EECAD $15,2636 months consecutive
QSW-ARRIMACAD $3,4623 months
CEC-EENone requiredN/A
Family SponsorshipNone (sponsor audited)N/A
PNPProvince-specificVaries

Source: IRCC program requirements, 2024-2025.

What Openomi Produces

The Streamlit frontend runs a three-phase workflow: program and family size selection, bank statement upload (PDFs and images), and AI analysis via Bedrock Agent. The upload phase pushes files directly to Amazon S3 via boto3. The analysis phase invokes the Bedrock Agent with a prompt that includes the program code, family size, and the S3 keys of every uploaded document.

The agent generates a structured markdown audit report with five sections:

  • Executive Summary: APPROVED / NEEDS REVIEW / REJECTED verdict, risk level, and a one-line decision rationale for the reviewing officer
  • Financial Overview: total funds available, compliance status against the program's minimum, statement history length check, and per-statement balance summary
  • Red Flags Detected: tiered HIGH / MEDIUM / LOW flags, each with the specific evidence that triggered it (for example, a single deposit over $5,000 within 60 days, or income inconsistencies across statements)
  • Compliance Check: tabular pass/fail against every program-specific requirement
  • Fraud Analysis: document authenticity assessment, suspicious deposit pattern detection, borrowed funds indicators, and AI confidence score

The UI parses the verdict from the agent's response and renders a color-coded banner. Red flag count is extracted from the report text. Results export as JSON or plain text for downstream use.

From Demo to Production Platform

The system described above is the build you can run from the GitHub repository. Since then, the Daemon Craft team has grown Openomi into a full production SaaS platform at openomi.io, now live and serving Regulated Canadian Immigration Consultants (RCICs) across Canada and immigration candidates worldwide.

The production platform extends well beyond the original Streamlit demo:

  • AI document audits: the bank statement audit described here, now one of five distinct document audit types
  • CRM with Kanban pipeline: case and client management for immigration consultants
  • Test preparation: TCF Canada and IELTS prep with AI grading
  • IRCC form filling: automated completion of IRCC forms
  • Bilingual expert chat: immigration guidance in English and French
  • Built-in IRCC phone calls: in-platform calling

The AI stack scaled with it. Openomi now uses Google Gemini as a reasoning and grounding model alongside AWS Bedrock, Claude-powered services, and LangChain agents for specialized tasks and workflow orchestration. The architecture has expanded, but the LandingAI ADE extraction pipeline described in this article remains the core engine for processing immigration documents.

Three Lessons for Builders

1. Separate parsing from extraction.

LandingAI ADE's two-model flow, parse() with dpt-2-latest then extract() with extract-latest, maps onto two distinct problems. The parse model handles layout understanding: varied column formats, handwriting, stamps, image-embedded tables. The extract model handles semantic mapping: reading markdown content and populating typed fields from a Pydantic schema. Combining both into a single prompt asks one model to solve two very different problems at once. The split produces more reliable results on real documents.

2. Keep compliance rules in the knowledge base, not the system prompt.

IRCC program rules change by regulatory cycle. Any threshold, requirement, or exception that an external authority controls should live in a retrievable document, not hardcoded into agent instructions. The agent's system prompt defines how to audit; the knowledge base defines what to audit against. This pattern applies to any compliance domain where rules are externally governed and subject to change.

3. Lambda plus an OpenAPI schema is the cleanest pattern for Bedrock Agent tool calls.

Declaring the extraction tool through openapi_schema.json rather than custom routing code means the agent understands the tool's interface declaratively. Adding a second tool, say a currency conversion API, a sanctions list lookup, or a payslip extractor, is an OpenAPI schema addition and a new Lambda handler. The agent orchestration layer does not change.

Frequently Asked Questions

Can Openomi's extraction be adapted to other document types beyond bank statements?

Yes. The extraction schema is the only component tied to bank statements. Replacing BankStatementSchema with a PaystubSchema or TaxReturnSchema and updating the Pydantic model is the only required change in the Lambda function. The Bedrock Agent, RAG knowledge base, and Streamlit frontend all stay the same.

What are the current limitations of Openomi's verdict parsing?

The verdict (APPROVED, NEEDS REVIEW, or REJECTED) is parsed from the agent's response using string matching on the output text. When the agent's phrasing varies from expected patterns, this can misclassify. A better approach would be to have the agent return a structured JSON object with a dedicated verdict field alongside the markdown narrative, removing the dependency on text pattern matching entirely.

Why use AWS Bedrock Agent instead of calling Claude directly via the Anthropic API?

Bedrock Agent manages multi-step tool orchestration natively: it decides which tools to call, in what order, and how to aggregate results across multiple documents. Calling Claude directly via the Anthropic API would mean writing that orchestration loop manually: managing tool call and response cycles, tracking multi-document state, and routing between extraction and reasoning passes. For a workflow where the number of uploaded documents varies per applicant, the Bedrock Agent Action Group pattern is much simpler to build and maintain.