Getting started with the X12 file format
Jun 22, 2022
EDI
This post mentions Stedi’s EDI Core API. Converting EDI into JSON remains a key Stedi offering, however EDI Core API has been superseded by Stedi Core, an event-driven EDI system that allows you to configure integrations without being an EDI or development expert.
This document is the tl;dr of EDI. It won’t contain everything. It may not answer all your questions. It will only apply to X12. But it will save you a ton of time if you’re trying to decipher your first EDI document.
For this document, I’ll be using an 856 Ship Notice as an example. If you’re wondering what the heck an 856 Ship Notice is, you’re in the right place. Anyway, here’s the example.
ISA*00* *00* *ZZ*MYORG *ZZ*Interchange Rec*200831*2324*U*00501*100030537*0*P*>~
GS*SH*MYORG*Interchange Rec*20200831*2324*200030537*X*005010~
ST*856*300089443~
BSN*00*P1982123*20200831*2324*0001~
DTM*011*20200831*2324~
HL*1**S~
TD1*CTN*1****G*2*LB~
TD5**2*FDE*U********3D*3D*3D~
DTM*011*20200831~
N1*ST*SOO KIM*92*DROPSHIP CUSTOMER~
N3*26218 QUENTIN TURNPIKE~
N4*REANNAFORT*MS*51135~
HL*2*1*O~
PRF*1881225***20200831~
HL*3*2*P~
MAN*CP*037178019302492~
HL*4*3*I~
LIN*1*VC*11216.32*SK*RGR-11216.32~
SN1*1*1*EA~
PID*F****ALL TERRAIN ENTRY GUARD KIT 2020 JEEP WRANGLER J~
CTT*4~
SE*20*300089443~
GE*1*200030537~
IEA*1*100030537
What is EDI?
EDI a structured way for businesses to send documents back and forth. It can be:
a purchase order (“I want to buy this!”),
an invoice (“Pay me for this!”),
a ship notice (“I sent you this!”),
or any of 300+ other transaction types.
Think of it as a JSON Schema to cover all possible business transactions and details, but before JSON, or XML, or the World Wide Web were invented.
You might hear people talk about X12 EDI. This is just a specific format of EDI. Another common one is EDIFACT. We’ll focus on X12 EDI here.
You might also hear of 5010 or 4010 . These are specific versions (formally known as releases) of EDI. Think of a versioned API, which might have small but breaking changes as you increase versions. EDI is an old standard and it required some changes over the years.
Structure
Segments, elements, and separators
When you first look at the 856 Ship Notice, you’ll see the following:
ISA*00* *00* *ZZ*MYORG *ZZ*Interchange Rec*200831*2324*U*00501*100030537*0*P*>~
GS*SH*MYORG*Interchange Rec*20200831*2324*200030537*X*005010~
ST*856*300089443~
BSN*00*P1982123*20200831*2324*0001~
DTM*011*20200831*2324~
…
This feels overwhelming. Don’t let it be.
Notice that the example of this particular EDI document is split into 5 lines. (The full document has 24 lines, as you can see at the start of the article.) Each line is called a segment. Each segment is broken into multiple elements.
Let’s start by breaking down what’s happening on line 1.
It starts with
ISA
. This is the segment name. We’ll often refer to the segment by its name. “Ohh, they’re missing an ABC segment”, or “That’s an invalid value in the XYZ segment”. This is the ISA segment.There are a bunch of letters and numbers separated by
*
. An asterisk serves as a separator between elements (technically, the fourth character—right afterISA
—is the element separator, but it’s commonly a*
). Elements are often referred to by their numerical index within a particular segment. For example, notice the200831
near the end of the ISA segment. That is called ISA09 as it is the ninth element in the ISA segment. When you look at the definition of the segment, you’ll see that it refers to the Interchange Date in YYMMDD format. Thus,200831
is August 31, 2020.
In the file we’ve looked at so far, each segment is on a different line. Sometimes you’ll get a file that’s all on one line. EDI documents will generally use ~
or a newline \n
to distinguish between segments. (It’s technically the 105th byte in the ISA
segment.) When reviewing a document, I find it much easier to split it into new lines based on the segment delimiter.
Common segments
Now that we know the basics of segments, elements, and separators, let’s look at some common segments. Specifically, we’re going to look at ISA
, GS
, and ST
.
ISA
We looked at the ISA segment in the previous section. This will always be the first line in an EDI document. It’s called an interchange and contains metadata that applies to the document as a whole. This includes the document’s date and time, a control number (similar to an auto-incrementing primary key), whether it’s a test document, and more.
Typically, there’s only one ISA segment in a document, but some organizations combine multiple EDI documents into one.
GS
The GS segment will always be next. It’s the functional group and it includes additional metadata about the transactions within the group. The most important value is the last one (GS08) which indicates the X12 version that is used by the document. In the example above, the value of this element is 005010
. That indicates it’s using the 5010 version.
The X12 spec allows multiple functional groups in a single document.
ST
The ST segment is for the actual transaction being sent. This is the star of the show and the reason we’re all here. It could be an invoice, a purchase order, or any other of the many transaction types.
Each functional group can have multiple transactions.
ST01 identifies the transaction type for the given transaction. In the example above, it says 856
, which maps to a ship notice.
Other common transaction types are:
Closing segments
Finally, for each of these key sections, there is a closing segment (formally a trailer segment) to indicate when they end. These closing segments include a checksum and a control number.
The code fragment above shows the last three lines of our ship notice example. The SE segment indicates the end of the ST block. SE01 refers to the number of segments within the ST block. The value 20
indicates there were 20 segments in that transaction. SE02 is a control number that matches the control number from the ST segment.
Likewise, the GE segment indicates the end of the functional group, which started with GS. GE01 states how many transactions were included within the functional group, and GE02 is a control number for the group. Same thing with IEA which closes the ISA block.
Implementation guides
The X12 spec is expansive, and most companies don’t need all of it. Accordingly, companies will limit what they support. The terms may be dictated and standardized by the trading partner with the most market power, or it may be by mutual agreement between the two trading partners.
As a result, you may get an implementation guide indicating what is supported by a your trading partner. We’ll take a look at an example for a mapping guide for an 856 Ship Notice. There are two kinds of pages here: the overview page, and the segment detail page.
Overview
The overview page shows all the segments that are allowed in this particular transaction.
The Req column shows whether a segment is mandatory (M) or optional (O).
For this transaction, only two segments are optional.
The Max Use column shows the maximum number of times a segment can be repeated.
For example, the DTM segment can be used up to 10 times, which means a ship notice can have 10 dates associated with it.
A loop is a collection of segments that can be repeated, in this case up to 200 times.
A loop can also contain other loops.
Note that repeats are multiplicative. The top-level loop can be repeated 200,000 times and the inner loop 200 times, so the N1, N3, and N4 segment can be included 200,000 × 200 = 40,000,000 times.
Another look at the example document shows multiple iterations of the HL loop.
Details
The overview usually doesn’t take up more than a page or two. The rest of the implementation guide is made up of segment detail pages. Here’s one for the PRF segment.
The details page describes each element within the segment.
For example, the PRF01 segment is mandatory and can have at most 22 characters.
The PRF06 segment is optional and can have at most 30 characters.
At times, an element will accept a small number of codes that map to specific values, similar to an enum. You can see an example of that on the details page for DTM.
Transforming EDI
So far, we’ve looked at a raw EDI document and you may have noticed that the format is hard to use with your favorite programming language. It would take a lot of string parsing, array indexing, and other tedium. Stedi offers an EDI parser, converter, and validator called EDI Core.
We can take our EDI example and give it to EDI Core. EDI Core will return a JSON representation of the EDI that we call JEDI.
{
"interchanges": [
{
"interchange_control_header_ISA": {
"authorization_information_qualifier_01": "no_authorization_information_present_no_meaningful_information_in_i02_00",
"authorization_information_02": "",
"security_information_qualifier_03": "no_security_information_present_no_meaningful_information_in_i04_00",
"security_information_04": "",
"interchange_id_qualifier_05": "mutually_defined_ZZ",
"interchange_sender_id_06": "MYORG",
"interchange_id_qualifier_07": "mutually_defined_ZZ",
"interchange_receiver_id_08": "Interchange Rec",
"interchange_date_09": "200831",
"interchange_time_10": "2324",
"repetition_separator_11": "U",
"interchange_control_version_number_12": "00501",
"interchange_control_number_13": "100030537",
"acknowledgment_requested_14": "no_interchange_acknowledgment_requested_0",
"interchange_usage_indicator_15": "production_data_P",
"component_element_separator_16": ">"
},
"groups": [
{
"functional_group_header_GS": {
"functional_identifier_code_01": "ship_notice_manifest_856_SH",
"application_senders_code_02": "MYORG",
"application_receivers_code_03": "Interchange Rec",
"date_04": "20200831",
"time_05": "2324",
"group_control_number_06": "200030537",
"responsible_agency_code_07": "accredited_standards_committee_x12_X",
"version_release_industry_identifier_code_08": "005010"
},
"transaction_sets": [
{
"set": "856",
"heading": {
"transaction_set_header_ST": {
"transaction_set_identifier_code_01": "856",
"transaction_set_control_number_02": "300089443"
},
"beginning_segment_for_ship_notice_BSN": {
"transaction_set_purpose_code_01": "original_00",
"shipment_identification_02": "P1982123",
"date_03": "20200831",
"time_04": "2324",
"hierarchical_structure_code_05": "shipment_order_packaging_item_0001"
},
"date_time_reference_DTM": [
{
"date_time_qualifier_01": "shipped_011",
"date_02": "20200831",
"time_03": "2324"
}
]
},
"detail": {
"hierarchical_level_HL_loop": [
{
"hierarchical_level_HL": {
"hierarchical_id_number_01": "1",
"hierarchical_level_code_03": "shipment_S"
},
"carrier_details_quantity_and_weight_TD1": [
{
"packaging_code_01": "CTN",
"lading_quantity_02": "1",
"weight_qualifier_06": "gross_weight_G",
"weight_07": "2",
"unit_or_basis_for_measurement_code_08": "pound_LB"
}
],
"carrier_details_routing_sequence_transit_time_TD5": [
{
"identification_code_qualifier_02": "standard_carrier_alpha_code_scac_2",
"identification_code_03": "FDE",
"transportation_method_type_code_04": "private_parcel_service_U",
"service_level_code_12": "three_day_service_3D",
"service_level_code_13": "three_day_service_3D",
"service_level_code_14": "three_day_service_3D"
}
],
"date_time_reference_DTM": [
{
"date_time_qualifier_01": "shipped_011",
"date_02": "20200831"
}
],
"party_identification_N1_loop": [
{
"party_identification_N1": {
"entity_identifier_code_01": "ship_to_ST",
"name_02": "SOO KIM",
"identification_code_qualifier_03": "assigned_by_buyer_or_buyers_agent_92",
"identification_code_04": "DROPSHIP CUSTOMER"
},
"party_location_N3": [
{
"address_information_01": "26218 QUENTIN TURNPIKE"
}
],
"geographic_location_N4": {
"city_name_01": "REANNAFORT",
"state_or_province_code_02": "MS",
"postal_code_03": "51135"
}
}
]
},
{
"hierarchical_level_HL": {
"hierarchical_id_number_01": "2",
"hierarchical_parent_id_number_02": "1",
"hierarchical_level_code_03": "order_O"
},
"purchase_order_reference_PRF": {
"purchase_order_number_01": "1881225",
"date_04": "20200831"
}
},
{
"hierarchical_level_HL": {
"hierarchical_id_number_01": "3",
"hierarchical_parent_id_number_02": "2",
"hierarchical_level_code_03": "pack_P"
},
"marks_and_numbers_information_MAN": [
{
"marks_and_numbers_qualifier_01": "carrier_assigned_package_id_number_CP",
"marks_and_numbers_02": "037178019302492"
}
]
},
{
"hierarchical_level_HL": {
"hierarchical_id_number_01": "4",
"hierarchical_parent_id_number_02": "3",
"hierarchical_level_code_03": "item_I"
},
"item_identification_LIN": {
"assigned_identification_01": "1",
"product_service_id_qualifier_02": "vendors_sellers_catalog_number_VC",
"product_service_id_03": "11216.32",
"product_service_id_qualifier_04": "stock_keeping_unit_sku_SK",
"product_service_id_05": "RGR-11216.32"
},
"item_detail_shipment_SN1": {
"assigned_identification_01": "1",
"number_of_units_shipped_02": "1",
"unit_or_basis_for_measurement_code_03": "each_EA"
},
"product_item_description_PID": [
{
"item_description_type_01": "free_form_F",
"description_05": "ALL TERRAIN ENTRY GUARD KIT 2020 JEEP WRANGLER J"
}
]
}
]
},
"summary": {
"transaction_totals_CTT": {
"number_of_line_items_01": "4"
},
"transaction_set_trailer_SE": {
"number_of_included_segments_01": "20",
"transaction_set_control_number_02": "300089443"
}
}
}
],
"functional_group_trailer_GE": {
"number_of_transaction_sets_included_01": "1",
"group_control_number_02": "200030537"
},
"release": "005010"
}
],
"interchange_control_trailer_IEA": {
"number_of_included_functional_groups_01": "1",
"interchange_control_number_02": "100030537"
},
"delimiters": {
"element": "*",
"segment": "~",
"sub_element": ">"
}
}
],
"__version": "jedi@2.0"
}
This is more verbose, but it’s much easier to deal with from code. You can see the EDI and the JSON side-by-side by using the Inspector. It’ll show an explanation of each segment, too.
Getting started
This is certainly not all you need to know, but it’s enough to get you started. Don’t forget to check out our blog for more information on working with EDI.
This post mentions Stedi’s EDI Core API. Converting EDI into JSON remains a key Stedi offering, however EDI Core API has been superseded by Stedi Core, an event-driven EDI system that allows you to configure integrations without being an EDI or development expert.
This document is the tl;dr of EDI. It won’t contain everything. It may not answer all your questions. It will only apply to X12. But it will save you a ton of time if you’re trying to decipher your first EDI document.
For this document, I’ll be using an 856 Ship Notice as an example. If you’re wondering what the heck an 856 Ship Notice is, you’re in the right place. Anyway, here’s the example.
ISA*00* *00* *ZZ*MYORG *ZZ*Interchange Rec*200831*2324*U*00501*100030537*0*P*>~
GS*SH*MYORG*Interchange Rec*20200831*2324*200030537*X*005010~
ST*856*300089443~
BSN*00*P1982123*20200831*2324*0001~
DTM*011*20200831*2324~
HL*1**S~
TD1*CTN*1****G*2*LB~
TD5**2*FDE*U********3D*3D*3D~
DTM*011*20200831~
N1*ST*SOO KIM*92*DROPSHIP CUSTOMER~
N3*26218 QUENTIN TURNPIKE~
N4*REANNAFORT*MS*51135~
HL*2*1*O~
PRF*1881225***20200831~
HL*3*2*P~
MAN*CP*037178019302492~
HL*4*3*I~
LIN*1*VC*11216.32*SK*RGR-11216.32~
SN1*1*1*EA~
PID*F****ALL TERRAIN ENTRY GUARD KIT 2020 JEEP WRANGLER J~
CTT*4~
SE*20*300089443~
GE*1*200030537~
IEA*1*100030537
What is EDI?
EDI a structured way for businesses to send documents back and forth. It can be:
a purchase order (“I want to buy this!”),
an invoice (“Pay me for this!”),
a ship notice (“I sent you this!”),
or any of 300+ other transaction types.
Think of it as a JSON Schema to cover all possible business transactions and details, but before JSON, or XML, or the World Wide Web were invented.
You might hear people talk about X12 EDI. This is just a specific format of EDI. Another common one is EDIFACT. We’ll focus on X12 EDI here.
You might also hear of 5010 or 4010 . These are specific versions (formally known as releases) of EDI. Think of a versioned API, which might have small but breaking changes as you increase versions. EDI is an old standard and it required some changes over the years.
Structure
Segments, elements, and separators
When you first look at the 856 Ship Notice, you’ll see the following:
ISA*00* *00* *ZZ*MYORG *ZZ*Interchange Rec*200831*2324*U*00501*100030537*0*P*>~
GS*SH*MYORG*Interchange Rec*20200831*2324*200030537*X*005010~
ST*856*300089443~
BSN*00*P1982123*20200831*2324*0001~
DTM*011*20200831*2324~
…
This feels overwhelming. Don’t let it be.
Notice that the example of this particular EDI document is split into 5 lines. (The full document has 24 lines, as you can see at the start of the article.) Each line is called a segment. Each segment is broken into multiple elements.
Let’s start by breaking down what’s happening on line 1.
It starts with
ISA
. This is the segment name. We’ll often refer to the segment by its name. “Ohh, they’re missing an ABC segment”, or “That’s an invalid value in the XYZ segment”. This is the ISA segment.There are a bunch of letters and numbers separated by
*
. An asterisk serves as a separator between elements (technically, the fourth character—right afterISA
—is the element separator, but it’s commonly a*
). Elements are often referred to by their numerical index within a particular segment. For example, notice the200831
near the end of the ISA segment. That is called ISA09 as it is the ninth element in the ISA segment. When you look at the definition of the segment, you’ll see that it refers to the Interchange Date in YYMMDD format. Thus,200831
is August 31, 2020.
In the file we’ve looked at so far, each segment is on a different line. Sometimes you’ll get a file that’s all on one line. EDI documents will generally use ~
or a newline \n
to distinguish between segments. (It’s technically the 105th byte in the ISA
segment.) When reviewing a document, I find it much easier to split it into new lines based on the segment delimiter.
Common segments
Now that we know the basics of segments, elements, and separators, let’s look at some common segments. Specifically, we’re going to look at ISA
, GS
, and ST
.
ISA
We looked at the ISA segment in the previous section. This will always be the first line in an EDI document. It’s called an interchange and contains metadata that applies to the document as a whole. This includes the document’s date and time, a control number (similar to an auto-incrementing primary key), whether it’s a test document, and more.
Typically, there’s only one ISA segment in a document, but some organizations combine multiple EDI documents into one.
GS
The GS segment will always be next. It’s the functional group and it includes additional metadata about the transactions within the group. The most important value is the last one (GS08) which indicates the X12 version that is used by the document. In the example above, the value of this element is 005010
. That indicates it’s using the 5010 version.
The X12 spec allows multiple functional groups in a single document.
ST
The ST segment is for the actual transaction being sent. This is the star of the show and the reason we’re all here. It could be an invoice, a purchase order, or any other of the many transaction types.
Each functional group can have multiple transactions.
ST01 identifies the transaction type for the given transaction. In the example above, it says 856
, which maps to a ship notice.
Other common transaction types are:
Closing segments
Finally, for each of these key sections, there is a closing segment (formally a trailer segment) to indicate when they end. These closing segments include a checksum and a control number.
The code fragment above shows the last three lines of our ship notice example. The SE segment indicates the end of the ST block. SE01 refers to the number of segments within the ST block. The value 20
indicates there were 20 segments in that transaction. SE02 is a control number that matches the control number from the ST segment.
Likewise, the GE segment indicates the end of the functional group, which started with GS. GE01 states how many transactions were included within the functional group, and GE02 is a control number for the group. Same thing with IEA which closes the ISA block.
Implementation guides
The X12 spec is expansive, and most companies don’t need all of it. Accordingly, companies will limit what they support. The terms may be dictated and standardized by the trading partner with the most market power, or it may be by mutual agreement between the two trading partners.
As a result, you may get an implementation guide indicating what is supported by a your trading partner. We’ll take a look at an example for a mapping guide for an 856 Ship Notice. There are two kinds of pages here: the overview page, and the segment detail page.
Overview
The overview page shows all the segments that are allowed in this particular transaction.
The Req column shows whether a segment is mandatory (M) or optional (O).
For this transaction, only two segments are optional.
The Max Use column shows the maximum number of times a segment can be repeated.
For example, the DTM segment can be used up to 10 times, which means a ship notice can have 10 dates associated with it.
A loop is a collection of segments that can be repeated, in this case up to 200 times.
A loop can also contain other loops.
Note that repeats are multiplicative. The top-level loop can be repeated 200,000 times and the inner loop 200 times, so the N1, N3, and N4 segment can be included 200,000 × 200 = 40,000,000 times.
Another look at the example document shows multiple iterations of the HL loop.
Details
The overview usually doesn’t take up more than a page or two. The rest of the implementation guide is made up of segment detail pages. Here’s one for the PRF segment.
The details page describes each element within the segment.
For example, the PRF01 segment is mandatory and can have at most 22 characters.
The PRF06 segment is optional and can have at most 30 characters.
At times, an element will accept a small number of codes that map to specific values, similar to an enum. You can see an example of that on the details page for DTM.
Transforming EDI
So far, we’ve looked at a raw EDI document and you may have noticed that the format is hard to use with your favorite programming language. It would take a lot of string parsing, array indexing, and other tedium. Stedi offers an EDI parser, converter, and validator called EDI Core.
We can take our EDI example and give it to EDI Core. EDI Core will return a JSON representation of the EDI that we call JEDI.
{
"interchanges": [
{
"interchange_control_header_ISA": {
"authorization_information_qualifier_01": "no_authorization_information_present_no_meaningful_information_in_i02_00",
"authorization_information_02": "",
"security_information_qualifier_03": "no_security_information_present_no_meaningful_information_in_i04_00",
"security_information_04": "",
"interchange_id_qualifier_05": "mutually_defined_ZZ",
"interchange_sender_id_06": "MYORG",
"interchange_id_qualifier_07": "mutually_defined_ZZ",
"interchange_receiver_id_08": "Interchange Rec",
"interchange_date_09": "200831",
"interchange_time_10": "2324",
"repetition_separator_11": "U",
"interchange_control_version_number_12": "00501",
"interchange_control_number_13": "100030537",
"acknowledgment_requested_14": "no_interchange_acknowledgment_requested_0",
"interchange_usage_indicator_15": "production_data_P",
"component_element_separator_16": ">"
},
"groups": [
{
"functional_group_header_GS": {
"functional_identifier_code_01": "ship_notice_manifest_856_SH",
"application_senders_code_02": "MYORG",
"application_receivers_code_03": "Interchange Rec",
"date_04": "20200831",
"time_05": "2324",
"group_control_number_06": "200030537",
"responsible_agency_code_07": "accredited_standards_committee_x12_X",
"version_release_industry_identifier_code_08": "005010"
},
"transaction_sets": [
{
"set": "856",
"heading": {
"transaction_set_header_ST": {
"transaction_set_identifier_code_01": "856",
"transaction_set_control_number_02": "300089443"
},
"beginning_segment_for_ship_notice_BSN": {
"transaction_set_purpose_code_01": "original_00",
"shipment_identification_02": "P1982123",
"date_03": "20200831",
"time_04": "2324",
"hierarchical_structure_code_05": "shipment_order_packaging_item_0001"
},
"date_time_reference_DTM": [
{
"date_time_qualifier_01": "shipped_011",
"date_02": "20200831",
"time_03": "2324"
}
]
},
"detail": {
"hierarchical_level_HL_loop": [
{
"hierarchical_level_HL": {
"hierarchical_id_number_01": "1",
"hierarchical_level_code_03": "shipment_S"
},
"carrier_details_quantity_and_weight_TD1": [
{
"packaging_code_01": "CTN",
"lading_quantity_02": "1",
"weight_qualifier_06": "gross_weight_G",
"weight_07": "2",
"unit_or_basis_for_measurement_code_08": "pound_LB"
}
],
"carrier_details_routing_sequence_transit_time_TD5": [
{
"identification_code_qualifier_02": "standard_carrier_alpha_code_scac_2",
"identification_code_03": "FDE",
"transportation_method_type_code_04": "private_parcel_service_U",
"service_level_code_12": "three_day_service_3D",
"service_level_code_13": "three_day_service_3D",
"service_level_code_14": "three_day_service_3D"
}
],
"date_time_reference_DTM": [
{
"date_time_qualifier_01": "shipped_011",
"date_02": "20200831"
}
],
"party_identification_N1_loop": [
{
"party_identification_N1": {
"entity_identifier_code_01": "ship_to_ST",
"name_02": "SOO KIM",
"identification_code_qualifier_03": "assigned_by_buyer_or_buyers_agent_92",
"identification_code_04": "DROPSHIP CUSTOMER"
},
"party_location_N3": [
{
"address_information_01": "26218 QUENTIN TURNPIKE"
}
],
"geographic_location_N4": {
"city_name_01": "REANNAFORT",
"state_or_province_code_02": "MS",
"postal_code_03": "51135"
}
}
]
},
{
"hierarchical_level_HL": {
"hierarchical_id_number_01": "2",
"hierarchical_parent_id_number_02": "1",
"hierarchical_level_code_03": "order_O"
},
"purchase_order_reference_PRF": {
"purchase_order_number_01": "1881225",
"date_04": "20200831"
}
},
{
"hierarchical_level_HL": {
"hierarchical_id_number_01": "3",
"hierarchical_parent_id_number_02": "2",
"hierarchical_level_code_03": "pack_P"
},
"marks_and_numbers_information_MAN": [
{
"marks_and_numbers_qualifier_01": "carrier_assigned_package_id_number_CP",
"marks_and_numbers_02": "037178019302492"
}
]
},
{
"hierarchical_level_HL": {
"hierarchical_id_number_01": "4",
"hierarchical_parent_id_number_02": "3",
"hierarchical_level_code_03": "item_I"
},
"item_identification_LIN": {
"assigned_identification_01": "1",
"product_service_id_qualifier_02": "vendors_sellers_catalog_number_VC",
"product_service_id_03": "11216.32",
"product_service_id_qualifier_04": "stock_keeping_unit_sku_SK",
"product_service_id_05": "RGR-11216.32"
},
"item_detail_shipment_SN1": {
"assigned_identification_01": "1",
"number_of_units_shipped_02": "1",
"unit_or_basis_for_measurement_code_03": "each_EA"
},
"product_item_description_PID": [
{
"item_description_type_01": "free_form_F",
"description_05": "ALL TERRAIN ENTRY GUARD KIT 2020 JEEP WRANGLER J"
}
]
}
]
},
"summary": {
"transaction_totals_CTT": {
"number_of_line_items_01": "4"
},
"transaction_set_trailer_SE": {
"number_of_included_segments_01": "20",
"transaction_set_control_number_02": "300089443"
}
}
}
],
"functional_group_trailer_GE": {
"number_of_transaction_sets_included_01": "1",
"group_control_number_02": "200030537"
},
"release": "005010"
}
],
"interchange_control_trailer_IEA": {
"number_of_included_functional_groups_01": "1",
"interchange_control_number_02": "100030537"
},
"delimiters": {
"element": "*",
"segment": "~",
"sub_element": ">"
}
}
],
"__version": "jedi@2.0"
}
This is more verbose, but it’s much easier to deal with from code. You can see the EDI and the JSON side-by-side by using the Inspector. It’ll show an explanation of each segment, too.
Getting started
This is certainly not all you need to know, but it’s enough to get you started. Don’t forget to check out our blog for more information on working with EDI.
This post mentions Stedi’s EDI Core API. Converting EDI into JSON remains a key Stedi offering, however EDI Core API has been superseded by Stedi Core, an event-driven EDI system that allows you to configure integrations without being an EDI or development expert.
This document is the tl;dr of EDI. It won’t contain everything. It may not answer all your questions. It will only apply to X12. But it will save you a ton of time if you’re trying to decipher your first EDI document.
For this document, I’ll be using an 856 Ship Notice as an example. If you’re wondering what the heck an 856 Ship Notice is, you’re in the right place. Anyway, here’s the example.
ISA*00* *00* *ZZ*MYORG *ZZ*Interchange Rec*200831*2324*U*00501*100030537*0*P*>~
GS*SH*MYORG*Interchange Rec*20200831*2324*200030537*X*005010~
ST*856*300089443~
BSN*00*P1982123*20200831*2324*0001~
DTM*011*20200831*2324~
HL*1**S~
TD1*CTN*1****G*2*LB~
TD5**2*FDE*U********3D*3D*3D~
DTM*011*20200831~
N1*ST*SOO KIM*92*DROPSHIP CUSTOMER~
N3*26218 QUENTIN TURNPIKE~
N4*REANNAFORT*MS*51135~
HL*2*1*O~
PRF*1881225***20200831~
HL*3*2*P~
MAN*CP*037178019302492~
HL*4*3*I~
LIN*1*VC*11216.32*SK*RGR-11216.32~
SN1*1*1*EA~
PID*F****ALL TERRAIN ENTRY GUARD KIT 2020 JEEP WRANGLER J~
CTT*4~
SE*20*300089443~
GE*1*200030537~
IEA*1*100030537
What is EDI?
EDI a structured way for businesses to send documents back and forth. It can be:
a purchase order (“I want to buy this!”),
an invoice (“Pay me for this!”),
a ship notice (“I sent you this!”),
or any of 300+ other transaction types.
Think of it as a JSON Schema to cover all possible business transactions and details, but before JSON, or XML, or the World Wide Web were invented.
You might hear people talk about X12 EDI. This is just a specific format of EDI. Another common one is EDIFACT. We’ll focus on X12 EDI here.
You might also hear of 5010 or 4010 . These are specific versions (formally known as releases) of EDI. Think of a versioned API, which might have small but breaking changes as you increase versions. EDI is an old standard and it required some changes over the years.
Structure
Segments, elements, and separators
When you first look at the 856 Ship Notice, you’ll see the following:
ISA*00* *00* *ZZ*MYORG *ZZ*Interchange Rec*200831*2324*U*00501*100030537*0*P*>~
GS*SH*MYORG*Interchange Rec*20200831*2324*200030537*X*005010~
ST*856*300089443~
BSN*00*P1982123*20200831*2324*0001~
DTM*011*20200831*2324~
…
This feels overwhelming. Don’t let it be.
Notice that the example of this particular EDI document is split into 5 lines. (The full document has 24 lines, as you can see at the start of the article.) Each line is called a segment. Each segment is broken into multiple elements.
Let’s start by breaking down what’s happening on line 1.
It starts with
ISA
. This is the segment name. We’ll often refer to the segment by its name. “Ohh, they’re missing an ABC segment”, or “That’s an invalid value in the XYZ segment”. This is the ISA segment.There are a bunch of letters and numbers separated by
*
. An asterisk serves as a separator between elements (technically, the fourth character—right afterISA
—is the element separator, but it’s commonly a*
). Elements are often referred to by their numerical index within a particular segment. For example, notice the200831
near the end of the ISA segment. That is called ISA09 as it is the ninth element in the ISA segment. When you look at the definition of the segment, you’ll see that it refers to the Interchange Date in YYMMDD format. Thus,200831
is August 31, 2020.
In the file we’ve looked at so far, each segment is on a different line. Sometimes you’ll get a file that’s all on one line. EDI documents will generally use ~
or a newline \n
to distinguish between segments. (It’s technically the 105th byte in the ISA
segment.) When reviewing a document, I find it much easier to split it into new lines based on the segment delimiter.
Common segments
Now that we know the basics of segments, elements, and separators, let’s look at some common segments. Specifically, we’re going to look at ISA
, GS
, and ST
.
ISA
We looked at the ISA segment in the previous section. This will always be the first line in an EDI document. It’s called an interchange and contains metadata that applies to the document as a whole. This includes the document’s date and time, a control number (similar to an auto-incrementing primary key), whether it’s a test document, and more.
Typically, there’s only one ISA segment in a document, but some organizations combine multiple EDI documents into one.
GS
The GS segment will always be next. It’s the functional group and it includes additional metadata about the transactions within the group. The most important value is the last one (GS08) which indicates the X12 version that is used by the document. In the example above, the value of this element is 005010
. That indicates it’s using the 5010 version.
The X12 spec allows multiple functional groups in a single document.
ST
The ST segment is for the actual transaction being sent. This is the star of the show and the reason we’re all here. It could be an invoice, a purchase order, or any other of the many transaction types.
Each functional group can have multiple transactions.
ST01 identifies the transaction type for the given transaction. In the example above, it says 856
, which maps to a ship notice.
Other common transaction types are:
Closing segments
Finally, for each of these key sections, there is a closing segment (formally a trailer segment) to indicate when they end. These closing segments include a checksum and a control number.
The code fragment above shows the last three lines of our ship notice example. The SE segment indicates the end of the ST block. SE01 refers to the number of segments within the ST block. The value 20
indicates there were 20 segments in that transaction. SE02 is a control number that matches the control number from the ST segment.
Likewise, the GE segment indicates the end of the functional group, which started with GS. GE01 states how many transactions were included within the functional group, and GE02 is a control number for the group. Same thing with IEA which closes the ISA block.
Implementation guides
The X12 spec is expansive, and most companies don’t need all of it. Accordingly, companies will limit what they support. The terms may be dictated and standardized by the trading partner with the most market power, or it may be by mutual agreement between the two trading partners.
As a result, you may get an implementation guide indicating what is supported by a your trading partner. We’ll take a look at an example for a mapping guide for an 856 Ship Notice. There are two kinds of pages here: the overview page, and the segment detail page.
Overview
The overview page shows all the segments that are allowed in this particular transaction.
The Req column shows whether a segment is mandatory (M) or optional (O).
For this transaction, only two segments are optional.
The Max Use column shows the maximum number of times a segment can be repeated.
For example, the DTM segment can be used up to 10 times, which means a ship notice can have 10 dates associated with it.
A loop is a collection of segments that can be repeated, in this case up to 200 times.
A loop can also contain other loops.
Note that repeats are multiplicative. The top-level loop can be repeated 200,000 times and the inner loop 200 times, so the N1, N3, and N4 segment can be included 200,000 × 200 = 40,000,000 times.
Another look at the example document shows multiple iterations of the HL loop.
Details
The overview usually doesn’t take up more than a page or two. The rest of the implementation guide is made up of segment detail pages. Here’s one for the PRF segment.
The details page describes each element within the segment.
For example, the PRF01 segment is mandatory and can have at most 22 characters.
The PRF06 segment is optional and can have at most 30 characters.
At times, an element will accept a small number of codes that map to specific values, similar to an enum. You can see an example of that on the details page for DTM.
Transforming EDI
So far, we’ve looked at a raw EDI document and you may have noticed that the format is hard to use with your favorite programming language. It would take a lot of string parsing, array indexing, and other tedium. Stedi offers an EDI parser, converter, and validator called EDI Core.
We can take our EDI example and give it to EDI Core. EDI Core will return a JSON representation of the EDI that we call JEDI.
{
"interchanges": [
{
"interchange_control_header_ISA": {
"authorization_information_qualifier_01": "no_authorization_information_present_no_meaningful_information_in_i02_00",
"authorization_information_02": "",
"security_information_qualifier_03": "no_security_information_present_no_meaningful_information_in_i04_00",
"security_information_04": "",
"interchange_id_qualifier_05": "mutually_defined_ZZ",
"interchange_sender_id_06": "MYORG",
"interchange_id_qualifier_07": "mutually_defined_ZZ",
"interchange_receiver_id_08": "Interchange Rec",
"interchange_date_09": "200831",
"interchange_time_10": "2324",
"repetition_separator_11": "U",
"interchange_control_version_number_12": "00501",
"interchange_control_number_13": "100030537",
"acknowledgment_requested_14": "no_interchange_acknowledgment_requested_0",
"interchange_usage_indicator_15": "production_data_P",
"component_element_separator_16": ">"
},
"groups": [
{
"functional_group_header_GS": {
"functional_identifier_code_01": "ship_notice_manifest_856_SH",
"application_senders_code_02": "MYORG",
"application_receivers_code_03": "Interchange Rec",
"date_04": "20200831",
"time_05": "2324",
"group_control_number_06": "200030537",
"responsible_agency_code_07": "accredited_standards_committee_x12_X",
"version_release_industry_identifier_code_08": "005010"
},
"transaction_sets": [
{
"set": "856",
"heading": {
"transaction_set_header_ST": {
"transaction_set_identifier_code_01": "856",
"transaction_set_control_number_02": "300089443"
},
"beginning_segment_for_ship_notice_BSN": {
"transaction_set_purpose_code_01": "original_00",
"shipment_identification_02": "P1982123",
"date_03": "20200831",
"time_04": "2324",
"hierarchical_structure_code_05": "shipment_order_packaging_item_0001"
},
"date_time_reference_DTM": [
{
"date_time_qualifier_01": "shipped_011",
"date_02": "20200831",
"time_03": "2324"
}
]
},
"detail": {
"hierarchical_level_HL_loop": [
{
"hierarchical_level_HL": {
"hierarchical_id_number_01": "1",
"hierarchical_level_code_03": "shipment_S"
},
"carrier_details_quantity_and_weight_TD1": [
{
"packaging_code_01": "CTN",
"lading_quantity_02": "1",
"weight_qualifier_06": "gross_weight_G",
"weight_07": "2",
"unit_or_basis_for_measurement_code_08": "pound_LB"
}
],
"carrier_details_routing_sequence_transit_time_TD5": [
{
"identification_code_qualifier_02": "standard_carrier_alpha_code_scac_2",
"identification_code_03": "FDE",
"transportation_method_type_code_04": "private_parcel_service_U",
"service_level_code_12": "three_day_service_3D",
"service_level_code_13": "three_day_service_3D",
"service_level_code_14": "three_day_service_3D"
}
],
"date_time_reference_DTM": [
{
"date_time_qualifier_01": "shipped_011",
"date_02": "20200831"
}
],
"party_identification_N1_loop": [
{
"party_identification_N1": {
"entity_identifier_code_01": "ship_to_ST",
"name_02": "SOO KIM",
"identification_code_qualifier_03": "assigned_by_buyer_or_buyers_agent_92",
"identification_code_04": "DROPSHIP CUSTOMER"
},
"party_location_N3": [
{
"address_information_01": "26218 QUENTIN TURNPIKE"
}
],
"geographic_location_N4": {
"city_name_01": "REANNAFORT",
"state_or_province_code_02": "MS",
"postal_code_03": "51135"
}
}
]
},
{
"hierarchical_level_HL": {
"hierarchical_id_number_01": "2",
"hierarchical_parent_id_number_02": "1",
"hierarchical_level_code_03": "order_O"
},
"purchase_order_reference_PRF": {
"purchase_order_number_01": "1881225",
"date_04": "20200831"
}
},
{
"hierarchical_level_HL": {
"hierarchical_id_number_01": "3",
"hierarchical_parent_id_number_02": "2",
"hierarchical_level_code_03": "pack_P"
},
"marks_and_numbers_information_MAN": [
{
"marks_and_numbers_qualifier_01": "carrier_assigned_package_id_number_CP",
"marks_and_numbers_02": "037178019302492"
}
]
},
{
"hierarchical_level_HL": {
"hierarchical_id_number_01": "4",
"hierarchical_parent_id_number_02": "3",
"hierarchical_level_code_03": "item_I"
},
"item_identification_LIN": {
"assigned_identification_01": "1",
"product_service_id_qualifier_02": "vendors_sellers_catalog_number_VC",
"product_service_id_03": "11216.32",
"product_service_id_qualifier_04": "stock_keeping_unit_sku_SK",
"product_service_id_05": "RGR-11216.32"
},
"item_detail_shipment_SN1": {
"assigned_identification_01": "1",
"number_of_units_shipped_02": "1",
"unit_or_basis_for_measurement_code_03": "each_EA"
},
"product_item_description_PID": [
{
"item_description_type_01": "free_form_F",
"description_05": "ALL TERRAIN ENTRY GUARD KIT 2020 JEEP WRANGLER J"
}
]
}
]
},
"summary": {
"transaction_totals_CTT": {
"number_of_line_items_01": "4"
},
"transaction_set_trailer_SE": {
"number_of_included_segments_01": "20",
"transaction_set_control_number_02": "300089443"
}
}
}
],
"functional_group_trailer_GE": {
"number_of_transaction_sets_included_01": "1",
"group_control_number_02": "200030537"
},
"release": "005010"
}
],
"interchange_control_trailer_IEA": {
"number_of_included_functional_groups_01": "1",
"interchange_control_number_02": "100030537"
},
"delimiters": {
"element": "*",
"segment": "~",
"sub_element": ">"
}
}
],
"__version": "jedi@2.0"
}
This is more verbose, but it’s much easier to deal with from code. You can see the EDI and the JSON side-by-side by using the Inspector. It’ll show an explanation of each segment, too.
Getting started
This is certainly not all you need to know, but it’s enough to get you started. Don’t forget to check out our blog for more information on working with EDI.
Share
Backed by
Stedi is a registered trademark of Stedi, Inc. All names, logos, and brands of third parties listed on our site are trademarks of their respective owners (including “X12”, which is a trademark of X12 Incorporated). Stedi, Inc. and its products and services are not endorsed by, sponsored by, or affiliated with these third parties. Our use of these names, logos, and brands is for identification purposes only, and does not imply any such endorsement, sponsorship, or affiliation.
Backed by
Stedi is a registered trademark of Stedi, Inc. All names, logos, and brands of third parties listed on our site are trademarks of their respective owners (including “X12”, which is a trademark of X12 Incorporated). Stedi, Inc. and its products and services are not endorsed by, sponsored by, or affiliated with these third parties. Our use of these names, logos, and brands is for identification purposes only, and does not imply any such endorsement, sponsorship, or affiliation.
Backed by
Stedi is a registered trademark of Stedi, Inc. All names, logos, and brands of third parties listed on our site are trademarks of their respective owners (including “X12”, which is a trademark of X12 Incorporated). Stedi, Inc. and its products and services are not endorsed by, sponsored by, or affiliated with these third parties. Our use of these names, logos, and brands is for identification purposes only, and does not imply any such endorsement, sponsorship, or affiliation.