850 in Python
Send an EDI 850 purchase order in Python
Quick answer
Do I need a Python X12 library?
Why Python teams use an EDI API
Retailers still mandate X12 850 purchase orders, but your fulfillment stack speaks Python and JSON. SignalEDI validates the payload, maps to partner-specific X12, and routes over AS2 or SFTP — you never maintain positional segment rules in your repo.
- POST /api/v1/documents/outbound
- Validation errors return field-level paths
- Partner 997 acks arrive as document.partner_ack webhooks
Working example
Replace partnerId and line SKUs with values from your partner profile. The same pattern works for 855 acknowledgements and other outbound types — swap documentTypeCode and payload shape.
import os
import requests
r = requests.post(
"https://api.signaledi.com/v1/documents/outbound",
headers={"Authorization": f"Bearer {os.environ['SIGNALEDI_API_KEY']}"},
json={
"partnerId": "your-partner-id",
"documentTypeCode": "850",
"payload": {
"purchaseOrderNumber": "PO-1042",
"shipTo": {"id": "DC-01", "name": "RetailMart DC 01"},
"lines": [{"lineNumber": 1, "sku": "SKU-100", "quantity": 24, "unitPrice": 12.5}],
},
},
)
print(r.json())Expected API response
A successful enqueue returns HTTP 202 with a documentId. Track status in the dashboard or via webhooks — do not block your worker on partner mailbox latency.
{
"ok": true,
"documentId": "doc_01HXYZ…",
"status": "queued"
}Map segments when debugging rejects
When a partner 997 rejects your 850, cross-reference BEG and PO1 segments in the X12 reference. Common fixes: PO number format, UOM codes, and product ID qualifiers.
- BEG03 purchase order number must match partner spec
- PO1 quantity and UOM drive chargeback risk on downstream 856
- See /edi/x12/segment/BEG and /edi/x12/segment/PO1
FAQ
Common questions
No for the SignalEDI path — you send JSON; SignalEDI generates compliant X12 per partner profile.
Use sandbox partner profiles and capture 997 webhooks as evidence. See /developers/guides/go-live-checklist.