# JSON Format

Tediware represents every EDI transaction set as JSON. When a partner sends you EDI, Tediware translates each transaction set into this JSON and hands it to your system. When you send EDI to a partner, your mapping produces JSON in the same style, shaped to that partner's implementation, and Tediware writes the X12 for you. You work with JSON; Tediware handles the EDI.

Much of what an X12 document means sits outside the document. Structure is implied by the order of segments, a key is a two-letter code, and a value like `PP` means nothing without the standard open beside you. This JSON puts that information back into the document: loops and hierarchies become arrays and nesting, keys carry the name and position of what they hold, coded values carry the meaning of the code along with the code itself, and numbers arrive as numbers. To see it applied to a document of your own, paste one into the [EDI Translator](/tools/translator).

## Document Structure

A translated document is a single transaction set, divided into up to three sections:

- `heading`: the segments before the detail area, holding the transaction's metadata.
- `detail`: the repeating body of the document, such as line items or stops.
- `summary`: totals and the transaction trailer.

Only the sections actually present in the document appear. The interchange and group envelope (ISA, GS, GE, IEA) is not part of the transaction set JSON. Tediware manages the envelope separately, from the settings described in [Envelopes](/resources/docs/envelopes).

The [EDI Translator](/tools/translator) is the one place you will see more than this. It translates a whole file rather than a delivered transaction set, so its output wraps everything below in `interchanges`, `groups` and `transaction_sets` keys, envelope segments included. Inside a transaction set the shape is identical to what your system receives.

Here is a complete translated 856 Ship Notice:

```json
{
  "heading": {
    "transaction_set_header_ST": {
      "transaction_set_identifier_code_01": "ship_notice_manifest_856",
      "transaction_set_control_number_02": "0001"
    },
    "beginning_segment_for_ship_notice_BSN": {
      "transaction_set_purpose_code_01": "original_00",
      "shipment_identification_02": "SHIP-0001",
      "date_03": "20260203",
      "time_04": "120000"
    }
  },
  "detail": {
    "shipment_S_HL_loop": [
      {
        "hierarchical_level_HL": {
          "hierarchical_id_number_01": "1",
          "hierarchical_level_code_03": "shipment_S",
          "hierarchical_child_code_04": "additional_subordinate_hl_data_segment_in_this_hierarchical_structure_1"
        },
        "measurements_MEA": [
          {
            "measurement_reference_id_code_01": "physical_dimensions_PD",
            "measurement_qualifier_02": "weight_WT",
            "measurement_value_03": 100.0,
            "composite_unit_of_measure_04": {
              "_composite": true,
              "unit_or_basis_for_measurement_code_01": "pound_LB",
              "exponent_02": 1.0,
              "multiplier_03": 1.0
            }
          },
          {
            "measurement_reference_id_code_01": "counts_CT",
            "measurement_qualifier_02": "height_HT",
            "measurement_value_03": 5.5,
            "composite_unit_of_measure_04": {
              "_composite": true,
              "unit_or_basis_for_measurement_code_01": "inch_IN"
            }
          }
        ],
        "item_I_HL_loop": [
          {
            "hierarchical_level_HL": {
              "hierarchical_id_number_01": "2",
              "hierarchical_parent_id_number_02": "1",
              "hierarchical_level_code_03": "item_I"
            },
            "item_identification_LIN": {
              "assigned_identification_01": "1",
              "product_service_id_qualifier_02": "u_p_c_consumer_package_code_1_5_5_1_UP",
              "product_service_id_03": "012345678905"
            },
            "item_detail_shipment_SN1": {
              "number_of_units_shipped_02": 24.0,
              "unit_or_basis_for_measurement_code_03": "each_EA"
            }
          }
        ]
      }
    ]
  },
  "summary": {
    "transaction_totals_CTT": {
      "number_of_line_items_01": 2
    },
    "transaction_set_trailer_SE": {
      "number_of_included_segments_01": 10,
      "transaction_set_control_number_02": "0001"
    }
  }
}
```

## Field Names

Every key carries its X12 meaning, so you do not have to memorize segment and element codes.

- Segment keys are the segment name followed by its X12 code, for example `transaction_set_header_ST` and `measurements_MEA`.
- Element keys are the element name followed by its two-digit position, for example `transaction_set_control_number_02` and `measurement_value_03`.

The naming is lossless. To recover the raw X12 code, take the text after the last underscore: `transaction_set_header_ST` yields the segment code `ST`, and `measurement_value_03` yields position `03`.

## Arrays and Objects

Whether a segment arrives as an array or as a single object is decided by the X12 standard, not by the document in front of you. A segment the standard allows to repeat is always an array, even when the document contains only one occurrence. A segment that cannot repeat is always a plain object.

Both appear in the example above, inside the same shipment: `measurements_MEA` is an array because MEA may repeat, while `item_identification_LIN` is an object because LIN may not. The shape does not change from document to document, so an accessor written against the transaction set's structure keeps working. Your partner's [implementation](/resources/docs/implementations) is the place to confirm which segments repeat.

Loops are always arrays, whatever they contain. They are covered below.

## Omitted Values

X12 carries empty elements as empty space between its delimiters. This JSON leaves them out instead. An element with no value has no key, a segment with nothing in it does not appear at all, and a loop with no occurrences is absent rather than present and empty.

A translated document therefore shows what your partner actually sent, which is rarely everything they are allowed to send. Two documents of the same transaction set can carry different keys. Read optional fields defensively, and take the question of what is required from the partner's implementation schema rather than from a sample document.

## Values

### Coded values

