This prompt is designed for fintech platform engineers who receive unstructured or semi-structured transaction data from upstream systems—OCR pipelines, PDF parsers, or other models—that failed to produce valid, typed JSON. Its job is to convert that narrative text into a clean, predictable array of transaction records. The output contract includes normalized dates, a consistent debit-credit sign convention, a category classification, and a verified running balance. The primary goal is to repair malformed data before it enters a ledger, reconciliation engine, or compliance database, preventing downstream processing failures.
Prompt
Bank Statement Text to Transaction Records Prompt Template

When to Use This Prompt
Understand the job-to-be-done, ideal user, and critical boundaries for the bank statement repair prompt.
Use this prompt when you have a batch of bank statement text that needs to be ingested into a structured system but cannot be parsed by a deterministic script. It is ideal for scenarios where the source text has a consistent narrative pattern but lacks a machine-readable schema. The prompt's strict output schema and built-in verification logic (like running balance checks) make it a powerful post-extraction repair tool. However, you should not use this prompt for real-time payment processing, fraud detection, or any workflow where a hallucinated transaction could trigger an irreversible financial action without a human in the loop. It is a repair and normalization tool, not a real-time decision engine.
Before integrating this prompt, ensure you have a clear understanding of the expected input format and the downstream system's schema requirements. The prompt template uses placeholders like [INPUT] and [OUTPUT_SCHEMA] that you must populate with your specific data and contract. The next section provides the copy-ready template. After adapting it, you must build a robust implementation harness—including output validation, retry logic, and human review for high-value or high-risk transactions—as described in the 'Implementation Harness' section. Never deploy this prompt directly to production without automated checks that verify the mathematical consistency of the output.
Use Case Fit
This prompt template converts unstructured bank statement text into typed transaction records. It is designed for fintech pipelines that need consistent debit-credit sign handling and running balance verification before records enter a ledger or reconciliation system.
Good Fit: Clean OCR Text from Single Accounts
Use when: you have machine-readable text from a single bank statement with clear transaction lines, dates, and amounts. Guardrail: The prompt expects one account context per run. Batch processing should split statements by account first.
Bad Fit: Multi-Currency or Scanned Handwriting
Avoid when: statements contain mixed currencies without ISO codes, or the source is low-confidence handwriting OCR. Guardrail: Currency normalization and handwriting disambiguation require upstream preprocessing. This prompt assumes legible, single-currency input.
Required Inputs: Statement Text and Date Range
What to watch: The prompt needs the full statement text and an expected statement period. Without a date range, the model cannot validate whether transactions fall within the statement window. Guardrail: Always pass [STATEMENT_TEXT] and [STATEMENT_START_DATE] / [STATEMENT_END_DATE] as explicit inputs.
Operational Risk: Running Balance Drift
What to watch: A single misread transaction amount can cause the running balance to drift across all subsequent records, making the entire output unreliable for reconciliation. Guardrail: Implement a post-processing harness that recalculates the running balance from the first transaction and flags any row where the model's balance differs from the computed balance by more than a configurable tolerance.
Operational Risk: Debit-Credit Sign Inversion
What to watch: The model may misinterpret whether a transaction is a debit or credit, especially when statement formatting is ambiguous (e.g., parentheses for credits). Guardrail: Add a harness check that verifies the sign of each transaction amount matches the transaction type (debit/credit) and the direction of the running balance change. Flag inconsistencies for human review.
Not a Replacement for Bank APIs
What to watch: Teams may treat this prompt as a substitute for direct bank data feeds or OFX/CSV exports. Guardrail: This prompt is a repair and normalization tool for unstructured text, not a primary data ingestion path. Always prefer structured bank feeds when available. Use this only when statements arrive as unstructured text that cannot be obtained in machine-readable format.
Copy-Ready Prompt Template
A reusable prompt template with square-bracket placeholders for converting bank statement text into structured, validated transaction records.
This prompt template is designed to be copied directly into your application's prompt layer. It instructs the model to parse raw bank statement text and output a clean JSON array of transaction records. The template uses square-bracket placeholders for all dynamic inputs, constraints, and schemas, making it easy to wire into a production harness where these values are populated at runtime. The core instruction enforces strict output formatting, field-level type discipline, and a critical running-balance verification step that catches many common extraction errors before the data enters your ledger.
textYou are a precise financial data extraction engine. Your task is to convert the provided bank statement text into a structured JSON array of transaction records. ## Input [INPUT] ## Output Schema Return ONLY a valid JSON array of objects. Each object must conform to this exact schema: [OUTPUT_SCHEMA] ## Constraints [CONSTRAINTS] ## Examples [EXAMPLES] ## Critical Verification Step Before outputting the final JSON, perform this check internally: 1. For each transaction, calculate the expected running balance by applying the transaction amount to the previous running balance. 2. Compare your calculated running balance to the running balance stated in the bank statement text for that transaction. 3. If there is a mismatch, flag the transaction by setting the `"balance_verified"` field to `false` and include the `"calculated_balance"` in the output. 4. If the stated running balance is missing from the source text, set `"balance_verified"` to `null`. ## Risk Level [RISK_LEVEL] ## Tools [TOOLS]
To adapt this template, replace each square-bracket placeholder with the concrete values for your specific bank statement format and application requirements. The [OUTPUT_SCHEMA] should be a detailed JSON schema defining fields like transaction_date (ISO 8601 string), description (string), amount (number, positive for credits, negative for debits), category (string or null), and running_balance (number or null). The [CONSTRAINTS] placeholder is where you enforce rules like 'debit amounts must be negative' or 'dates must be parsed from MM/DD/YYYY format.' The [RISK_LEVEL] placeholder should be set to high for financial data, which signals your harness to enable additional validation, logging, and human review gates. After copying this template, the next step is to build the implementation harness that populates these placeholders and validates the model's output against your schema before it touches any financial system of record.
Prompt Variables
Required and optional inputs for the Bank Statement Text to Transaction Records prompt. Each placeholder must be populated before the prompt is assembled and sent to the model.
| Placeholder | Purpose | Example | Validation Notes |
|---|---|---|---|
[BANK_STATEMENT_TEXT] | Raw OCR or copy-pasted text from a bank statement containing transaction lines, dates, amounts, and running balances | 01/15/2025 DEBIT CARD PURCHASE AMAZON.COM $42.97 Balance $1,203.45 | Must contain at least one transaction-like line. Reject empty strings or text with no numeric amounts. Minimum 20 characters. |
[STATEMENT_DATE_RANGE] | Expected date range for the statement period to help the model disambiguate transaction dates from other numbers | 2025-01-01 to 2025-01-31 | Must be two ISO-format dates separated by 'to'. Validate both dates parse correctly. Null allowed if statement text contains explicit period header. |
[ACCOUNT_CURRENCY] | ISO 4217 currency code for the account to normalize amount fields and detect currency symbols in text | USD | Must match /^[A-Z]{3}$/. Validate against known currency code list. Default to USD if null but log warning. |
[EXPECTED_TRANSACTION_COUNT] | Approximate number of transactions expected to detect truncation or major extraction failures | 47 | Must be a positive integer. Used for output count sanity check, not strict equality. Null allowed for variable-length statements. |
[CATEGORY_TAXONOMY] | List of valid transaction categories for the model to classify each record into | ["Groceries", "Utilities", "Dining", "Transfer", "Fee", "Income", "Shopping", "Uncategorized"] | Must be a JSON array of strings. Validate array is non-empty. Each category must be unique. Model output categories must match this list exactly or map to 'Uncategorized'. |
[OUTPUT_SCHEMA] | JSON schema definition the model must conform to for each transaction record | {"type": "object", "properties": {"date": {"type": "string"}, "description": {"type": "string"}, "amount": {"type": "number"}, "type": {"enum": ["debit", "credit"]}, "category": {"type": "string"}, "running_balance": {"type": "number"}}, "required": ["date", "description", "amount", "type", "running_balance"]} | Must be valid JSON Schema draft-07 or later. Validate with a JSON Schema validator before prompt assembly. Required fields must include date, description, amount, type, and running_balance at minimum. |
[RUNNING_BALANCE_CHECK] | Boolean flag enabling post-extraction arithmetic verification of running balance consistency | Must be true or false. When true, harness runs sequential balance verification: balance[i] + debit[i+1] or balance[i] - credit[i+1] must equal balance[i+1] within tolerance. Log failures as warnings, not hard errors. | |
[DEBIT_CREDIT_SIGN_CONVENTION] | Specifies whether debits are positive or negative in the source text to ensure sign consistency in output | debits_positive | Must be one of: debits_positive, debits_negative, inferred. When 'inferred', model determines convention from text. Harness validates all debit amounts have same sign and all credit amounts have opposite sign. |
Implementation Harness Notes
How to wire the bank statement extraction prompt into a reliable production pipeline with validation, retries, and audit trails.
This prompt is designed to be called as part of a structured extraction pipeline, not as a standalone chat interaction. The typical flow is: raw bank statement text enters the system, the prompt converts it into a typed transaction array, and a post-processing harness validates the output before it reaches any database or downstream system. Because financial data is high-risk, the harness must enforce debit-credit sign consistency, running balance verification, and required field presence before accepting any record.
Model choice and invocation pattern: Use a model with strong JSON mode or structured output support (e.g., GPT-4o with response_format: { type: 'json_object' }, Claude with tool-use extraction, or Gemini with controlled generation). Always set temperature=0 to minimize variance in numeric fields. Call the prompt with the raw statement text injected into the [STATEMENT_TEXT] placeholder. If the statement exceeds the model's context window, chunk it by statement page or month boundary and merge results in the application layer, checking for duplicate transactions across chunks by matching date, description, and amount within a small tolerance.
Validation and retry logic: After receiving the model response, run a multi-step validator: (1) confirm the output is valid JSON with a transactions array, (2) verify every record has non-null date, description, and amount fields, (3) check that debit and credit values are mutually exclusive per record (one must be zero or null when the other is populated), (4) recalculate the running balance from the first transaction forward and compare against the model's running_balance field with a tolerance of ±0.01, and (5) flag any transaction where the sign of the net change doesn't match the direction of the balance movement. If validation fails, construct a repair prompt that includes the original statement text, the failed output, and the specific validation errors, then retry once. If the retry also fails, route the record to a human review queue with the raw statement, the failed extraction, and the validator error log.
Logging and audit trail: Log every extraction attempt—including the raw input, the model's raw output, validation results, and any retry attempts—to an append-only audit store. This is critical for fintech compliance and debugging. Include a pipeline_run_id and transaction_batch_id in every log entry so you can trace a single statement through extraction, validation, repair, and eventual ingestion. Never silently drop failed records; even rejected extractions should leave an audit artifact explaining why they were rejected.
Integration with downstream systems: Once a transaction batch passes validation, transform the records into your canonical transaction schema before writing to the ledger or database. Map the prompt's category field to your internal chart of accounts using a lookup table or a secondary classification prompt if the model's category doesn't match your taxonomy. For running balance verification, treat the model's running_balance as a cross-check against your system of record—never as the authoritative balance. The authoritative balance must come from the bank's official statement or API, with the extracted balance serving only as a reconciliation signal.
What to avoid: Do not use this prompt for real-time transaction processing or payment initiation. Do not skip the running balance verification step, even if the model appears confident—arithmetic errors are common in long transaction sequences. Do not store raw bank statement text in logs without redacting account numbers and PII first. And do not treat a passing validation as proof of correctness; sampled human review of extracted transactions should be part of your regular quality assurance cadence, especially for high-value or unusual transactions.
Expected Output Contract
Defines the required fields, types, and validation rules for each transaction record extracted from bank statement text. Use this contract to build downstream parsers, database schemas, and validation harnesses.
| Field or Element | Type or Format | Required | Validation Rule |
|---|---|---|---|
transaction_date | string (ISO 8601 date) | Must parse to a valid date. Reject if month > 12 or day > 31. Normalize to YYYY-MM-DD format. | |
description | string | Must not be empty or whitespace-only. Length must be between 1 and 500 characters. Trim leading/trailing whitespace. | |
amount | number (decimal) | Must be a valid decimal number with up to 2 decimal places. Must not be zero. Sign must be consistent with [TRANSACTION_TYPE]. | |
transaction_type | string (enum) | Must be exactly 'debit' or 'credit'. Validate that debit amounts are negative and credit amounts are positive per [SIGN_CONVENTION]. | |
running_balance | number (decimal) or null | If present, must be a valid decimal. If [VERIFY_RUNNING_BALANCE] is true, validate that balance change equals transaction amount within 0.01 tolerance. | |
category | string or null | If present, must match one of the allowed values in [CATEGORY_LIST]. Null is allowed when category cannot be determined from description. | |
check_number | string or null | If present, must be a non-empty string. If extracted from description, verify it matches the pattern defined in [CHECK_NUMBER_PATTERN]. | |
source_text | string | Must contain the exact substring from [INPUT_TEXT] that produced this record. Used for audit trail and human review. Must not be empty. |
Common Failure Modes
Production failures when converting bank statement text to transaction records, and how to prevent them before they corrupt your ledger.
Debit-Credit Sign Inconsistency
What to watch: The model flips the sign on transactions—credits become debits or vice versa—especially when the statement uses ambiguous language like 'payment received' or 'withdrawal.' A single sign error can cascade into balance mismatches across the entire statement. Guardrail: Add a post-extraction harness check that verifies ending_balance = starting_balance + sum(credits) - sum(debits) for every statement. Flag any row where the running balance delta doesn't match the transaction amount sign.
Running Balance Drift
What to watch: The model extracts individual transactions correctly but the computed running balance diverges from the statement's printed running balance after several rows. This often happens when the model misses a transaction, duplicates one, or misaligns the balance column with the wrong row. Guardrail: Implement a row-by-row balance reconciliation check. After extracting all transactions, recompute the running balance from the first row and compare against the extracted balance at each step. Escalate any row where the delta exceeds $0.01 for human review.
Date Format Ambiguity
What to watch: The model misinterprets date formats—confusing MM/DD/YYYY with DD/MM/YYYY—or fails to parse relative dates like 'yesterday' or 'last Tuesday.' This is especially dangerous for statements crossing month boundaries or from international banks. Guardrail: Require the prompt to output dates in ISO 8601 format only. Add a validator that rejects any date not matching YYYY-MM-DD and flags dates that are in the future or more than 90 days in the past relative to the statement period.
Category Hallucination
What to watch: The model invents transaction categories that don't appear in the statement text—like labeling a generic 'ACH CREDIT' as 'Payroll' or 'Refund' without evidence. This contaminates downstream financial reporting and reconciliation. Guardrail: Constrain the prompt to only assign categories when the statement explicitly provides them. For uncategorized transactions, output null or "uncategorized" rather than inferring. Add a post-extraction check that flags any category value not present in the source text.
Multi-Line Transaction Fragmentation
What to watch: A single transaction split across multiple lines in the statement—common with detailed descriptions or multi-part entries—gets extracted as two separate transactions, inflating the record count and breaking balance calculations. Guardrail: Include few-shot examples in the prompt showing multi-line transactions merged into single records. Add a deduplication pass that merges adjacent rows sharing the same date and amount but with continuation descriptions, using the statement's line spacing or indentation as merge signals.
Currency Symbol and Amount Parsing
What to watch: The model misparses amounts containing currency symbols, thousand separators, or parentheses for negative values—turning ($1,234.56) into a positive number or dropping the decimal. This silently corrupts every downstream calculation. Guardrail: Enforce a strict numeric output format in the prompt: amounts must be decimal numbers with exactly two decimal places, no currency symbols, no thousand separators, and negative values must use a leading minus sign. Add a regex validator that rejects any amount field not matching ^-?\d+\.\d{2}$.
Evaluation Rubric
Use this rubric to test the quality of structured transaction records generated from bank statement text before shipping to production. Each criterion includes a pass standard, a failure signal, and a concrete test method.
| Criterion | Pass Standard | Failure Signal | Test Method |
|---|---|---|---|
Field Completeness | All required fields (date, description, amount, category, running_balance) are present and non-null for every transaction | Missing fields or null values in required fields for any transaction record | Schema validation: parse output JSON and assert all required keys exist and are not null for each record in the array |
Date Format Consistency | All date fields conform to ISO 8601 format (YYYY-MM-DD) and are parseable | Non-standard date formats, ambiguous dates (e.g., 01/02/2024), or unparseable strings | Regex pattern match against ^\d{4}-\d{2}-\d{2}$ for every date field; attempt Date.parse() and assert no NaN |
Debit-Credit Sign Consistency | Debit transactions have negative amounts, credit transactions have positive amounts, and sign matches the transaction type description | Positive amount for a debit transaction or negative amount for a credit transaction; sign contradicts description | For each record, check if description contains debit/credit keywords; assert amount sign matches expected direction; flag mismatches |
Running Balance Arithmetic | Each running_balance equals the previous running_balance plus the current transaction amount within a tolerance of 0.01 | Running balance drifts from expected value; cumulative sum of amounts does not reconcile with stated running balance | Iterate through sorted records; compute expected_balance = prior_balance + amount; assert abs(expected_balance - running_balance) < 0.01 for each record |
Category Assignment Validity | Every category field contains a value from the allowed enum: [INCOME, TRANSFER, PAYMENT, FEE, INTEREST, OTHER] | Category contains free-text, misspelled, or out-of-enum values; category is null or empty string | Assert category value is in the allowed enum set for every record; reject any record with non-matching category |
Amount Precision | All amount fields are numeric with exactly two decimal places and no currency symbols or commas | Amounts contain currency symbols ($, €), thousand separators, or more than two decimal places | Parse each amount as float; assert no NaN; assert amount.toFixed(2) equals original string representation after stripping non-numeric chars except decimal point |
Record Count Preservation | Number of output transaction records matches the number of transactions identifiable in the source text | Output contains fewer or more records than transactions present in the input statement text | Manual count of transactions in source text vs output array length; automated check: assert output.length equals expected count from ground truth or source parsing |
Description Fidelity | Description field contains the original transaction description from the source text without hallucinated additions | Description contains merchant names, locations, or details not present in the source text; description is truncated or rewritten | String similarity check between source text segments and output descriptions; flag records where edit distance exceeds threshold or contains tokens absent from source |
Enabling Efficiency, Speed & Accuracy
Intelligent Analysis, Decision & Execution
We build AI systems for teams that need search across company data, workflow automation across tools, or AI features inside products and internal software.
Talk to Us
Search across company data
Give teams answers from docs, tickets, runbooks, and product data with sources and permissions.
Useful when people spend too long searching or get different answers from different systems.

