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) 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).

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.1.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.1.0
File Size Uploaded Provenance Actions
docfig-0.1.0.tar.gz 29.1 kB Without provenance Details for docfig-0.1.0.tar.gz

Built distribution (wheel)

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

Total release size: 52.8 kB

Release files / docfig-0.1.0.tar.gz

Download URL docfig-0.1.0.tar.gz
Size 29.1 kB
Tags Source
SHA-256 checksum
How to use checksums
623a0542b59463dbc4d6499d9965b53dc4ecfd2b7fb86af96836e673a676074f
BLAKE2b-256 checksum
How to use checksums
7f5964d3c739afd4947af22cf16d58fc210fb684cf600efb6393a2cba076f0f7
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.1.0-py3-none-any.whl

Download URL docfig-0.1.0-py3-none-any.whl
Size 23.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a920aab0e68d6e07bf522dab8fc4457c8df6b9520040722c8da4fd3676e1b535
BLAKE2b-256 checksum
How to use checksums
b1025af4ee524856af8d803d2df2f4b92617d2d9fbfc82ad754206579239a29f
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.1.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.1.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