A coded element carries both its meaning and its code, joined by an underscore. In the example above, `transaction_set_purpose_code_01` is `original_00`: the readable name `original` followed by the X12 code `00`. Recover the bare code the same way you would a segment code, by splitting on the last underscore:

```javascript
const purposeCode = doc.heading
  .beginning_segment_for_ship_notice_BSN
  .transaction_set_purpose_code_01
  .split("_")
  .pop();
// "00"
```

### Numbers

Numeric elements are native JSON numbers, not strings. Integer elements (X12 type N0) become integers, and elements with decimal places (N2, R, and similar) become floating-point numbers. In the example, `number_of_line_items_01` is `2` and `measurement_value_03` is `100.0`.

X12 often writes decimals with the point implied by the element's type, so a raw `1550` in an N2 element means 15.50. That conversion is already applied by the time you see the JSON.

Identifiers, codes, dates, and free text remain strings.

### Dates and times

Dates and times are kept as their digits, in the form the EDI used. The example's `date_03` is `"20260203"`, a string rather than a formatted timestamp, because X12 date and time formats vary from element to element: a date may carry six digits or eight, and a time may or may not include seconds. Read the qualifier element in the same segment to learn how to interpret it. Times always have an even number of digits, so a value that would otherwise be five digits long is padded to six.

## Loops

A repeating group of segments becomes a JSON array, and its key ends in `_loop`. In the example, the shipment hierarchy is `shipment_S_HL_loop`, and within it the items are `item_I_HL_loop`.

Iterate these arrays with ordinary tools:

```javascript
for (const shipment of doc.detail.shipment_S_HL_loop) {
  for (const item of shipment.item_I_HL_loop ?? []) {
    console.log(item.item_identification_LIN.product_service_id_03);
  }
}
```

### Hierarchical loops

Documents such as the 856 Ship Notice organize their detail area with HL segments, which describe a tree: a shipment contains orders, an order contains items. In the EDI those segments are a flat list, and each one states its own id and its parent's id so that a reader can reassemble the hierarchy. Tediware reassembles it for you, so a child loop appears inside the parent it belongs to.

The key names come from the level code in HL03. A shipment level (`S`) becomes `shipment_S_HL_loop`, an order level (`O`) becomes `order_O_HL_loop`, and an item level (`I`) becomes `item_I_HL_loop`. The original `hierarchical_id_number_01` and `hierarchical_parent_id_number_02` values are still on each `hierarchical_level_HL` segment if you need them, but the nesting already reflects them.

A level appears only when the document contains one, so check for a child key before descending into it, as the loop above does.

## Composite Elements

A composite element packs several components into one element position. In JSON it becomes an object marked with `"_composite": true`, with one key per component, named and position-suffixed like any other element.

A fully populated composite:

```
MEA*PD*WT*100*LB:1:1~
```

```json
{
  "_composite": true,
  "unit_or_basis_for_measurement_code_01": "pound_LB",
  "exponent_02": 1.0,
  "multiplier_03": 1.0
}
```

When trailing components are absent, their keys are simply omitted:

```
MEA*CT*HT*5.5*IN~
```

```json
{
  "_composite": true,
  "unit_or_basis_for_measurement_code_01": "inch_IN"
}
```

When an interior component is absent, the EDI preserves the gap as a doubled component separator, and the JSON omits the missing key:

```
MEA*PD*WT*100*LB::5~
```

```json
{
  "_composite": true,
  "unit_or_basis_for_measurement_code_01": "pound_LB",
  "multiplier_03": 5.0
}
```

## Authoring JSON for Outbound EDI

For outbound, your [mapping](/resources/docs/mappings) produces JSON and Tediware writes the X12 from it. That JSON follows the conventions described above: the same `heading`, `detail` and `summary` areas, the same segment and element key patterns, the same `_loop` arrays, the same composite objects.

It is not the same document as a translation, though. What your mapping must satisfy is your partner's implementation schema, which describes one partner's specification rather than the standard at large, and it departs from a translation in these ways:

- Coded values use the bare X12 code, such as `"00"` or `"LB"`, matching the allowed values in the schema. Inbound, the same value carries its descriptive prefix (`pound_LB`).
- Numeric fields accept either a JSON number or a numeric string: `100.0` and `"100.0"` are both valid.
- Composites use the same `"_composite": true` object. Omit trailing components you do not need and Tediware trims them. To leave an interior component empty, omit its key and Tediware preserves the gap.
- Where an implementation uses the same segment for more than one purpose, telling them apart by a qualifier, each purpose is its own key: `reference_identification_BM_REF` and `reference_identification_CR_REF`, with loop equivalents such as `reference_identification_BM_REF_loop`. Translating a document that contains both gives you one `reference_identification_REF` array instead.
- Whether a segment is an array follows the implementation's own repetition rules. A partner who permits a single occurrence of a segment the standard lets repeat gives you an object where a translation would give an array.
- The schema covers only what that partner's specification allows, and marks which segments and elements are required. A translation carries whatever the sender put in the document.

Your partner's implementation schema is the authoritative contract for which segments, elements, and codes are valid in a given transaction set. See [Implementations](/resources/docs/implementations) for how that schema is built and where to read it.

## Where This JSON Appears

- **Inbound**, as the payload delivered to your endpoint when a partner's document finishes processing. See [Webhooks](/resources/docs/webhooks).
- **Outbound**, as the model for what your mapping produces. The target there is your partner's implementation schema, which uses these conventions without being a translation. See [Mappings](/resources/docs/mappings).
- **In traces**, as the payload each node emitted, which is where to look when a document did not turn into what you expected. See [Logs and Traces](/resources/docs/logs-results-traces).
- **On demand**, for any document you have on hand, in the [EDI Translator](/tools/translator).
