Skip to content
View Categories

EDI X12

4 min read

Audience: admin, developer · Last updated: 2026-06-16 · Edit on GitHub

EDI X12 #

EDI is dense and infrequent — you set up a trading partner once, then touch it
quarterly and have forgotten everything. This page is reference-grade: what
Bizuno actually supports, how a document moves, and where to look when one
doesn’t.


What’s supported #

Bizuno implements five X12 transaction sets, all real and operational:

Set Name Direction In Bizuno
850 Purchase Order Inbound Parsed and posted as a Sales Order (pending review)
997 Functional Acknowledgment Both Emitted for every inbound 850; accepted inbound
810 Invoice Outbound Built from a posted invoice
855 PO Acknowledgment Outbound Line-level accept/reject of a PO
856 Advance Ship Notice (ASN) Outbound Shipment confirmation with HL loops + tracking

Transport is SFTP (via phpseclib) — Bizuno pulls inbound files from the
partner’s “get” directory and writes outbound files to a “put” directory.


Configuring a trading partner #

Trading partners are configured under Settings → EDI Configuration (the
adminEdi controller); each partner is stored as metadata against a contact.
The fields that matter:

Field Meaning
cID The customer/vendor contact this partner is
ediID Your sender ID (goes in the ISA/GS of replies)
rcvrID Their receiver ID (verified against inbound ISA)
sepTag / sepSec Segment terminator (~) and element separator (*)
hostName / userName / userPass SFTP connection
pathGet / pathPut Inbound and outbound directories on the SFTP server

Multiple partners are supported — each is its own metadata row, and a poll runs
through all of them. File names are auto-generated as
{rcvrID}_{soNum}_{controlNum}_{spec}.edi; there’s no name-pattern to configure.


Inbound 850 lifecycle #

SFTP poll (ediGet)
   → pull files from the partner's pathGet
   → parse: split on sepTag (~) into segments, sepSec (*) into elements
   → verify ISA receiver ID matches rcvrID
   → dispatch each segment to its handler (x12_850_rcv)
   → map to a Sales Order (journal_id = 10), status "pending review"
   → post the order
   → build and send a 997 back to pathPut (AK5 = A accepted / E errors)

The order lands as pending review, not silently final — a human approves it
before it becomes a live commitment. Duplicate POs (same partner + PO number) are
detected and skipped.


Outbound 810 lifecycle #

Trigger: ediTransmit(invoiceID, '810')
   → build the envelope + segments from the posted invoice
   → write {rcvrID}_{soNum}_{ctl}_810.edi to pathPut over SFTP
   → verify the file landed
   → log the transmission (expect a 997 back from the partner)

855 (PO ack) and 856 (ASN) follow the same outbound shape, built by their
respective x12_855_rsp / x12_856_rsp builders.


Segment reference #

A document is an envelope wrapping content segments:

ISA ── interchange envelope (sender/receiver IDs, control number)
 GS ── functional group
  ST ── transaction set (850 / 810 / …)
     BEG  PO header (inbound 850)   |  BIG  invoice header (outbound 810)
     N1/N3/N4  name + address (bill-to / ship-to / …)
     PO1  line item (inbound)       |  IT1  line item (outbound)
     PID  product description (paired with the line)
     N9 + MSG  reference text  →  captured as a $0 description line (see below)
     CTT  transaction totals
  SE ── transaction-set trailer
 GE ── functional group trailer
IEA ── interchange trailer

The dispatcher routes each segment to a handler by name. Unknown segments are
not fatal
— they’re logged to the trace
(as a trap entry) and skipped, so an unexpected segment annotates the diagnostics
rather than failing the whole document.

The N9 + MSG pattern #

Some partners send reference text (e.g. “PO POLICIES” plus a URL) in N9/MSG
segments. Rather than ignore them or trap on them, Bizuno captures the N9 label +
MSG text as a $0 description line on the resulting Sales Order — visible to
the reviewer, zero effect on totals. MSG is handled as an explicit no-op so the
segment dispatcher doesn’t log it as unexpected. (since v7.4.0.)


Errors, acknowledgments, and reconciliation #

  • Inbound errors (bad ST, receiver-ID mismatch, unknown SKU, price variance)
    accumulate during processing. A 997 is still returned for every inbound 850,
    with AK5 = A when clean or E when errors were found, so the partner learns
    the outcome.
  • Logging: each EDI exchange is recorded as transaction metadata (spec,
    status, control number, the raw payload, the ack payload and date), and
    success/error emails go to the addresses configured in the EDI settings.
  • Reconciliation: match your outbound documents to the partner’s returning
    997s; an outbound 810 with no 997 back, or an inbound 850 whose 997 you sent
    with AK5 = E, is what to chase.

When something goes wrong: read the trace #

EDI problems surface in the trace file.
Unexpected segments, parse failures, SFTP connection errors, and SKU/price
mismatches all leave entries there (with credentials scrubbed). Reproduce the
poll or transmit, then read the trace for that run — it’s the fastest path from
“the partner says it failed” to the actual segment that broke.


Related #

Powered by BetterDocs

Leave a Comment