Skip to main content

Transports

The same pipeline — dedup → validate → translate → queue → acknowledge — runs behind every transport, so a partner can move between them without any code changes.

HTTP API

The direct path. POST /v1/edi/inbound takes X12 or EDIFACT (auto-detected) and returns the 997/CONTRL plus parsed JSON. Outbound endpoints take StateSet-shaped JSON and return wire format:
The HTTP inbound API is deliberately single-interchange — batch splitting applies only to the file transports.

File / VAN directory

Set EDI_INBOUND_DIR and EDI_OUTBOUND_DIR to directories served by your SFTP server or synced from a VAN. The worker picks up .edi, .x12, and .txt files, writes *.997.edi / *.ta1.edi responses, and moves consumed files to processed/ — or to failed/ with an .error.txt. Nothing is ever consumed silently. Files modified within the last EDI_SETTLE_SECONDS (default 2) are skipped, so an upload still in flight is never read half-written.
A pickup holding several concatenated ISA..IEA interchanges — the classic VAN batch shape — is split and each interchange processed independently. Acks get a .N infix (batch.1.997.edi), and one bad interchange quarantines the file with a note naming it while its siblings still process. This applies to all three file transports: directory, SFTP, and VAN mailbox.

Native SFTP mailbox

When the partner or VAN hosts the mailbox, the gateway connects out as an SFTP client (pure-Rust russh, no OpenSSL). It polls the remote inbound directory, processes each file, writes the 997/TA1 to the remote outbound directory, and moves sources into processed/ / failed/.
Leaving EDI_SFTP_HOST_KEY unset accepts any host key with only a warning. Pin the fingerprint in production.

AS2 (EDI over HTTP, with receipts)

AS2 answers what file transport can’t: did the partner receive this document, intact? The gateway computes a MIC (message integrity check) over what it sends; the partner returns an MDN echoing a MIC over what they received. A match is cryptographic proof of intact receipt.

Receiving

POST /v1/as2 — partners deliver here. The endpoint processes the EDI and returns a synchronous MDN. Per the AS2 spec it answers 200 OK even when the EDI is rejected; the disposition inside the MDN carries the verdict. It is unauthenticated by transport design — partners are identified by AS2 identity and S/MIME signature. Set EDI_AS2_REQUIRE_VERIFIED_INBOUND (default true) to fail closed: every inbound message must be signed and verified against the partner’s configured certificate.

Sending with tracked delivery

Dispatching to an AS2 partner records a pending delivery and returns immediately. A background worker (EDI_DELIVERY_POLL_SECONDS, default 60) sends each due delivery, confirms its MDN, and on failure retries with exponential backoff (1m → 30m). After the attempt cap it marks the delivery failed and fires a critical alert. Inspect deliveries at GET /v1/deliveries; re-drive one with POST /v1/deliveries/{id}/redeliver or all failures with POST /v1/deliveries/redeliver-bulk. Delivery state is shared via Postgres, so any replica can drive a delivery.

Synchronous and asynchronous MDNs

  • mdn_mode: sync (default) confirms the delivery inline from the HTTP response.
  • mdn_mode: async parks the delivery awaiting_mdn and does not retry it until the partner POSTs its MDN to POST /v1/as2/mdn. That endpoint matches it to the tracked delivery by Original-Message-ID, recomputes the MIC from the delivery’s stored payload to verify integrity, and flips it to delivered — or failed with an alert. An awaiting_mdn delivery older than EDI_MDN_TIMEOUT_HOURS (default 24) is re-driven by the worker.

S/MIME

Pure-Rust RustCrypto. Detached CMS SignedData (multipart/signed, SHA-256 + RSA) for signing and verification, and CMS EnvelopedData (AES-256-CBC + RSA key transport) for encryption. Set EDI_AS2_KEY_FILE and EDI_AS2_CERT_FILE plus a partner’s as2.partner_cert_pem to sign-then-encrypt outbound and decrypt-then-verify inbound. The MIC is computed over pre-encryption content on both ends, so receipts verify regardless of encryption. Rotate the signing/decryption identity without a restart via POST /v1/as2/identity. By default a rotation is replica-local; set EDI_AS2_PERSIST_IDENTITY=true to persist it to the state backend so it survives restarts and reaches all replicas — at the cost of putting key PEM in the database or data directory.

AS1 (EDI over email)

Partners who exchange EDI by email are served over AS1. Set a partner’s as1.partner_email and every outbound document is delivered as an application/edi-x12 attachment via the stateset-mail connector — best-effort, never blocking the API response. Inbound AS1 arrives at POST /v1/as1/inbound, where the mail service forwards the message. Configure the connector with EDI_MAIL_API_URL, EDI_MAIL_API_KEY, and EDI_MAIL_FROM.
  • Configuration — the full environment-variable reference
  • Operations — deliveries, reconciliation, and alerting