ml-connector
AcumaticaStedi

Acumatica and Stedi integration

Acumatica runs finance, distribution, and order management as the system of record. Stedi translates between JSON and X12 EDI and routes those documents to and from trading partners. Connecting the two means purchase orders and invoices entered in Acumatica become outbound EDI without re-keying, and inbound EDI from partners lands back in Acumatica as real records. ml-connector reads documents from Acumatica, hands them to Stedi to generate the matching X12 transaction set, and consumes Stedi inbound webhooks to write orders and acknowledgments into Acumatica. Because Stedi stores no business records, Acumatica stays the single source of truth.

How Acumatica works

Acumatica exposes vendors, customers, purchase orders, AP bills, sales invoices, GL accounts, and journal transactions through its contract-based REST API, where every entity path is version-locked to the customer ERP release, such as /entity/Default/24.200.001/PurchaseOrder, and every field value is wrapped in a value object. It authenticates with OAuth 2.0 through the built-in OpenID Connect server or with a legacy session cookie, against a tenant-specific instance URL. Acumatica push notifications can fire on record changes but use a shared-secret header rather than a signed payload and are not guaranteed, so the common pattern is polling on LastModifiedDateTime with top and skip paging.

How Stedi works

Stedi is an EDI translation and routing layer, not a data store, so it holds no vendors, invoices, or accounts. It exposes a REST API secured by a Bearer API key in the Authorization header, and it works in X12 transaction sets such as 850 purchase order, 810 invoice, 856 ship notice, and 855 order acknowledgment. Outbound documents are created by posting JSON to the partnership generate-edi endpoint, after which Stedi builds the X12 and delivers it over SFTP or AS2. Inbound documents are pushed to your endpoint as the transaction.processed event, which carries a download URL for the translated JSON that requires the API key to fetch.

What moves between them

Documents move in both directions. Outbound, ml-connector reads purchase orders and sales invoices from Acumatica and posts them to Stedi, which generates the matching X12 850 and 810 and delivers them to the trading partner. Inbound, Stedi pushes processed transactions such as an 850 from a buyer or an 855 acknowledgment, and ml-connector writes them into Acumatica as purchase orders, sales orders, or status updates against the original document. Outbound runs on a schedule that polls Acumatica for new and changed records, since its push notifications are not guaranteed, while inbound is driven by Stedi webhooks as partner files arrive.

How ml-connector handles it

ml-connector stores both credential sets encrypted. On the Acumatica side it requests and refreshes an OAuth 2.0 token against the tenant instance URL, pins the endpoint version so a release mismatch does not return a 404, and wraps every field value in the required value object. On the Stedi side it sends the API key on each request and posts outbound JSON to the partnership generate-edi endpoint, letting Stedi assign the ISA and GS control numbers rather than setting them by hand. Partnerships and transaction settings are configured once in the Stedi portal because there is no API to create them, and ml-connector maps Acumatica vendor, customer, and item codes to the partner and item identifiers each X12 guide expects. Inbound webhooks must be answered within Stedi's five-second timeout, so ml-connector returns 2xx immediately, then fetches the translated JSON from the download URL using the API key and writes it into Acumatica asynchronously. Acumatica has no idempotency-key header, so ml-connector dedupes on the document reference and a BullMQ jobId before posting, and it deduplicates inbound events on the Stedi event id. Stedi returns 429 when throttled and Acumatica returns 429 at its license-tier limit, so both calls back off and retry, and every document carries a full audit trail and can be replayed if a write fails.

A real-world example

A mid-sized industrial supplier with roughly 250 employees runs Acumatica for distribution and finance and has to trade EDI with several large retail and OEM customers that require X12. Before the integration, a coordinator printed each inbound purchase order that arrived through the partners' portals and keyed it into Acumatica, then hand-built outbound invoices in a separate EDI tool, which slowed order entry and caused chargebacks when a document was late or mismatched. With Acumatica and Stedi connected, inbound 850 orders flow straight into Acumatica as sales orders, and the invoices Acumatica raises against them go out to Stedi as 810 documents within the schedule window. Order entry stops being manual, the outbound invoices match their orders, and the chargebacks for missing or late EDI go away.

What you can do

  • Generate outbound X12 850 purchase orders and 810 invoices from Acumatica records through Stedi.
  • Write Stedi inbound transactions such as 850 orders and 855 acknowledgments back into Acumatica.
  • Map Acumatica vendor, customer, and item codes to the partner and item identifiers each X12 guide expects.
  • Bridge Acumatica OAuth 2.0 and the Stedi Bearer API key, and pin the Acumatica endpoint version per customer.
  • Answer Stedi webhooks within the five-second limit, then fetch and post the translated JSON with retries and a full audit trail.

Questions

Which direction does data move between Acumatica and Stedi?
Both directions. Acumatica purchase orders and invoices are read and sent to Stedi to generate outbound X12, while Stedi inbound webhooks such as an 850 order or 855 acknowledgment are written back into Acumatica. Stedi holds no business records of its own, so Acumatica stays the system of record and ml-connector only uses Stedi to translate and route the documents.
Does Stedi store the orders and invoices, or just translate them?
Stedi only translates and routes. It converts JSON to X12 and back and delivers files over SFTP or AS2, but it does not persist vendors, invoices, or accounts. The canonical records live in Acumatica, and ml-connector fetches the translated JSON from the download URL on each Stedi event to write it into Acumatica.
How does the integration handle inbound EDI given Stedi's five-second webhook timeout?
ml-connector returns a 2xx response to Stedi immediately and processes the document asynchronously. It then fetches the translated JSON using the Stedi API key, since the download URL is not public, and writes it into Acumatica. Inbound events are deduplicated on the Stedi event id so a redelivered webhook does not create a duplicate record.

Related integrations

Connect Acumatica and Stedi

Free to use. Add your credentials, ping your real systems, and see if we fit.

Get started