ModernEDI Python SDK
Server-side Python clients for the ModernEDI Integration API, including mappings, mapped outputs, transactions, configuration-as-code, and optional scenarios.
Preview 0.1.0: the API may evolve before 1.0. Install the official package from PyPI:
python -m pip install modernedi-sdk==0.1.0
Requires Python 3.10 or newer. Both synchronous and native asynchronous clients are included.
Get started
Create an Integration API key in your workspace with only the scopes your application needs. Keep it in a server-side secret store; never embed it in browser, mobile, or desktop distributions, or commit it to Git or logs. See Integration API authentication.
import os
from modernedi import ModernEdiClient
with ModernEdiClient(api_key=os.environ["MODERNEDI_API_KEY"]) as client:
response = client.partners.list_integration_partners()
print(response.data)
print("Support request ID:", response.request_id)
An incoming or outgoing mapping is enough to process a partner document. You do not need a scenario, Git repository, or configuration runner to use this client. Scenarios add conversation verification; configuration-as-code adds repeatable review and deployment of those same resources.
The client groups match the TypeScript SDK: partners, mappings, mapped_outputs,
transactions, outbound_as2, as2_connections, configuration_as_code, scenario_runs,
mapping_runtime, integration_events, account, and x12. Methods use snake_case and
keyword arguments. Their parameters and models come from the same OpenAPI contract.
from modernedi import AsyncModernEdiClient
async def list_partners(key):
async with AsyncModernEdiClient(api_key=key) as client:
return (await client.partners.list_integration_partners()).data
Reuse one client for connection pooling. Context managers close owned clients. If you inject an
HTTPX client using http_client=, you remain responsible for closing it; do not put authentication
in its default headers. The SDK chooses exactly one api_key or bearer_token, does not follow
redirects, verifies TLS by default, and uses a 30-second per-attempt timeout. Production requests
use https://api.modernedi.com. A custom base_url must use HTTPS except for loopback tests.
bearer_token sends the same Integration API key as Authorization: Bearer; it is not a
browser sign-in session token.
Models, configuration, and exact wire data
from modernedi import models
with ModernEdiClient(api_key=os.environ["MODERNEDI_API_KEY"]) as client:
exported = client.configuration_as_code.export_integration_configuration()
request = models.ConfigurationPlanRequest.from_dict({"files": exported.data.to_dict()["files"]})
planned = client.configuration_as_code.plan_integration_configuration(body=request)
print(planned.request_id) # A plan changes no configuration and sends no EDI.
models contains generated Pydantic models. Use from_dict()/from_json() for wire input and
to_dict()/to_json() for wire output, including nested union types; do not substitute Pydantic's
internal model_dump() for the wire serializer. Omitted optional fields stay omitted, and explicit
null/false values remain distinct. Configuration file contents and hashes are retained. Date-time
fields stay strings so nine-digit timestamp precision is not lost. Scenario parameter sets, Test
and Production bindings, and bindings with omitted syntax-tree pins are supported.
Configuration apply remains an explicit operation requiring the reviewed plan, current snapshot
precondition, and an idempotency key. This SDK does not apply automatically or bypass verification.
See configuration-as-code and the
read-only example.
Send source documents without changing their media type
For endpoints that accept XML, JSON, text, or X12, use an explicit RequestBody:
from modernedi import RequestBody
source = RequestBody.text("<invoice><number>INV-1</number></invoice>", "application/xml")
envelope = RequestBody.json(
{"input": "<invoice/>", "contentType": "application/xml", "params": {"invoiceNumber": "INV-1"}},
"application/vnd.modernedi.outbound+json",
)
# Pass one as body= to outbound_as2.send_as2_message(...) or reply_to_inbound_as2_message(...).
# test=True uses the partner's Test AS2 configuration; it still sends a real test message.
Use the generated-X12 methods only when you already have X12. Ordinary send/reply methods apply the selected outgoing map. Mapper-editor params are fixtures; supply required live params in the envelope. Polling mapped outputs does not acknowledge them: acknowledge only after durable custody.
Responses, errors, and retries
Every call returns ApiResponse: data, status_code, headers, and exact raw_body bytes,
plus request_id, etag, location, retry_after, idempotency_replayed, and content_sha256.
Use raw_body when checking a scenario evidence report's digest, not re-serialized JSON.
Conditional 304 responses have data=None.
ModernEdiApiError exposes status_code, code, request_id, retryable, details,
retry_after, and raw_body. Do not log raw partner documents or credentials indiscriminately.
Non-JSON errors still produce a structured exception with the status and available request ID.
Retries are off by default. Opt in with retry=RetryOptions(max_attempts=3). Retries cover
transport failures and HTTP 429/502/503/504 only. Safe reads, configuration plans, and transaction
watch/unwatch operations can retry; other mutations must support and supply an Idempotency-Key
in the API contract. Adding that header to an unsupported operation does not enable retries. The SDK never
retries before Retry-After; a delay above its configured cap returns the error to your application.
Pass request-specific headers/timeouts through RequestOptions. Cancellation of an async task
also cancels retry waits.
paginate_cursor and paginate_cursor_async accept page-loading, item, and next-cursor functions.
They preserve opaque cursors, detect cycles, and default to a 1,000-page limit. Repeat the same
filters on every page. Lower max_pages to bound work for your use case.
Verify mapped-output webhooks
from modernedi import verify_mapped_output_webhook
event = verify_mapped_output_webhook(raw_body, request_headers, signing_secret)
Pass the original bytes before JSON parsing. Verification checks the timestamp (five-minute
default tolerance), HMAC-SHA-256 with constant-time comparison, duplicate headers, event shape,
and header/body identity. WebhookVerificationError.code explains rejection. Your application
must durably deduplicate deliveryId; for business processing, also deduplicate message.id
because legitimate redelivery has a new delivery ID. A successful verification is not proof that
your ERP accepted the document.
No hosted workflow, provider login, or generator is needed by SDK consumers.
Build and test this repository
This is complete, standalone package source with offline tests and synthetic fixtures. No ModernEDI account, private repository, API key, or generator is needed.
python -m pip install . build
python -m unittest discover -s tests
python -m build
Generated API files come from ModernEDI's canonical contract. Please report issues here; changes are made upstream and exported as reviewed snapshots. PUBLIC_SOURCE.json records the exact source revision and hashes. Normal CI never publishes or calls your workspace.
Release files for modernedi-sdk 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| modernedi_sdk-0.1.0.tar.gz | 292.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| modernedi_sdk-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.1 MB
Release files / modernedi_sdk-0.1.0.tar.gz
| Download URL | modernedi_sdk-0.1.0.tar.gz |
|---|---|
| Size | 292.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6e4acabbc03b2d18e564b615acc531168bc45a71053ab2b6f58860e60024e64d
|
|
BLAKE2b-256 checksum How to use checksums |
a0f37d0e1c0e1234d0cacea1612c434414f0af8c44f1bfdde1808db0a4736a4b
|
| 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 Sep 18, 2026.
Transparency logRelease files / modernedi_sdk-0.1.0-py3-none-any.whl
| Download URL | modernedi_sdk-0.1.0-py3-none-any.whl |
|---|---|
| Size | 821.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
eb8fc5d5226489e0d2f65effd4e6cba5673c5d4e68dbb5c3d921e61cbd7f33fc
|
|
BLAKE2b-256 checksum How to use checksums |
869cb2d415a2a224b5ddd15ddfac4a9fe65031729c203ba0a9f63667d3157a0b
|
| 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 Sep 18, 2026.
Transparency log