Skip to main content

oxedi

A fast, lossless parser and writer for X12 EDI 835 files (electronic remittance advice). The core is written in Rust and is available from Python and from DuckDB.

  • Lossless. Every byte of the file is kept. Nothing is silently dropped, and the file can be written back exactly as it was read.
  • Ready-made tables. Payments, claims, service lines and adjustments come out as typed tables that open in Polars, pandas, pyarrow or DuckDB.
  • Problems are reported, not raised. Questionable data still parses; each issue is a diagnostic that names the rule, the position and the value.

Install

pip install oxedi               # no Python dependencies
pip install "oxedi[polars]"     # with Polars
pip install "oxedi[pandas]"     # with pandas and pyarrow
pip install "oxedi[pyx12]"      # with pyx12 validation
pip install "oxedi[edi-835-parser]"  # drop-in layer for edi-835-parser users

Requires Python 3.11 or later. Wheels are available for Linux (x86_64 and aarch64, plus musl on x86_64), macOS (Intel and Apple silicon) and Windows (x86_64).

For DuckDB:

INSTALL oxedi FROM community;
LOAD oxedi;

The community build is not available yet: it waits for the maintainers to merge duckdb/community-extensions#2942. Until then, build the extension and LOAD the file; see DuckDB.

Read

import oxedi

result = oxedi.parse_file("remittance.835")      # or oxedi.parse(data) from bytes

claims = result.tables["claims"].to_polars()     # or .to_pandas()
services = result.tables["services"].to_polars()

print(result.count_claims(), result.sum_payments())  # sum_payments() is a Decimal
print(result.payer["name"], result.payee["name"])

There are five tables: payments, claims, services, adjustments and provider_adjustments. Child tables point to their parents by row number. Tables also follow the Arrow PyCapsule interface, so DuckDB and any Arrow-aware library read them directly:

import duckdb

claims = result.tables["claims"]
duckdb.sql("select claim_status, sum(payment_amount) from claims group by 1")

A file that is not an 835 at all raises oxedi.ParseError. Anything else parses, and its problems come back as diagnostics:

for diagnostic in result.diagnostics:
    print(diagnostic)

For large files, stream yields one transaction at a time, so memory stays bounded:

from pathlib import Path

for batch in oxedi.stream(Path("big.835").read_bytes()):
    services = batch.tables["services"].to_polars()

To get a parsed file back byte for byte: result.document.write().

Write

oxedi.write turns tables into an 835. Parse, change a value, write:

import datetime
import polars as pl

frames = {name: result.tables[name].to_polars() for name in result.tables.keys()}
frames["payments"] = frames["payments"].with_columns(trace_number=pl.lit("CHK100235"))

envelope = oxedi.Envelope(
    sender_id="ACMEPAYER",
    receiver_id="SUNRISECLINIC",
    date=datetime.date(2024, 1, 10),
    time=datetime.time(9, 0),
    usage_indicator="T",  # "P" (production) is the default
)
data = oxedi.write(frames, envelope, spec=result.spec)  # bytes, one interchange

Pass spec=result.spec so the tables are written with the spec that parsed them (4010 or 5010). The writer is strict: if the file would not read back clean, or the money does not balance, it raises oxedi.WriteError listing every finding, and writes nothing. To get the file anyway, for example to build invalid test files:

try:
    data = oxedi.write(frames, envelope, spec=result.spec)
except oxedi.WriteError as error:
    for finding in error.findings:
        print(finding.table, finding.row, finding.column, finding)

data, findings = oxedi.write(frames, envelope, spec=result.spec, allow_findings=True)

DuckDB

FROM read_835('remits/*.835', table_name := 'services', filename := true);

-- the findings of the parse, one row each
FROM read_835('remits/*.835', table_name := 'diagnostics', ignore_errors := true);

Write tables back with COPY. This needs extension 0.2.0 or later; until it reaches the community repository, build the extension. payments, claims and the rest are tables or views with those names, for example CREATE TEMP TABLE claims AS FROM read_835('remittance.835', table_name := 'claims'), changed in SQL before writing:

COPY (
  SELECT {
    'payments':             (SELECT list(t ORDER BY t."row") FROM payments t),
    'claims':               (SELECT list(t ORDER BY t."row") FROM claims t),
    'services':             (SELECT list(t ORDER BY t."row") FROM services t),
    'adjustments':          (SELECT list(t ORDER BY t."row") FROM adjustments t),
    'provider_adjustments': (SELECT list(t ORDER BY t."row") FROM provider_adjustments t)
  }
) TO 'out.835' (FORMAT edi835, sender_id 'ACMEPAYER', receiver_id 'SUNRISECLINIC',
                date DATE '2024-01-10', time TIME '09:00');

Validate with pyx12

import oxedi
from oxedi.pyx12 import validate

result = oxedi.parse_file("remittance.835")
findings = result.diagnostics + validate("remittance.835")   # bytes, a path or a binary file
for d in sorted(findings, key=lambda d: d.level):
    print(d.origin, d.code, d)                   # "oxedi" or "pyx12"

parse never calls pyx12; validate does, on demand, and returns the same Diagnostic type.

Spec versions

parse, parse_file and stream read the version a file declares and use the matching built-in spec: 5010 (005010X221A1) by default, 4010 (004010X091A1) for 4010 files. Pass spec=oxedi.Spec.builtin("4010") to choose one. A JSON patch adds segments or table columns without touching the code; see The spec.

More detail

