Skip to main content

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)

Source distribution for modernedi-sdk 0.1.0
File Size Uploaded
modernedi_sdk-0.1.0.tar.gz 292.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for modernedi-sdk 0.1.0
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

0.2.1

2 release files

0.2.0

2 release files

This release

0.1.0 This release

2 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