---
title: EDI X12
description: "**Audience:** admin, developer · **Last updated:** 2026-06-16 · [Edit on GitHub](https://github.com/phreesoft/bizuno/edit/main/docs/07-integration/02-edi-x12.md) # 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…"
url: "https://www.bizuno.com/docs/edi-x12/"
updated: "2026-06-18"
category: Integration
---

# EDI X12

**Audience:** admin, developer · **Last updated:** 2026-06-16 · [Edit on GitHub](https://github.com/phreesoft/bizuno/edit/main/docs/07-integration/02-edi-x12.md)

# 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](/docs/trap-and-trace-files/)
 (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](/docs/trap-and-trace-files/).
 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

- [Trap and trace files](/docs/trap-and-trace-files/) — where EDI parse/segment errors land
- [Quote → SO → Invoice → Payment → Deposit](/docs/quote-so-invoice-payment-deposit/) — the Sales Order an inbound 850 becomes
- [REST API surface](/docs/rest-api-surface/) — `ediCron` and the token-authenticated portal API