Automate internal workflows
Use AI to route work, draft outputs, trigger actions, and keep approvals and logs in place.
Useful when repetitive work moves across multiple tools and teams.

Add AI to products and internal tools
Build assistants, guided actions, or decision support into the software your team or customers already use.
Useful when AI needs to be part of the product, not a separate tool.
Adapt This Prompt
How to adapt
Use the base prompt with a frontier model (GPT-4o, Claude 3.5 Sonnet) and minimal post-processing. Focus on getting the core extraction working before adding validation layers. Remove the running balance verification step initially—add it once date parsing and amount sign conventions are stable.
Prompt snippet
codeExtract transactions from [BANK_STATEMENT_TEXT] as JSON. Fields: date, description, amount, category, running_balance.
Watch for
- Debit/credit sign inconsistency (deposits as negative, withdrawals as positive)
- Date format drift across statement pages
- Category hallucination when statement doesn't provide categories
- Running balance not matching sequential transaction math

About the author
Prasad Kumkar
CEO & MD, Inference Systems
Prasad Kumkar is the CEO & MD of Inference Systems and writes about AI systems architecture, LLM infrastructure, model serving, evaluation, and production deployment. Over 5+ years, he has worked across computer vision models, L5 autonomous vehicle systems, and LLM research, with a focus on taking complex AI ideas into real-world engineering systems.
His work and writing cover AI systems, large language models, AI agents, multimodal systems, autonomous systems, inference optimization, RAG, evaluation, and production AI engineering.
Partnered with leading AI, data, and software stack.
How We Work
Custom AI workflows for your Business
One-fit-all AI don't work for modern businesses. At Inferensys, we aim to understand your business & custom requirements; which we use to define most efficient agentic workflows, the data, and the tools for your business.
01
Review the use case
We understand the task, the users, and where AI can actually help.
Read more02
Pick the right approach
We define what needs search, automation, or product integration.
Read more03
Build the first useful version
We implement the part that proves the value first.
Read more04
Improve from there
We add the checks and visibility needed to keep it useful.
Read moreThe first call is a practical review of your use case and the right next step.
Talk to Us