Skip to main content

docfig

Check bank statement transaction tables for reconciliation errors, offline and free. Convert statement PDFs to checked JSON, Excel and CSV with the DocFig API.

pip install docfig            # add [excel] to read .xlsx files: pip install "docfig[excel]"

Free reconciliation check

Scraped or exported bank statements often have corrupted tables: a debit in the credit column, a dropped row, a row copied twice, a misread amount. docfig check finds them. No API key, no network, no cost.

docfig check statement.csv
docfig check statement.csv --opening 2841.17 --closing 11023.40
docfig check statement.csv --json      # for scripts and CI
docfig check: statement.csv
  27 rows, 26 balance checks. Passed: 24, flagged: 3.
  Opening 2841.17 (inferred), closing 11023.40 (inferred). Money in 11501.94, money out 3434.66.

  3 problems:
  - [row 9] sign_error: Row 9: 150.88 is in the wrong column; the balance says it is a debit.
    Fix: Move 150.88 to the debit column.
  - [row 15] duplicate: Row 15 repeats row 14: same date, description, amount and balance.
    Fix: Delete row 15 if it was copied or exported twice.
  - [row 20] amount_typo: Row 20: the balance says this amount should be -180.80, not -18.08 (a zero looks dropped or added).
    Fix: Amount 18.08 likely 180.80.

Starting from PDFs? docfig.com/api

What it checks, row by row:

  • Running balance: every balance must equal the previous balance plus the rows in between (in integer cents, so 0.1 + 0.2 never fails). Oldest-first or newest-first order is detected from the balances.
  • Swapped debit/credit columns for the whole file, and sign errors or figures in the wrong column on single rows.
  • Mistyped amounts: "amount 125.00 likely 1,250.00" (a dropped zero, a misplaced decimal point, two swapped digits, one misread digit).
  • Missing rows: a gap in the balance chain, with the amount that is missing and where.
  • Duplicated rows, dates out of order (including day and month swapped), totals against --opening and --closing.

It reads what real exports look like: headers such as Date / Narration / Withdrawal Amt. / Deposit Amt. / Closing Balance, a signed Amount column or separate Debit and Credit columns, a Dr/Cr column, CR/DR suffixes, (1,234.56) negatives, £-12.50, decimal commas (1.234,56), Indian lakh grouping (1,23,456.78), ; or tab delimiters, preamble lines above the header, balance brought forward lines, and dates as 2026-03-31, 31/03/2026, 03/31/2026, 31.03.2026, 31-Mar-26 or Mar 31, 2026. A credit card table, where the balance is the amount owed, takes --type card.

Exit codes: 0 clean, 1 problems found, 2 the file could not be read as a transactions table. The same logic powers the checks on docfig.com, and the Node package (npm install docfig-api) gives identical results.

From Python:

import docfig

report = docfig.check_file("statement.csv", opening="2841.17")
print(report["status"], report["flagged"])
for p in report["problems"]:
    print(p["line"], p["kind"], p["message"], p["fix"])
print(docfig.format_report(report))

Convert statement PDFs (DocFig API)

Get a free key at docfig.com/api (email code, no card): 100 pages a month. Text PDFs, scanned PDFs, password-protected PDFs and photos (JPG, PNG, HEIC).

import docfig

client = docfig.Client()                      # reads DOCFIG_API_KEY
st = client.convert("statement.pdf")          # upload, wait, return the result
print(st.bank, st.account["last4"], st.period)
print(st.checks["status"], st.checks["rows_flagged"])
for t in st.transactions:
    print(t["date"], t["description"], t["amount"], t["balance"], t["flags"])
st.download("statement.xlsx")                 # the same workbook as the website, or .csv

locked = client.convert("locked.pdf", password="1234")

combined = client.combine(["jan.pdf", "feb.pdf", "apr.pdf"])
for p in combined.problems:
    print(p["kind"], p["text"])               # "Missing statement: 1 Mar 2026 to 31 Mar 2026 ..."
combined.download("all-statements.xlsx")

print(client.usage())                         # pages used and left this month

client.upload(file) returns at once; client.get(id), client.wait(id), client.download(id, "csv") and client.delete(id) work with the id. Results are deleted from DocFig an hour after upload.

From the shell: docfig convert statement.pdf -o statement.xlsx (or .csv, .json).

Errors

All errors derive from docfig.DocFigError and carry .code and .status:

Exception When
AuthenticationError missing, invalid or revoked key
PasswordRequiredError, WrongPasswordError locked PDF (.attempts_left)
InvalidFileError empty, too large, too many pages, unsupported, unreadable, or refused by the virus scan
LimitReachedError the month's pages are used (.upgrade_url)
RateLimitError too many requests (.retry_after); retried automatically first
ConversionFailedError the statement could not be read
ServiceUnavailableError daily capacity reached or busy; retried first
NotFoundError, DocFigTimeoutError, APIConnectionError unknown or expired id, waited too long, network

Options: docfig.Client(api_key=None, base_url="https://docfig.com", timeout=60, max_retries=3, poll_interval=2.0).

MCP server for AI assistants

docfig mcp runs a Model Context Protocol server on stdio, so Claude Desktop, Cursor, VS Code and other MCP apps can use DocFig directly:

  • check_transactions: check a transactions table (CSV, TSV or rows) for balance errors. Free, offline, no key. Same result as docfig check --json.
  • convert_statement: a statement PDF or photo (local path, https URL or base64) to checked transactions, with Excel and CSV links valid for one hour. Needs DOCFIG_API_KEY.
  • combine_statements: several statements to one set of accounts, with missing months and duplicated rows found.
  • usage: pages left this month.
{
  "mcpServers": {
    "docfig": {
      "command": "uvx",
      "args": ["docfig", "mcp"],
      "env": { "DOCFIG_API_KEY": "dfk_..." }
    }
  }
}

With pip instead of uv: pip install docfig, then use "command": "docfig", "args": ["mcp"]. No install at all: the hosted server is at https://mcp.docfig.com/mcp (Streamable HTTP; send the key as Authorization: Bearer dfk_...). Setup for each app: docfig.com/api#mcp.

Privacy

The offline check never sends anything anywhere. For the API: files are virus scanned, read in memory, account numbers are masked before the AI step, and results are deleted after an hour. See docfig.com/security.

License

MIT

Metadata

Release files for docfig 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for docfig 0.2.0
File Size Uploaded Provenance Actions
docfig-0.2.0.tar.gz 53.3 kB Without provenance Details for docfig-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for docfig 0.2.0
File Interpreter ABI Platform Actions
docfig-0.2.0-py3-none-any.whl Python 3 none any Details for docfig-0.2.0-py3-none-any.whl

Total release size: 93.6 kB

Release files / docfig-0.2.0.tar.gz

Download URL docfig-0.2.0.tar.gz
Size 53.3 kB
Tags Source
SHA-256 checksum
How to use checksums
e13d24ed5152f6756e7971aa5e2db863ea2e75f822ed1183edd1536f26916a55
BLAKE2b-256 checksum
How to use checksums
0f59159de316e9c348689a7d3ce668b8c993097d4e4fb6a081d676d6af1d40f4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release files / docfig-0.2.0-py3-none-any.whl

Download URL docfig-0.2.0-py3-none-any.whl
Size 40.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
40a877f350d9df157581138df34289417936ec7aa4cc2f33732d238fc48b6006
BLAKE2b-256 checksum
How to use checksums
cc785be76bd1680351ccc816c5bc41459d82678a45e82d61b1cc33dd298206f2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Security for docfig 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page