Guide What is in it
Reading Tables in depth, large files, diagnostics, the document
Writing The envelope, findings, balancing rules, writing from your own tables
DuckDB read_835 parameters, COPY options, accepted types, limits
The spec Spec versions and patches
Validating with pyx12 What validate reports and where
Migrating from edi-835-parser Change the import, or move to the native API

Versioning

The project follows semantic versioning. While the version is 0.x, a minor release may change the API. See CHANGELOG.md. The DuckDB extension is versioned separately.

Contributing

See CONTRIBUTING.md.

License

MIT. See LICENSE and THIRD_PARTY_NOTICES.

Metadata

Release files for oxedi 0.5.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 oxedi 0.5.0
File Size Uploaded
oxedi-0.5.0.tar.gz 343.0 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for oxedi 0.5.0
File
oxedi-0.5.0-cp311-abi3-win_amd64.whl CPython 3.11 abi3 Windows x86-64 Details
oxedi-0.5.0-cp311-abi3-musllinux_1_2_x86_64.whl CPython 3.11 abi3 Linux musl 1.2+ x86-64 Details
oxedi-0.5.0-cp311-abi3-manylinux_2_28_x86_64.whl CPython 3.11 abi3 Linux glibc 2.28+ x86-64 Details
oxedi-0.5.0-cp311-abi3-manylinux_2_28_aarch64.whl CPython 3.11 abi3 Linux glibc 2.28+ ARM64 Details
oxedi-0.5.0-cp311-abi3-macosx_11_0_arm64.whl CPython 3.11 abi3 macOS 11.0+ ARM64 Details
oxedi-0.5.0-cp311-abi3-macosx_10_12_x86_64.whl CPython 3.11 abi3 macOS 10.12+ x86-64 Details

Total release size: 8.1 MB

Release files / oxedi-0.5.0.tar.gz

Download URL oxedi-0.5.0.tar.gz
Size 343.0 kB
Tags Source
SHA-256 checksum
How to use checksums
d4a99df0d3609c78b274d8cafcee9937e8c05805d70d89e54b968dfc71257e08
BLAKE2b-256 checksum
How to use checksums
91f572c3d28663d58cf6c719bee7ba7d00bb0ed94454cfe203db33a2d20de543
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Oct 12, 2026.

Transparency log

Release files / oxedi-0.5.0-cp311-abi3-win_amd64.whl

Download URL oxedi-0.5.0-cp311-abi3-win_amd64.whl
Size 1.1 MB
Tags CPython 3.11 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
91d9d81585bfa74b2c92c3ea809d9e22b4bde2ac0d23c18db246fc5dcb055a0a
BLAKE2b-256 checksum
How to use checksums
852f47d03b5e73e64e2e37c8ac895f19fc4a2465da183dc9c8bc50666e56eab3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Oct 12, 2026.

Transparency log

Release files / oxedi-0.5.0-cp311-abi3-musllinux_1_2_x86_64.whl

Download URL oxedi-0.5.0-cp311-abi3-musllinux_1_2_x86_64.whl
Size 1.6 MB
Tags CPython 3.11 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
407b489bfd9a291fa2541c4ca2b24126ae55cfa150b2f7b06f3c49ca2bf71c72
BLAKE2b-256 checksum
How to use checksums
b2581d2f908ebd75379a62c96831b87d2fd009e635fa893a790f6bbdaafea99c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Oct 12, 2026.

Transparency log

Release files / oxedi-0.5.0-cp311-abi3-manylinux_2_28_x86_64.whl

Download URL oxedi-0.5.0-cp311-abi3-manylinux_2_28_x86_64.whl
Size 1.4 MB
Tags CPython 3.11 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
d00fcb11ca325351e8a0b16a1ee08999e819efe3f9eea8ed7c43cb21b98c0148
BLAKE2b-256 checksum
How to use checksums
ce1ff51c37a505f2a38104fb2278c7a283eac6c04620770594f5fdbe12ec555f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Oct 12, 2026.

Transparency log

Release files / oxedi-0.5.0-cp311-abi3-manylinux_2_28_aarch64.whl

Download URL oxedi-0.5.0-cp311-abi3-manylinux_2_28_aarch64.whl
Size 1.3 MB
Tags CPython 3.11 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
fea499c0ecc7291add2a7741acba741343e6d7e4d98242ad397454fb506be50f
BLAKE2b-256 checksum
How to use checksums
b3aa61e0100902e83b84d8498bc61101f57ad0c74d932382e0aa359509d389de
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Oct 12, 2026.

Transparency log

Release files / oxedi-0.5.0-cp311-abi3-macosx_11_0_arm64.whl

Download URL oxedi-0.5.0-cp311-abi3-macosx_11_0_arm64.whl
Size 1.2 MB
Tags CPython 3.11 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
7514960f269ab084ef43833c263d339a5b461c689d31c101b732fec8e65f4282
BLAKE2b-256 checksum
How to use checksums
3235b2ad5f9991b16c95cb388872be4541bede25b8e1a331e91e5e6504de9db6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Oct 12, 2026.

Transparency log

Release files / oxedi-0.5.0-cp311-abi3-macosx_10_12_x86_64.whl

Download URL oxedi-0.5.0-cp311-abi3-macosx_10_12_x86_64.whl
Size 1.2 MB
Tags CPython 3.11 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
bd347c7833b8bab53b46a133caec7c6f61878b1c401f740a43108c25684af095
BLAKE2b-256 checksum
How to use checksums
7585adaf663d055c9f0f38b091cc67da86e90333d18cc05814d399ce3ea362d6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Oct 12, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.5.0 This release

7 release files

0.4.0

7 release files

0.3.0

7 release files

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