# EDI Order Parser (X12 850 and EDIFACT ORDERS to JSON/CSV) (`madrasco/edi-order-parser`) Actor

Parses X12 850 purchase orders and UN/EDIFACT ORDERS messages into plain JSON and CSV, with a per-message check of envelopes, control numbers, segment counts, required segments, dates and numbers. No EDI software needed.

- **URL**: https://apify.com/madrasco/edi-order-parser.md
- **Developed by:** [Jack Valmadre](https://apify.com/madrasco) (community)
- **Categories:** Developer tools, E-commerce, Integrations
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## EDI Order Parser (X12 850 and EDIFACT ORDERS to JSON/CSV)

Turn **EDI purchase orders** into data you can use without EDI software. Give the actor **ANSI X12 850** purchase orders or **UN/EDIFACT ORDERS** messages (paste them, link them, or upload them to a key-value store) and get:

- **one dataset row per message** with the order mapped to plain JSON: order number, dates, parties and addresses, references, currency, and every line item with IDs, description, quantity, unit and price;
- **orders.csv**: one row per order line, ready for a spreadsheet or an import into your ERP or accounting system;
- **a structural check of every message** (errors and warnings with segment, position and element), plus a Markdown report per file.

The standard is detected automatically. Delimiters are read from the ISA segment (X12) or the UNA segment (EDIFACT, with the default `:+.? '` when UNA is absent); the EDIFACT release character is handled. One file can hold several interchanges, groups and messages.

### What it checks

**X12 envelopes** (any transaction set)

- ISA is 16 elements and 106 characters, each element at its fixed width; ISA09 date, ISA10 time, ISA12 version and ISA13 control number are well formed; ISA14 is 0 or 1; ISA15 is P or T (warning otherwise).
- GS has 8 elements, a valid date (CCYYMMDD from version 004 on) and time, a 1-9 digit control number.
- ST02 is 4-9 characters; **SE01 equals the real segment count** and SE02 matches ST02; **GE01 equals the number of transaction sets** and GE02 matches GS06; **IEA01 equals the number of groups** and IEA02 matches ISA13.
- Missing trailers, stray segments outside a transaction set, and an 850 sent in a group other than PO.

**X12 850 purchase orders**

- BEG present and first, with purpose code, order type, PO number and a valid date.
- At least one PO1; quantity and unit price are numbers; a unit is given with a quantity; product ID qualifiers and values come in pairs.
- **CTT01 equals the number of PO1 lines**; CTT02 hash total compared with the sum of quantities (warning).
- For version 004010, a few element lengths published in public implementation guides (BEG03, PO101-PO104, N102, N104, REF02, CTT01, PID05) (warnings).

**EDIFACT envelopes** (any message type)

- UNB syntax identifier and version, sender and recipient, date and time, control reference; UNG/UNE group reference.
- UNH message reference and message identifier (type, version, release, agency); **UNT segment count equals the real count** and UNT reference matches UNH; **UNE and UNZ counts** and references match.
- Characters outside the UNOA or UNOB character set declared in UNB (warning).

**EDIFACT ORDERS**

- BGM present and directly after UNH; at least one header DTM; UNS+S present; LIN not after UNS.
- DTM values match their format code (101, 102, 203, 204); QTY, PRI and MOA values are numbers; NAD has a party function.
- CNT+2 line count equals the number of LIN segments; lines without a quantity (warning).
- A few data element lengths from the UN/EDIFACT D.96A directory (warnings; later directories allow some longer values).

Each message gets a result: **pass**, **pass-with-warnings** or **fail**.

### What it does not do

- It does **not** check your trading partner's own implementation guide (their required segments, code values or business rules). It checks the envelope structure and the openly documented basics listed above. Code lists (qualifiers, units, party codes) are not validated.
- Other document types (invoices, ship notices, etc.) are read and their envelopes checked, but only 850 and ORDERS are mapped; turn on **Include raw segments** to get every segment of any message as JSON.
- It does not send or receive EDI (no AS2, VAN or SFTP) and does not create acknowledgements (997/CONTRL).

**This actor does not certify that a message complies with any standard, guideline or trading-partner requirement.** It runs a fixed list of automated checks and can miss problems. Check the mapped data before you ship goods or send invoices based on it.

### Input

| Field | What to put there |
|---|---|
| EDI files (pasted) | A list of `{"name": "...", "text": "..."}` objects or plain strings |
| File URLs | Links to EDI files reachable without a login |
| Key-value store | A store in your account with uploaded EDI files (all records, or only the keys you list) |
| Include raw segments | Adds every segment of each message to its dataset row |
| Maximum file size (MB) | Applies to pasted text, URLs and key-value store records; larger files are reported as load failures (default 10, maximum 20) |

### Output

Dataset row (one per message), shortened:

```json
{
  "file": "po-1001.edi", "status": "parsed", "standard": "X12", "messageType": "850",
  "messageControlNumber": "0001", "version": "004010", "sender": "BUYER", "receiver": "SUPPLIER",
  "conformance": "fail", "errors": 1, "warnings": 0,
  "issues": [{"severity": "error", "code": "se-count", "segment": "SE", "position": 9, "element": "SE01",
              "message": "SE01 says 8 segments; the transaction set has 7 (ST to SE inclusive)."}],
  "order": {"orderNumber": "PO-1001", "orderDate": "20260901",
            "parties": [{"role": "ST", "name": "EXAMPLE STORE 12", "idQualifier": "92", "id": "0012"}],
            "lines": [{"lineNumber": "1", "quantity": "24", "unit": "EA", "unitPrice": "3.50",
                       "productIds": [{"qualifier": "VN", "id": "SKU-100"}, {"qualifier": "UP", "id": "012345678905"}],
                       "description": "BLUE MUG"}]}
}
```

Key-value store: `orders.csv` (all order lines), `OUTPUT` (run summary per file, including the list of CSV keys) and `NNN-<file>.report.md` (issues per message). If the order lines exceed about 25 MB of CSV, they continue in `orders-2.csv`, `orders-3.csv` and so on, each with its own header row.

### Limits and memory

Files are parsed one message at a time, so memory depends mostly on the largest single file, not on how many files you give (up to 1,000 per run).

- **About 10 MB of file per 256 MB of run memory.** Measured on the Apify platform at the default 256 MB: a generated 10 MB X12 file of about 6,100 ordinary orders (20 line items each) peaked at 122 MB and stayed flat through the run. Parsing alone (measured outside the platform) peaked at about 40 MB (X12) and 65 MB (EDIFACT) for 10 MB files and about 60 MB and 105 MB for 20 MB files.
- The default 256 MB handles files up to the default 10 MB limit. For files up to the 20 MB maximum, set the run memory to 512 MB.
- A single message with more than 40,000 segments (about 20,000 X12 line items or 10,000 EDIFACT line items) is checked for envelope structure only and not mapped; its row carries a `message-too-large` warning. This keeps memory bounded for unusually large orders.
- A dataset row is limited to 9 MB by the platform. If a row would be larger (usually only with **Include raw segments**), the raw segments are left out and then order lines are trimmed in that row (`linesTruncated` says how many); every line is still in `orders.csv`.

Values are kept as they appear in the file (text), so nothing is lost to number or date conversion.

### Privacy

The actor reads only the files you give it and writes results to your own Apify storage. Purchase orders can contain names and addresses of businesses and contacts; they are not sent anywhere else.

### Support

Open an issue on the actor's Issues tab. This actor is built and maintained with AI assistance by Madrasco; a human owner can be reached on request through the Issues tab.

# Actor input Schema

## `ediFiles` (type: `array`):

Paste EDI text directly: a list of objects {"name": "po-1001.edi", "text": "ISA*00*..."}, or a list of strings. X12 and EDIFACT are detected automatically; one file may hold several interchanges.

## `urls` (type: `array`):

Links to EDI files (plain text). Must be reachable without a login.

## `keyValueStoreId` (type: `string`):

Pick a key-value store in your Apify account holding EDI files (for example uploaded through the Storage tab). Every record is read, unless you list keys below.

## `keys` (type: `array`):

Optional: record keys to read from the key-value store above.

## `includeSegments` (type: `boolean`):

Also put every segment (tag and element values) of each message in the dataset row, for messages or fields the order mapping does not cover.

## `maxDownloadMb` (type: `integer`):

Applies to pasted text, downloaded URLs and key-value store records alike: larger files are reported as a load failure. The default 10 MB fits the default 256 MB run memory; for files up to 20 MB, set the run memory to 512 MB.

## Actor input object example

```json
{
  "ediFiles": [
    {
      "name": "example-850.edi",
      "text": "ISA*00*          *00*          *ZZ*BUYER          *ZZ*SUPPLIER       *260901*1200*U*00401*000000101*0*T*>~\nGS*PO*BUYER*SUPPLIER*20260901*1200*101*X*004010~\nST*850*0001~\nBEG*00*SA*PO-1001**20260901~\nN1*ST*EXAMPLE STORE 12*92*0012~\nPO1*1*24*EA*3.50**VN*SKU-100*UP*012345678905~\nPID*F****BLUE MUG~\nCTT*1*24~\nSE*7*0001~\nGE*1*101~\nIEA*1*000000101~"
    }
  ],
  "includeSegments": false,
  "maxDownloadMb": 10
}
```

# Actor output Schema

## `messages` (type: `string`):

One dataset row per purchase-order message with parties, dates, lines and check results (the Issues view lists each check finding).

## `files` (type: `string`):

Order-line CSV files and a Markdown check report for each input file.

## `summary` (type: `string`):

Counts of files, messages and issues.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "ediFiles": [
        {
            "name": "example-850.edi",
            "text": "ISA*00*          *00*          *ZZ*BUYER          *ZZ*SUPPLIER       *260901*1200*U*00401*000000101*0*T*>~\nGS*PO*BUYER*SUPPLIER*20260901*1200*101*X*004010~\nST*850*0001~\nBEG*00*SA*PO-1001**20260901~\nN1*ST*EXAMPLE STORE 12*92*0012~\nPO1*1*24*EA*3.50**VN*SKU-100*UP*012345678905~\nPID*F****BLUE MUG~\nCTT*1*24~\nSE*7*0001~\nGE*1*101~\nIEA*1*000000101~"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("madrasco/edi-order-parser").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "ediFiles": [{
            "name": "example-850.edi",
            "text": """ISA*00*          *00*          *ZZ*BUYER          *ZZ*SUPPLIER       *260901*1200*U*00401*000000101*0*T*>~
GS*PO*BUYER*SUPPLIER*20260901*1200*101*X*004010~
ST*850*0001~
BEG*00*SA*PO-1001**20260901~
N1*ST*EXAMPLE STORE 12*92*0012~
PO1*1*24*EA*3.50**VN*SKU-100*UP*012345678905~
PID*F****BLUE MUG~
CTT*1*24~
SE*7*0001~
GE*1*101~
IEA*1*000000101~""",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("madrasco/edi-order-parser").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "ediFiles": [
    {
      "name": "example-850.edi",
      "text": "ISA*00*          *00*          *ZZ*BUYER          *ZZ*SUPPLIER       *260901*1200*U*00401*000000101*0*T*>~\\nGS*PO*BUYER*SUPPLIER*20260901*1200*101*X*004010~\\nST*850*0001~\\nBEG*00*SA*PO-1001**20260901~\\nN1*ST*EXAMPLE STORE 12*92*0012~\\nPO1*1*24*EA*3.50**VN*SKU-100*UP*012345678905~\\nPID*F****BLUE MUG~\\nCTT*1*24~\\nSE*7*0001~\\nGE*1*101~\\nIEA*1*000000101~"
    }
  ]
}' |
apify call madrasco/edi-order-parser --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,madrasco/edi-order-parser"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/TX2P3aRdmVRvbzn4J/builds/mC75qiUiKJX0lRQpp/openapi.json
