Skip to main content

eqlx-ebelge

Read Turkish e-Fatura (UBL-TR) and e-Defter (XBRL GL) files: clean data, a trial balance (mizan), and consistency checks that catch wrong totals, invalid tax ids, duplicate invoices and unbalanced journal entries. An optional MCP server lets AI agents such as Claude use the same functions, read-only.

Built by eqlx. Part of eqlx.org, open research and tools.

Status: alpha (0.1.1). Tested on synthetic documents and checked against GİB's public sample packages (e-Fatura, e-Arşiv, e-Defter): on those samples it raises no false alarms, and the findings it does raise are real inconsistencies in the samples. Please report any real-world file it reads wrongly (without sending the file itself).

Why

Lenders, factoring companies and finance teams receive invoices and ledgers as GİB XML and still read them by hand or through paid tools. This library turns them into data you can check and analyse, locally, with no network access.

Install

pip install "eqlx-ebelge[mcp] @ git+https://github.com/eqlx-ai/eqlx-ebelge"

Python 3.10+. The core needs only defusedxml; [mcp] adds the MCP server.

Command line

ebelge sample demo          # write 10 synthetic files to try it on
ebelge check demo           # every check, on files, folders or ZIP archives
ebelge invoices demo --csv  # one row per invoice
ebelge mizan demo           # trial balance from e-Defter journals (add --level sub)
$ ebelge check demo
10 documents: 9 invoices, 1 ledger files (7 entries). 2 errors, 1 warnings, 0 info.

severity  code                file                         message
error     payable             fatura_08_toplam_hatali.xml  TaxInclusiveAmount - withholding + rounding = 4682.88, PayableAmount is 99999.99 (gap 95317.11)
error     tax_id_check_digit  fatura_09_vkn_hatali.xml     supplier VKN 4477127821 fails its check digit
warning   possible_duplicate  fatura_02.xml                supplier 4477127820, same customer, 2026-10-07, payable 10140.12: EQX2026000000002 (fatura_02.xml), EQX2026000000007 (fatura_07.xml)

$ ebelge mizan demo
account  name             debit      credit     debit_bal  credit_bal
100      KASA             10000.00   8500.00    1500.00    0
102      BANKALAR         560000.00  10000.00   550000.00  0
120      ALICILAR         90000.00   60000.00   30000.00   0
...

ebelge check exits with code 1 when it finds an error, so it can gate a pipeline.

Python

from pathlib import Path
import eqlx_ebelge as eb

inv = eb.read_invoice(Path("fatura.xml").read_bytes(), "fatura.xml")
inv.supplier.tax_id, inv.totals.payable, [line.name for line in inv.lines]
eb.check_invoice(inv)  # list of Finding(code, severity, message, ...)

report = eb.scan(["inbox/", "archive.zip"])  # every document, every check, duplicates across all
report.summary()

ledgers = [eb.read_ledger(p.read_bytes(), p.name) for p in sorted(Path("edefter").glob("*.xml"))]
rows = eb.trial_balance(ledgers)  # e.g. twelve monthly journals -> one year's mizan

Amounts are Decimal, never floats.

Checks

Code Severity What it catches
tax_id_check_digit, tax_id_length, tax_id_missing error VKN or TCKN that fails its check digit, has the wrong length, or is missing
lines_total error invoice lines do not add up to LineExtensionAmount
tax_total, tax_inclusive error tax subtotals or the tax-inclusive total do not add up
payable error above 1 TRY, else warning payable amount differs from tax-inclusive total minus withholding (tevkifat)
line_amount, tax_rate warning quantity x price - discount, or base x rate, differs from what the line or tax says
number_format, number_year, uuid_format warning invoice number is not 3 characters + year + 9 digits, its year differs from the date, malformed ETTN
duplicate_uuid, duplicate_number error the same ETTN, or the same supplier and number, appears more than once
possible_duplicate warning same supplier, customer, date and amount under different numbers
entry_unbalanced, entry_total, ledger_unbalanced error a journal entry, its header totals, or the whole file do not balance
counter_repeat / counter_gap error / warning journal entry counters repeat or skip
date_outside_period warning an entry dated outside the period the file covers
placeholder_tckn, same_party, account_code, unsupported info context worth knowing
unreadable error a file that is malformed or unsafe to parse

Tolerances: one kuruş per comparison, plus half a kuruş per line where per-line rounding adds up.

MCP server (for Claude and other agents)

The server exposes four read-only tools: list_documents, check, read_invoices and trial_balance. It reads only inside the folder you give it; .., absolute paths and symlinks that point outside are refused.

Claude Code:

claude mcp add ebelge -- ebelge mcp --root /path/to/invoices

Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "ebelge": { "command": "ebelge", "args": ["mcp", "--root", "/path/to/invoices"] }
  }
}

Then ask, for example: "Bu klasördeki faturaları kontrol et, sorunlu olanları ve mükerrerleri göster."

Safety and privacy

  • Runs locally. No network access, no telemetry.
  • XML with a DOCTYPE is refused, which blocks entity-expansion and external-entity (XXE) attacks.
  • ZIP archives are read in memory with limits on size, file count and compression ratio.
  • From e-Defter it keeps only what the checks and the trial balance need; entry comments, document numbers and people's names are not read.
  • Tests use synthetic documents only. ebelge sample writes the same kind of made-up files.

See LIMITS.md for what it does not do.

Development

uv sync --all-extras
uv run pytest
uv run ruff check . && uv run ruff format --check . && uv run mypy src

Contributions are welcome; see CONTRIBUTING.md.

License

Apache-2.0. See LICENSE and NOTICE. GİB schemas are not included.

Metadata

Release files for eqlx-ebelge 0.1.1

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

Source distribution (sdist)

Source distribution for eqlx-ebelge 0.1.1
File Size Uploaded Provenance Actions
eqlx_ebelge-0.1.1.tar.gz 31.0 kB With provenance Details for eqlx_ebelge-0.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for eqlx-ebelge 0.1.1
File Interpreter ABI Platform Actions
eqlx_ebelge-0.1.1-py3-none-any.whl Python 3 none any Details for eqlx_ebelge-0.1.1-py3-none-any.whl

Total release size: 66.4 kB

Release files / eqlx_ebelge-0.1.1.tar.gz

Download URL eqlx_ebelge-0.1.1.tar.gz
Size 31.0 kB
Tags Source
SHA-256 checksum
How to use checksums
882a8f52220b7acc4e9875c66e329e825dbfb2f50ef0e8d198ebc9d57a385010
BLAKE2b-256 checksum
How to use checksums
920a1f7e99cc5fe68a2910ecc4575fa07e9b36827749d1c8dbb254dd2bd9fb70
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.

Transparency log

Release files / eqlx_ebelge-0.1.1-py3-none-any.whl

Download URL eqlx_ebelge-0.1.1-py3-none-any.whl
Size 35.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e92306427b824ef161b29f841b946b146de7aa83cfff3ec032d7b6cf74536216
BLAKE2b-256 checksum
How to use checksums
efbe4e4d8f924dde9a9eed9c68d5b4f707967735b0bfc34a59b1e168bac56d94
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.

Transparency log

Security for eqlx-ebelge 0.1.1

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.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for eqlx_ebelge-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.

Transparency log

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.1 This release

2 release files Full 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