https://edi.stateset.com with one illustrative partner, acme-retail, and one PO, 4500012345.
It assumes you know what the gateway is — if not, read the overview and
the quickstart. The focus here is the order of calls, what each response
tells you, and what to do when one does not say what you expected.
Before you start
- A tenant API key, sent as
Authorization: Bearer <key>on every request (the admin token picks a tenant withx-tenant-id, defaultdefault). - Your ISA qualifier and ID (
ZZ/STATESETbelow), the retailer’s, and their X12 version.
{ "success": true, "data": ... }. The outbound document endpoints
do not return JSON: the body is the wire-ready X12 interchange, Content-Type: application/edi-x12.
1
Register the trading partner
A partner is one
TradingPartner object, keyed by the id in the URL. Only the four ISA fields
are required.partner_isa_qualifier + partner_isa_id is how inbound documents are routed: the gateway reads
the ISA sender of whatever arrives and looks up the matching partner. ack_sla_hours is the clock
the reconciliation monitor runs for this partner’s 997s, overriding the global EDI_ACK_SLA_HOURS.Before the retailer sends anything real, POST /v1/partners/acme-retail/certification/run-standard
runs the prebuilt retail-baseline pack against this envelope and reports passed per case.An empty
validation block means this partner’s implementation guide accepts everything — right
for a first cycle; tighten it once the retailer’s spec is in hand (Configuration).
Transport is configuration too: moving this partner to AS2, SFTP or a VAN changes nothing below
except who carries the bytes (Transports).2
Receive the 850 and return the 997
The interchange below is adapted from Three things happened. The PO was parsed into a
examples/po.edi in the server repository (PO number and
date changed). Save it as po-4500012345.edi:BEG*00*SA is an original, stand-alone order; PO1 is line 1, twelve each at 24.50, by seller SKU
(SK). To dry-run it first, post the same body to POST /v1/edi/validate/acme-retail: the
ValidationReport says valid: true or names the structural_error / per-document reason, with
no side effects. Then submit it for real — POST /v1/edi/inbound auto-detects the syntax and routes
by ISA sender (POST /v1/edi/inbound/{partner_id} is the route a partner-scoped key may call).Response (abridged)
PurchaseOrder850 and stored in the document
ledger under the reference 4500012345 — the PO number is the handle every later document and trace
uses. An edi.purchase_order.received event was queued in the durable outbox for the StateSet
sequencer (events_queued: 1). And a 997 was generated, acknowledging group 101
(AK1*PO*101) and accepting transaction 0001.Over the HTTP API, returning that 997 to the retailer is your job — it is the ack_997 string. On
the file and SFTP transports the worker writes the .997.edi beside the inbound file for you.3
Acknowledge the order with an 855
The 997 said “we could read it”. The 855 says “we will fill it”, line by line. The response body is the enveloped X12 855 —
po_number,
ack_date and at least one line are required. ack_type is BAK02 (AC accept, AD accept with
detail, RJ reject); each line’s status is ACK01 (IA accepted, IB backordered, IQ quantity
changed, IR rejected).ST*855*0001, the first this partner has been sent.
Behind it the gateway applied the partner’s overlay (if any), minted ISA/GS/ST control numbers
from the per-partner sequence, wrote a sent ledger record, queued the outbound event, recorded
the 855 as pending in acknowledgment reconciliation, and handed it to AS2, AS1 or the outbound
directory if one is configured. Over plain HTTP, delivering the body is up to you.Partial acceptance is still one 855: mark the short line IQ, or IB with status_quantity for
the backordered portion. A declined order is ack_type: "RJ".4
Ship it with an 856
shipment_id (BSN02), ship_date and orders[].po_number are required. Use orders[].cartons —
each carton with its SSCC-18 and contents — for the S→O→P→I hierarchy retailers expect;
orders[].items is for shipments with no carton breakdown.HL*…*P loop with MAN*GM carrying its SSCC, so the barcode on the physical
label and the ASN agree — mint those labels from the same payload with
POST /v1/labels/856/acme-retail/cartons. The ASN is the document retailers charge back on most:
send it when the truck leaves, and make sure the SSCCs here are the ones actually printed.5
Invoice it with an 810
invoice_number, invoice_date, po_number, lines and total_amount are required. Freight,
handling and discounts go in allowances as explicit SAC segments, not folded into unit prices.total_amount lands in TDS with two implied decimals.
Twelve × 24.50 plus 15.00 freight is 309.00 — the gateway does not compute the total, and a total
that does not foot is the classic short-pay trigger.6
Close the loop: the retailer's 997, reconciliation, and the trace
Every outbound document is pending until the retailer’s 997 names it.
Post it to The trace lists every event carrying that reference, oldest first.
GET /v1/reconciliation?outstanding=true now shows three OutboundAck rows for acme-retail —
sets 855, 856, 810, each with its ST control_number and status: "pending" — and
outstanding: 3 on the envelope.The retailer’s 997 arrives through the same inbound door as their 850. This one accepts the 855
(adapted from the reconciliation test in tests/http_api.rs):POST /v1/edi/inbound exactly as you posted the 850. FA groups are never themselves
acknowledged (ack_997 is null) and queue no event; the gateway matches AK2*855*0001 against
the pending 855 by set + ST control number and maps AK5 to a status — A → accepted, E →
accepted_with_errors, P → partially_accepted, R → rejected. outstanding drops to 2.Finally, trace the chain from the PO’s point of view, and push the queued events to the StateSet
sequencer now instead of waiting for the EDI_FLUSH_SECONDS worker:GET /v1/documents is the same
ledger paged newest-first across partners — each id opens the raw wire, parsed payload,
generated acknowledgment and any validation_issues — and GET /v1/evidence/4500012345 packages
the chain as a compliance bundle when a chargeback needs answering.Where errors surface
Reprocess and replay are idempotent: event IDs derive from (partner, ISA13, GS06, ST02), so re-deriving
events from the same wire collapses in the outbox and at the sequencer.
Troubleshooting
The 850 came back rejected with 'not configured to send'
The 850 came back rejected with 'not configured to send'
The partner’s
validation.accepted_inbound does not include 850. That list is an allow-list:
once non-empty, every set not in it is rejected in the 997 with AK5*R. Add 850 (and 860 if
the retailer sends changes) with another PUT /v1/partners/acme-retail, then POST /v1/documents/{id}/reprocess the stored document — it re-validates against the current guide and
issues a fresh 997.My 855 / 856 / 810 has been pending for days
My 855 / 856 / 810 has been pending for days
Two problems look the same here. On AS2, check
GET /v1/deliveries first — a failed or
long-pending delivery means the retailer never received the document, so no 997 is coming;
redeliver it. If it is delivered (or the file demonstrably landed), the retailer is simply late,
and ?overdue=true will say so once ack_sla_hours has elapsed.The retailer's 997 arrived but reconciliation still shows pending
The retailer's 997 arrived but reconciliation still shows pending
Matching is by (partner, transaction set, ST control number) — the
AK2 pair. Open the inbound 997
with GET /v1/documents/{id} and compare its AK2*855*0001 with the pending OutboundAck’s
control_number. Padded or truncated control numbers, or a 997 sent under a different ISA sender
than the partner record, will not match.What you built
Every call above is also an MCP tool with the same handler behind it; the server’s
edi_demo_order_to_invoice_flow tool runs this cycle in one shot — see the EDI MCP server.
Next steps
Move the partner to AS2 or SFTP
Add an
as2 or SFTP configuration to the same partner record; the pipeline above does not change.Label the cartons
One GS1-128 / SSCC-18 ZPL label per carton, minted from the same 856 payload.
Operate it
Business reconciliation, evidence bundles, deductions, monitoring and alerting.
Every transaction set
860 changes, 865 change acks, 940/945 warehouse flows, 820 remittance, and the EDIFACT pair.