How to Send an EDI 870 Order Status Report
Step-by-step guide to building an EDI 870 Order Status Report: required segments, trigger rules, testing, and how to fix rejected PO references.
What Triggers an EDI 870 and Who Sends It
The EDI 870 order status report is a transaction a supplier sends to a buyer, never the other way around.Suppliers send an EDI 870 Order Status Report in two main scenarios: in response to an EDI 869 Inquiry, providing detailed answers to buyer questions about a specific order, or as a scheduled update, sent automatically at set intervals or milestones in the order process. If you're an EDI manager on the supplier side being asked to add 870 support to a distributor relationship, that's the whole decision tree: either you're reacting to something the buyer asked, or you've agreed to push updates on a cadence nobody has to ask for.
Scope matters more than people expect. An EDI 870 is the X12 Order Status Report: the transaction set used to report the current status of a requirement forecast, an entire purchase order, selected line items or products on a purchase order, or a customer's purchase orders. That's five distinct reporting levels in one transaction set, and the implementation guide your partner sends you will tell you which ones they actually expect. Don't assume "order status" means the whole order every time. A lot of 870 deployments only ever populate line-item status because that's what the buyer's merchandising system consumes.
The companion document is the EDI 869 order status inquiry. EDI 869 is used by customers to request an update on all or part of an existing order, and generally requires a seller response using EDI 870 Order Status Report. If your trading partner spec references both, you need inbound 869 parsing logic that can trigger an outbound 870 build automatically, usually keyed off the PO number and line references in the inquiry's REF segments.
Before You Start: What You Need
You can't build a correct 870 without the right inputs lined up first. At minimum you need an active trading partner agreement that specifies 870 usage, a translator capable of generating proper X12 envelopes, and the original PO data sitting where your mapping tool can reach it.
- A signed trading partner spec naming version 4010 (the common version for this transaction) — CDW, Insight, and D&H all publish their own 870 implementation guides at this version, and no two are identical on which segments are "must use" versus optional.
- An EDI translator or mapping tool (Cleo Integration Cloud, TrueCommerce, SPS Commerce, IBM Sterling, Orderful, Boomi, or an order-visibility layer like Cargoson sitting over your ERP) that can generate ISA/GS/ST envelopes and validate against the partner's guide before transmission.
- The original PO number, PO date, and line-item identifiers pulled from the inbound 850 — not re-keyed by a human.
- Agreed status codes. BSR01 and ISR01 are both coded fields and your partner's guide defines which codes they'll accept.
- 997 functional acknowledgement support configured on both sides. Once received, buyers typically send back an EDI 997 Functional Acknowledgement to confirm successful receipt of the 870, and if you're responding to an 869 inquiry, the same rule applies in reverse — most sellers will respond to EDI 869 with an EDI 997 Functional Acknowledgement to confirm receipt, and will also normally reply with an EDI 870 Order Status Report.
One timing detail that trips up new implementers: some retailers explicitly forbid sending an 870 too early. Sears' own guideline states plainly, "Do not send an 870 the same day that you receive the 850 Purchase Order, you must wait at" least a day. Check your specific partner's guide for a similar rule before you wire up a same-day trigger.
Step-by-Step: Building the 870
The structure is three tables — heading, detail, summary — built around two core segments: BSR at the top and ISR repeated per line or per order. Here's the build sequence in practice.
- Confirm the trigger. Check whether you're responding to an inbound 869 or firing on a scheduled interval from your trading partner agreement. This decides what goes in BSR01.
- Open with ST*870 and a control number. The transaction set exists "for use within the context of an Electronic Data Interchange (EDI) environment" and functions under Functional Group ID=RS, so your GS segment needs RS as the functional identifier code, not PO or whatever you use for 850s.
- Build the BSR segment. BSR's purpose is to indicate the beginning of an Order Status Report Transaction Set, and BSR01 carries the Status Report Code and BSR02 the Order/Item Code, both mandatory 1-2 character ID fields. This is where you declare whether the report covers the whole order or selected items.
- Open the HL loop and attach PRF. The PRF segment references the original purchase order number and purchase order date for which status is reported, and this data comes from the BEG segment of the 850. Pull it programmatically. Don't let a user type it.
- Add ISR per line or per order. The Beginning Segment for Order Status Report establishes the core information about the report, while the Hierarchical Level segment structures order and line-item details, and the Item Status Report segment conveys specific status information for individual items, such as whether they are in stock, backordered, or shipped. Note that in several distributor guides the ISR segment is generated at either the order or item level but not at both levels — check your partner's rule before you double-report.
- Attach QTY and DTM. D&H's guide is explicit that ISR01 status is applicable to the quantities in QTY02, and ISR02 carries the date of that status change, so these three fields (status code, date, quantity) have to stay in sync line by line.
- Add carrier detail if the partner expects routing visibility. The report uses the HL and ISR segments to organize and communicate the status of each line item, includes the carrier routing information in the TD5 segment, and references the original purchase order through the PRF segment. Not every partner wants this — plenty of 4010 guides mark TD5 "Not Used" — so confirm before you build the logic.
- Close with SE, then wrap GS/GE and ISA/IEA through your AS2 connection or VAN exactly as you would for any other outbound transaction set.
A real fragment from a distributor-style spec looks like this once PRF and ISR are populated: HL*1**O~ PRF*4501234567**20210801~ ISR*ED*20210805**100~ — hierarchical level for the order, purchase order reference back to PO 4501234567, and an item status report showing status code "ED" (expect to ship by) with a date and quantity.
How You Know It Worked
Success on the wire and success in the buyer's system are two different checkpoints, and conflating them is the single most common mistake with any X12 transaction, not just 870.
First checkpoint: the 997. You should see a functional acknowledgement come back from the buyer's EDI system confirming the envelope and segments parsed cleanly. This is a syntax check only — it says nothing about whether the buyer's merchandising or procurement system accepted the content.
Second checkpoint: the buyer's portal. Log into the partner's EDI dashboard (SPS Commerce, TrueCommerce, or whatever platform they run) and confirm the status report posted against the correct PO number, not a duplicate or an orphaned record.
Third checkpoint: content-level rejection codes. A clean 997 can still hide a problem the buyer's application layer catches later — mismatched PO reference, an unrecognized status code, or a quantity that doesn't reconcile against the open order balance. If your partner uses 999 implementation acknowledgements on top of 997s, check those too before you mark the transaction closed.
Common Failure Mode: Orphaned Status Reports
The most frequent rejection pattern with 870s has nothing to do with segment syntax and everything to do with one mismatched reference number. If the PRF value doesn't exactly match the buyer's original PO number — including any suffix, dash, or revision letter the buyer's system expects — the report lands with no PO to attach to. It sits in the buyer's queue as an unmatched document, and nobody notices until someone asks why the status never updated.
The fix is almost embarrassingly simple: pull PRF directly from the stored inbound 850 record, field for field, rather than letting anyone re-key or reformat it. Validate the exact format against the partner's implementation guide during testing, not after go-live. CDW's own guide marks PRF "Must use" at the HL loop level specifically because buyers rely on it as the join key back to the original order — treat it with the same rigor you'd apply to a primary key in a database.
Where 870 Fits in the Broader Document Flow
The order-to-cash sequence for most retail and distribution partners runs 850 (purchase order) → 855 or 865 (acknowledgment or change acknowledgment) → 870 (status) → 856 (advance ship notice) → 810 (invoice). The 870 sits in the middle as a visibility layer, not a commitment document — it doesn't change the order, it just reports on it.
If your organization also handles EDIFACT trading partners, the mapping is direct: X12 is used in the USA and by U.S. companies, while much of the rest of the world uses EDIFACT messages, and Order Status Report maps as X12 870 to EDIFACT ORDREP.
Don't confuse 870 with carrier-side shipment status. The 870 reports procurement-level order and line status between buyer and supplier. Transportation visibility — truck location, carrier milestones, transit exceptions — is a different conversation entirely, usually handled through a TMS or carrier-connectivity platform such as MercuryGate, Descartes, Transporeon, or a lighter shipper-facing tool like Cargoson rather than through the 870 itself. Keep those two visibility streams separate in your integration architecture; merging them into one feed is a common source of confused mapping specs down the line.
Next Steps
If you're staring down a new 870 requirement from a distributor, start by pulling their actual implementation guide rather than working from a generic X12 reference. CDW, Insight, and D&H all publish their own 4010-based guides, and the "must use" versus "optional" segment flags differ enough between them that a mapping built for one will fail validation against another. Build your PRF and ISR population logic directly off stored 850 data, confirm your 997 handling is bidirectional if 869 is also in scope, and run a handful of test transactions through your partner's test environment before flipping production traffic on.