The 404 is the X12 rail carrier shipment information - the electronic bill of lading for rail. Shippers send it to the railroad to tender a car or container for movement.
BX and BNX describe the shipment and payment, N7 loops the rail equipment, N1 loops the parties, and L5, L0 and hazardous material segments describe the lading.
004010SR (GS01)TS404 in EdiFabric.Templates.X12The full X12 404 layout from its OpenEDI definition, the same model ediFabric uses to parse, validate and generate it: 14 loops and 88 segment positions, in file order. Loops are shaded and their segments indented; Max use is how many times a segment or loop may repeat.
| Segment / loop | Name | Usage | Max use |
|---|---|---|---|
ST | Transaction Set Header | Mandatory | 1 |
ZC1 | Beginning Segment for Data Correction or Change | Optional | 1 |
BX | General Shipment Information | Optional | 1 |
BNX | Rail Shipment Information | Optional | 1 |
M3 | Release | Mandatory | 1 |
N9 | Reference Identification | Mandatory | 30 |
CM | Cargo Manifest | Optional | 2 |
M1 | Insurance | Optional | 1 |
DTM | Date/Time Reference | Optional | 5 |
| N7 loop | Equipment Details | Mandatory | 500 |
N7 | Equipment Details | Mandatory | 1 |
EM | Equipment Characteristics | Optional | 1 |
| VC loop | Motor Vehicle Control | Optional | 21 |
VC | Motor Vehicle Control | Mandatory | 1 |
| N1 loop | Name | Optional | 2 |
N1 | Name | Mandatory | 1 |
N3 | Address Information | Optional | 2 |
N4 | Geographic Location | Optional | 1 |
H3 | Special Handling Instructions | Optional | 1 |
M7 | Seal Numbers | Optional | 5 |
N5 | Equipment Ordered | Optional | 1 |
IC | Intermodal Chassis Equipment | Optional | 1 |
IM | Intermodal Movement Information | Optional | 1 |
M12 | In-bond Identifying Information | Optional | 2 |
| E1 loop | Empty Car Disposition - Pended Destination Consignee | Optional | 2 |
E1 | Empty Car Disposition - Pended Destination Consignee | Mandatory | 1 |
E4 | Empty Car Disposition - Pended Destination City | Optional | 1 |
E5 | Empty Car Disposition - Pended Destination Route | Optional | 13 |
PI | Price Authority Identification | Optional | 1 |
GA | Canadian Grain Information | Optional | 15 |
| REF loop | Reference Identification | Optional | 99 |
REF | Reference Identification | Mandatory | 1 |
N10 | Quantity and Description | Optional | 15 |
| N1 loop | Name | Optional | 5 |
N1 | Name | Mandatory | 1 |
N3 | Address Information | Optional | 1 |
N4 | Geographic Location | Optional | 1 |
NA | Cross-Reference Equipment | Optional | 10 |
F9 | Origin Station | Mandatory | 1 |
D9 | Destination Station | Mandatory | 1 |
| N1 loop | Name | Mandatory | 10 |
N1 | Name | Mandatory | 1 |
N2 | Additional Name Information | Optional | 2 |
N3 | Address Information | Optional | 2 |
N4 | Geographic Location | Optional | 1 |
REF | Reference Identification | Optional | 2 |
PER | Administrative Communications Contact | Optional | 2 |
BL | Billing Information | Optional | 12 |
| S1 loop | Stop-off Name | Optional | 12 |
S1 | Stop-off Name | Mandatory | 1 |
S2 | Stop-off Address | Optional | 2 |
S9 | Stop-off Station | Optional | 1 |
N1 | Name | Optional | 1 |
N2 | Additional Name Information | Optional | 1 |
N3 | Address Information | Optional | 1 |
N4 | Geographic Location | Optional | 1 |
PER | Administrative Communications Contact | Optional | 1 |
R2 | Route Information | Optional | 13 |
R9 | Route Code Identification | Optional | 1 |
| E1 loop | Empty Car Disposition - Pended Destination Consignee | Optional | 2 |
E1 | Empty Car Disposition - Pended Destination Consignee | Mandatory | 1 |
E4 | Empty Car Disposition - Pended Destination City | Optional | 1 |
E5 | Empty Car Disposition - Pended Destination Route | Optional | 13 |
PI | Price Authority Identification | Optional | 1 |
H3 | Special Handling Instructions | Optional | 20 |
PS | Protective Service Instructions | Optional | 5 |
| LX loop | Assigned Number | Mandatory | 25 |
LX | Assigned Number | Mandatory | 1 |
L5 | Description, Marks and Numbers | Mandatory | 15 |
| L0 loop | Line Item - Quantity and Weight | Optional | 25 |
L0 | Line Item - Quantity and Weight | Mandatory | 1 |
MEA | Measurements | Optional | 3 |
L1 | Rate and Charges | Optional | 10 |
PI | Price Authority Identification | Optional | 30 |
X1 | Export License | Optional | 6 |
| T1 loop | Transit Inbound Origin | Optional | 64 |
T1 | Transit Inbound Origin | Mandatory | 1 |
T2 | Transit Inbound Lading | Optional | 30 |
T3 | Transit Inbound Route | Optional | 12 |
T6 | Transit Inbound Rates | Optional | 1 |
T8 | Free-form Transit Data | Optional | 99 |
L3 | Total Weight and Charges | Optional | 1 |
| LS loop | Loop Header | Optional | 1 |
LS | Loop Header | Mandatory | 1 |
| LH1 loop | Hazardous Identification Information | Optional | 100 |
LH1 | Hazardous Identification Information | Mandatory | 1 |
LH2 | Hazardous Classification Information | Optional | 4 |
LH3 | Hazardous Material Shipping Name | Optional | 10 |
LFH | Freeform Hazardous Material Information | Optional | 20 |
LEP | EPA-Required Data | Optional | 3 |
LH4 | Canadian Dangerous Requirements | Optional | 1 |
LHT | Transborder Hazardous Requirements | Optional | 3 |
LHR | Hazardous Material Identifying Reference Numbers | Optional | 5 |
PER | Administrative Communications Contact | Optional | 5 |
LE | Loop Trailer | Mandatory | 1 |
PER | Administrative Communications Contact | Optional | 5 |
LH2 | Hazardous Classification Information | Optional | 6 |
LHR | Hazardous Material Identifying Reference Numbers | Optional | 1 |
LH6 | Hazardous Certification | Optional | 5 |
XH | Pro Forma - B13 Information | Optional | 1 |
X7 | Customs Information | Optional | 10 |
SE | Transaction Set Trailer | Mandatory | 1 |
Mandatory segments must be sent, Optional ones only when the data applies. Trading partners often add their own rules in companion guides - ediFabric templates can be adjusted to match. Open the element-level definition in the EdiNation spec library.
A rail bill of lading for one car with its lading. Paste it into EdiNation to see every element named and validated.
ISA*00* *00* *16*SENDER1 *14*RECEIVER1 *071216*1406*U*00204*000000263*1*T*>~ GS*IN*SENDER1*RECEIVER1*20071216*1406*000000001*X*004010~ ST*404*0001~ BX*00*R*11**NS*L*B*N~ BNX*A**S~ M3*R*20000301*1116*LT~ N9*BM*2041247**20000301*1116*LT~ N7*CR*237522*80503*N*******RR~ M7*582127*582128~ F9**WARREN*MI~ D9**VALLEY PARK*MO~ N1*11*CORPAY SOLUTIONS~ N3*PO BOX 195199/2065 S CENTER RD~ N4*BURTON*MI*48519~ N1*CN*ST LOUIS ASSEMBLY I*93*04087~ N3*1001 N HIGHWAY DRIVE~ N4*FENTON*MO*63026~ N1*UC*ST LOUIS ASSEMBLY I*93*04087~ N3*1001 N HIGHWAY DRIVE~ N4*FENTON*MO*63026~ N1*SH*STERLING STAMPING*93*06215~ N3*35777 VAN DYKE RD~ N4*STERLING HEIGHTS*MI*48312~ R2*NS*R*ESTL~ R2*BNSF*1~ LX*1~ L5*1*AUTO PARTS*3714993*T~ L0*1***80503*N***42*RCK~ SE*27*0001~ GE*2*000000001~ IEA*1*000000263~
ediFabric turns every loop, segment and element into a named field. This is the transaction from the sample, in the JSON that ediFabric Native and Cloud return and accept.
{
"ST": {
"TransactionSetIdentifierCode_01": "404",
"TransactionSetControlNumber_02": "0001"
},
"BX": {
"TransactionSetPurposeCode_01": "00",
"TransportationMethodTypeCode_02": "R",
"ShipmentMethodofPayment_03": "11",
"StandardCarrierAlphaCode_05": "NS",
"WeightUnitCode_06": "L",
"ShipmentQualifier_07": "B",
"SectionSevenCode_08": "N"
},
"BNX": {
"ShipmentWeightCode_01": "A",
"BillingCode_03": "S"
},
"M3": {
"ReleaseCode_01": "R",
"Date_02": "20000301",
"Time_03": "1116",
"TimeCode_04": "LT"
},
"N9": [
{
"ReferenceIdentificationQualifier_01": "BM",
"ReferenceIdentification_02": "2041247",
"Date_04": "20000301",
"Time_05": "1116",
"TimeCode_06": "LT"
}
],
"N7Loop": [
{
"N7": {
"EquipmentInitial_01": "CR",
"EquipmentNumber_02": "237522",
"Weight_03": "80503",
"WeightQualifier_04": "N",
"EquipmentDescriptionCode_11": "RR"
},
"M7": [
{
"SealNumber_01": "582127",
"SealNumber_02": "582128"
}
]
}
],
"F9": {
"CityName_02": "WARREN",
"StateorProvinceCode_03": "MI"
},
"D9": {
"CityName_02": "VALLEY PARK",
"StateorProvinceCode_03": "MO"
},
"N1Loop": [
{
"N1": {
"EntityIdentifierCode_01": "11",
"Name_02": "CORPAY SOLUTIONS"
},
"N3": [
{
"AddressInformation_01": "PO BOX 195199/2065 S CENTER RD"
}
],
"N4": {
"CityName_01": "BURTON",
"StateorProvinceCode_02": "MI",
"PostalCode_03": "48519"
}
},
{
"N1": {
"EntityIdentifierCode_01": "CN",
"Name_02": "ST LOUIS ASSEMBLY I",
"IdentificationCodeQualifier_03": "93",
"IdentificationCode_04": "04087"
},
"N3": [
{
"AddressInformation_01": "1001 N HIGHWAY DRIVE"
}
],
"N4": {
"CityName_01": "FENTON",
"StateorProvinceCode_02": "MO",
"PostalCode_03": "63026"
}
},
{
"N1": {
"EntityIdentifierCode_01": "UC",
"Name_02": "ST LOUIS ASSEMBLY I",
"IdentificationCodeQualifier_03": "93",
"IdentificationCode_04": "04087"
},
"N3": [
{
"AddressInformation_01": "1001 N HIGHWAY DRIVE"
}
],
"N4": {
"CityName_01": "FENTON",
"StateorProvinceCode_02": "MO",
"PostalCode_03": "63026"
}
},
{
"N1": {
"EntityIdentifierCode_01": "SH",
"Name_02": "STERLING STAMPING",
"IdentificationCodeQualifier_03": "93",
"IdentificationCode_04": "06215"
},
"N3": [
{
"AddressInformation_01": "35777 VAN DYKE RD"
}
],
"N4": {
"CityName_01": "STERLING HEIGHTS",
"StateorProvinceCode_02": "MI",
"PostalCode_03": "48312"
}
}
],
"R2": [
{
"StandardCarrierAlphaCode_01": "NS",
"RoutingSequenceCode_02": "R",
"CityName_03": "ESTL"
},
{
"StandardCarrierAlphaCode_01": "BNSF",
"RoutingSequenceCode_02": "1"
}
],
"LXLoop": [
{
"LX": {
"AssignedNumber_01": "1"
},
"L5": [
{
"LadingLineItemNumber_01": "1",
"LadingDescription_02": "AUTO PARTS",
"CommodityCode_03": "3714993",
"CommodityCodeQualifier_04": "T"
}
],
"L0Loop": [
{
"L0": {
"LadingLineItemNumber_01": "1",
"Weight_04": "80503",
"WeightQualifier_05": "N",
"LadingQuantity_08": "42",
"PackagingFormCode_09": "RCK"
}
}
]
}
],
"SE": {
"NumberofIncludedSegments_01": "27",
"TransactionSetControlNumber_02": "0001"
}
}Read the file into typed objects with ediFabric .NET, convert it to JSON in process with the ediFabric Native bindings for Python, Java and C, or post it to the ediFabric Cloud REST API from any language.
using EdiFabric.Templates.X12004010; License.SetSerial("YOUR_SERIAL_KEY"); using (var stream = File.OpenRead(@"C:\edi\RailCarrierShipment.txt")) using (var reader = new X12Reader(stream, "EdiFabric.Templates.X12")) { var items = await reader.ReadToEndAsync(); foreach (var transaction in items.OfType<TS404>()) { if (transaction.IsValid(out MessageErrorContext errors)) Console.WriteLine($"{transaction.ST.TransactionSetControlNumber_02} is valid"); else Console.WriteLine(string.Join(Environment.NewLine, errors.Flatten())); } }
import json import edifabric_x12 as ef serial = "YOUR_SERIAL_KEY" ef.load_library() ef.set_serial(serial) ef.set_map(json.dumps({"default": serial, "maps": {}})) edi = open("RailCarrierShipment.txt", "rb").read() output, offset = ef.parse(edi, ef.ParseMode.JSON_VALIDATE) transactions = output[:offset] report = json.loads(output[offset:]) print(report["errors_count"])
import com.edifabric.nativex12.EdiFabricX12; import com.edifabric.nativex12.ParseMode; import com.edifabric.nativex12.ParseResult; String serial = "YOUR_SERIAL_KEY"; EdiFabricX12.loadLibrary(); EdiFabricX12.setSerial(serial); EdiFabricX12.setMap("{\"default\":\"" + serial + "\",\"maps\":{}}"); String edi = Files.readString(Path.of("RailCarrierShipment.txt")); ParseResult result = EdiFabricX12.parse(edi, ParseMode.JSON_VALIDATE); System.out.println(result.getTransactions()); System.out.println(result.getReport());
#include "edifabric_x12.h" const char *serial = "YOUR_SERIAL_KEY"; ef_parse_result result; if (ef_load_library(NULL) != 0) return 1; ef_set_serial(serial); ef_set_map("{\"default\":\"YOUR_SERIAL_KEY\",\"maps\":{}}"); char *edi = read_file("RailCarrierShipment.txt", NULL); /* helper in example_all_functions.c */ if (ef_parse(edi, EF_PARSE_JSON_VALIDATE, NULL, &result) == 0) { /* transactions = output[0 .. offset), report = output[offset .. length) */ fwrite(result.output.data, 1, (size_t)result.output.length, stdout); ef_free(result.output.data); }
curl -X POST 'https://api.edination.com/v2/x12/read' \ -H 'Ocp-Apim-Subscription-Key: YOUR_SERIAL_KEY' \ -H 'Content-Type: application/octet-stream' \ --data-binary '@RailCarrierShipment.txt'
Populate a TS404 object in .NET, or pass JSON in the shape shown above to ediFabric Native or ediFabric Cloud, and get a valid 404 file back.
using EdiFabric.Templates.X12004010; License.SetSerial("YOUR_SERIAL_KEY"); var transaction = new TS404(); // Transaction Set Identifier Code // = “404” (Rail Carrier Shipment Information) // Transaction Set Control Number = 0001 transaction.ST = new ST(); transaction.ST.TransactionSetIdentifierCode_01 = "404"; transaction.ST.TransactionSetControlNumber_02 = "0001"; // ... set the remaining loops and segments the same way // SegmentBuilders is in the Common project of the example repository using (var stream = new MemoryStream()) { using (var writer = new X12Writer(stream)) { writer.Write(SegmentBuilders.BuildIsa("1")); writer.Write(SegmentBuilders.BuildGs("1")); writer.Write(transaction); } Console.WriteLine(Encoding.UTF8.GetString(stream.ToArray())); }
import json import edifabric_x12 as ef serial = "YOUR_SERIAL_KEY" ef.load_library() ef.set_serial(serial) ef.set_map(json.dumps({"default": serial, "maps": {}})) # the transactions JSON returned by ef.parse, edited or produced by your application transactions = open("RailCarrierShipment.json", "rb").read() edi = ef.build(transactions, postfix="\r\n") print(edi)
import com.edifabric.nativex12.EdiFabricX12; String serial = "YOUR_SERIAL_KEY"; EdiFabricX12.loadLibrary(); EdiFabricX12.setSerial(serial); EdiFabricX12.setMap("{\"default\":\"" + serial + "\",\"maps\":{}}"); // the transactions JSON returned by parse, edited or produced by your application String transactions = Files.readString(Path.of("RailCarrierShipment.json")); String edi = EdiFabricX12.build(transactions, "\r\n"); System.out.println(edi);
#include "edifabric_x12.h" ef_buffer edi; if (ef_load_library(NULL) != 0) return 1; ef_set_serial("YOUR_SERIAL_KEY"); ef_set_map("{\"default\":\"YOUR_SERIAL_KEY\",\"maps\":{}}"); /* the transactions JSON returned by ef_parse, edited or produced by your application */ char *transactions = read_file("RailCarrierShipment.json", NULL); if (ef_build(transactions, "\r\n", &edi) == 0) { fwrite(edi.data, 1, (size_t)edi.length, stdout); ef_free(edi.data); }
# the JSON returned by /read, edited or produced by your application curl -X POST 'https://api.edination.com/v2/x12/write' \ -H 'Ocp-Apim-Subscription-Key: YOUR_SERIAL_KEY' \ -H 'Content-Type: application/json' \ --data-binary '@RailCarrierShipment.json' \ -o 'RailCarrierShipment.txt'
Yes. It carries the same information as the paper bill of lading and is how rail shipments are tendered electronically in North America.
With the LH1, LH2, LH3 and LH4 segments and the emergency contact information required for rail.
N7 carries the equipment initial and number (for example a railcar mark), with weights and seal numbers in related segments.
In .NET, install EdiFabric and EdiFabric.Templates.X12, read the file with X12Reader into TS404 objects and write them back with X12Writer. From Python, Java or C, use ediFabric Native, which converts 404 files to JSON and JSON back to X12 inside your process. From any other language, post the file to the ediFabric Cloud REST API.