> ## Documentation Index
> Fetch the complete documentation index at: https://dokumentation.websale.de/llms.txt
> Use this file to discover all available pages before exploring further.

# JSON interface

> Embed external data in JSON format anywhere in the template, evaluate and format it, and generate your own JSON data in the shop.

Some information does not fit into any field of the merchandise management system: technical data sheets for a product, shipping times per postcode, a menu tree, the response of a payment provider. The JSON interface brings such data to any place in the template, in a way that lets you use it there just like shop data.

Typical applications:

* additional product information, images and technical parameters
* shipment tracking in the customer account
* a complete main menu including submenus
* top-seller structures and cross-links for categories or products
* postcode lists with shipping times and Europe-wide public holidays for delivery time calculation
* third-party reviews
* content from a content management system

It works in both directions: the shop can not only read JSON data but also generate and modify it itself, in order to pass it on via AJAX, JavaScript or email. ASSE is suitable for sending data to external systems.

## Where the data comes from

| Type | Source | Activation required |
| - | - | - |
| `global` | File in the root directory of the JSON FTP access, applies to all subshops | yes |
| `subshop` | File in the subshop directory of the same FTP access | yes |
| `userdir` | File in the `benutzer` directory of the regular shop FTP access | yes |
| `intern` | Data supplied by the shop itself or by an external system at the moment of the call | no |

## Activation and FTP access

Have the JSON interface activated for your shop. You will receive a dedicated FTP access with server, user name and password.

> [!NOTE]
>
> If you only want to work with internal data, i.e. with responses from external systems, you need neither activation nor a dedicated FTP access.

## The folder structure

The root directory contains the files that apply to all shops and subshops. If a subshop is to get its own files, create a directory named with the subshop ID and place the files there.

> [!NOTE]
>
> The file name must be the same in all subshop directories. Which file is loaded depends on the subshop the visitor is currently in.

You are free to create further subdirectories.

> [!WARNING]
>
> Do not place more than 500 JSON files in one directory, as performance suffers beyond that. Distribute the files across subdirectories instead.

## File requirements

| Requirement | Reason |
| - | - |
| exactly one JSON object or exactly one array of objects per file | the interface cannot load more |
| UTF-8 encoded | other encodings are not read |
| names without dots, without square, round or curly brackets, without dollar signs and tildes | these characters have a special meaning in the access path and in the tag language |

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{
   "Name": "Wert",
   "Name(2.0)": "Wert (2.0)"
}
```

The second name is invalid because it contains brackets and a dot. Correct:

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{
   "Name": "Wert",
   "Name2": "Wert (2.0)"
}
```

> [!WARNING]
>
> A tag may be at most 128 characters long, and the access path is part of the tag. Therefore keep names short and hierarchies flat. With deeply nested data and long names, you will hit this limit.

## The two tag families

| Prefix | Meaning | Tag-in-tag |
| - | - | - |
| `EJD-` | External JSON Data | possible |
| `EJD-DA-` | External JSON Data Direct Access, access via path and ID | not possible for most |

The tags work on all templates. No adjustment of the `shop.config` is required.

## Loading data

Data is loaded with `EJD-LoadData()`. The tag takes three values: the type, the path and an identifier.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<!-- global: aus dem Wurzelverzeichnis -->
~EJD-LoadData(global,file.json,jdat)~

<!-- global aus einem Unterverzeichnis -->
~EJD-LoadData(global,verzeichnis1/verzeichnis2/file.json,jdat)~

<!-- subshop: aus dem Verzeichnis des aktuellen Subshops -->
~EJD-LoadData(subshop,file.json,jdat)~

<!-- userdir: aus dem Verzeichnis "benutzer" des Shop-FTP-Zugangs -->
~EJD-LoadData(userdir,navigation/grafiken/json/file.json,jdat)~
```

You choose the identifier in the third field freely. All subsequent tags use it to access the loaded data. Several files can be loaded in parallel in one template, each with its own identifier.

> [!WARNING]
>
> At most 100 JSON files can be loaded at the same time.

Reference: EJD-LoadData()

## Checking whether the data has arrived

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~EJD-LoadData(global,file.json,jdat)~

{EJD-DataOK(jdat)}
   JSON-Daten sind geladen.
{/EJD-DataOK(jdat)}

{!EJD-DataOK(jdat)}
   JSON-Daten konnten nicht geladen werden. Fehlercode: ~EJD-DataOK(jdat)~
{/!EJD-DataOK(jdat)}
```

> [!NOTE]
>
> Used as a single tag, the negative tag outputs the error code. This lets you distinguish whether the file is missing or does not contain valid JSON.

Reference: EJD-DataOK()

## Accessing values

A value is addressed via its access path. This is made up of the names of the levels, joined by dots. Array elements get their index in square brackets, counted from zero. The top-level element is represented by an empty path or `_root_`.

The following examples use this file:

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{
   "Produktname": "Sportlicher Sneaker",
   "Produktnummer": "A-1234",
   "AdditionalInfo":
   {
      "Beschreibung": "Moderne Schuhe für jeden Anlass",
      "lieferbar": true,
      "Crosslinks": [ "A-5678", "B-9876", "C-2323" ],
      "Lagerbestand": 42,
      "Preis": 59.95
   }
}
```

| Value sought | Access path |
| - | - |
| `A-1234` | `Produktnummer` |
| `Moderne Schuhe für jeden Anlass` | `AdditionalInfo.Beschreibung` |
| `B-9876` | `AdditionalInfo.Crosslinks[1]` |

In the template:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~EJD-LoadData(subshop,$PR-Number$.json,jdat)~

{EJD-DataOK(jdat)}
   Produktnummer: ~EJD-DA-Value(Produktnummer,jdat)~<br>
   Beschreibung: ~EJD-DA-Value(AdditionalInfo.Beschreibung,jdat)~<br>
   Zweiter Crosslink: ~EJD-DA-Value(AdditionalInfo.Crosslinks[1],jdat)~
{/EJD-DataOK(jdat)}
```

```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
Produktnummer: A-1234
Beschreibung: Moderne Schuhe für jeden Anlass
Zweiter Crosslink: B-9876
```

> [!NOTE]
>
> The file name itself can come from a tag. In the example, the file with the product number in its name is loaded for each product.

Reference: EJD-DA-Value()

### Setting the identifier once

If only one file is used on the template, `EJD-SetUseID()` saves you from repeating the identifier in every tag.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~EJD-LoadData(subshop,file.json,jdat)~

{EJD-DataOK(jdat)}
   ~EJD-SetUseID(jdat)~
   Beschreibung: ~EJD-DA-Value(AdditionalInfo.Beschreibung)~
{/EJD-DataOK(jdat)}
```

> [!WARNING]
>
> `EJD-DataOK()` still needs the identifier. The default does not apply to this one tag.

Reference: EJD-SetUseID()

## Reusing values in other tags

The `EJD-DA-` tags carry their values in brackets and therefore cannot simply be nested inside other tags. However, the shop remembers every value and every name that such a tag touches. Via `EJD-LastValueAccessed` and `EJD-LastNameAccessed` you can get at whatever was touched last, and this can be reused like any other value.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~EJD-LoadData(subshop,$PR-Number$.json,jdat)~

{EJD-DataOK(jdat)}
   ~EJD-SetUseID(jdat)~

   Beschreibung: ~EJD-DA-Value(AdditionalInfo.Beschreibung)~<br>

   <!-- gibt die Anzahl aus und merkt sie zugleich -->
   Anzahl der Crosslinks: ~EJD-DA-ArrayElements(AdditionalInfo.Crosslinks)~<br>

   <!-- die gemerkte Anzahl wird zur Anzahl der Schleifendurchläufe -->
   ~DC-ZeroLoop1_set($EJD-LastValueAccessed$)~
   {@DC-ZeroLoop1}
      Crosslink #~DC-ZeroLoop1_position~: ~EJD-DA-Value(AdditionalInfo.Crosslinks[$DC-ZeroLoop1_position$])~<br>
   {/@DC-ZeroLoop1}

{/EJD-DataOK(jdat)}
```

```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
Beschreibung: Moderne Schuhe für jeden Anlass
Anzahl der Crosslinks: 3
Crosslink #1: A-5678
Crosslink #2: B-9876
Crosslink #3: C-2323
```

If a value should be remembered but not output, there are dedicated tags for that:

| Tag | Remembers |
| - | - |
| `EJD-DA-TouchValue()` | the value |
| `EJD-DA-TouchName()` | the name |
| `EJD-DA-TouchArrayElements()` | the number of array elements |

> [!NOTE]
>
> The access path can also be assembled in a free placeholder if the index comes from a loop:
>
> ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
> ~DC-FP1_set(AdditionalInfo.Crosslinks[)~
> ~DC-FP1_append($DC-ZeroLoop1_position$)~
> ~DC-FP1_append(])~
> ~EJD-DA-Value($DC-FP1$)~
> ```

Reference: EJD-DA-ArrayElements() · EJD-LastValueAccessed · EJD-LastNameAccessed · EJD-DA-TouchName() · EJD-DA-TouchValue() · EJD-DA-TouchArrayElements() · DC-ZeroLoop1…3 · DC-ZeroLoop1…3\_set() · DC-ZeroLoop1…3\_position

### Setting decimal places

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~EJD-SetRealOutputFormat(4)~
Preis: ~EJD-DA-Value(AdditionalInfo.Preis)~
```

```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
Preis: 59.9500
```

Reference: EJD-SetRealOutputFormat()

## Checking elements

The type of a value can be queried. The value is remembered at the same time.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{EJD-DA-IsTrue(AdditionalInfo.lieferbar,jdat)}
   Das Produkt ist lieferbar.
{/EJD-DA-IsTrue(AdditionalInfo.lieferbar,jdat)}
```

Available tags are `EJD-DA-IsTrue()`, `EJD-DA-IsFalse()`, `EJD-DA-IsNull()`, `EJD-DA-IsNumber()`, `EJD-DA-IsReal()`, `EJD-DA-IsString()`, `EJD-DA-IsObject()` and `EJD-DA-IsArray()`.

Whether a name exists at all is answered by a dedicated tag. It remembers the name in the process.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{EJD-DA-NameExists(AdditionalInfo.Crosslinks,jdat)}
   Es gibt ein Element mit diesem Namen: ~EJD-LastNameAccessed~
{/EJD-DA-NameExists(AdditionalInfo.Crosslinks,jdat)}
```

> [!NOTE]
>
> The output is `Crosslinks`, i.e. the last part of the path, not the whole path.

Reference: EJD-DA-IsTrue() · EJD-DA-IsFalse() · EJD-DA-IsNull() · EJD-DA-IsNumber() · EJD-DA-IsObject() · EJD-DA-IsReal() · EJD-DA-IsString() · EJD-DA-IsArray() · EJD-DA-NameExists()

## Iterating over elements

If you do not know the names of the elements in advance, `EJD-ElementIterator()` iterates over them. As a loop, the tag repeats the code; as a single tag, it outputs the name of the current element.

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{
   "Customer": "D200299",
   "Items": {
      "001119090": { "Sales CY": 11, "Sales PY": 174 },
      "001129090": { "Sales CY": 76, "Sales PY": 650 },
      "001169090": { "Sales CY": 5,  "Sales PY": 206, "OrderBacklog": 1 },
      "001189090": { "OrderBacklog": 1 }
   }
}
```

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~EJD-LoadData(global,D200299.json,bezuege)~

{EJD-DataOK(bezuege)}
   ~EJD-SetUseID(bezuege)~

   {@EJD-ElementIterator(Items)}
      Artikel: ~EJD-ElementIterator~
      Letztes Jahr: ~EJD-DA-Value(Items.$EJD-ElementIterator$.Sales PY)~
      Dieses Jahr: ~EJD-DA-Value(Items.$EJD-ElementIterator$.Sales CY)~
      Auftragsbestand: ~EJD-DA-Value(Items.$EJD-ElementIterator$.OrderBacklog)~<br>
   {/@EJD-ElementIterator(Items)}

{/EJD-DataOK(bezuege)}
```

```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
Artikel: 001119090 Letztes Jahr: 174 Dieses Jahr: 11 Auftragsbestand:
Artikel: 001129090 Letztes Jahr: 650 Dieses Jahr: 76 Auftragsbestand:
Artikel: 001169090 Letztes Jahr: 206 Dieses Jahr: 5 Auftragsbestand: 1
Artikel: 001189090 Letztes Jahr: Dieses Jahr: Auftragsbestand: 1
```

> [!NOTE]
>
> If an element is missing, the position stays empty, without an error. Where this is a problem, check beforehand with `EJD-DA-NameExists()`.

Reference: EJD-ElementIterator()

## Generating your own JSON data

The shop can also build JSON data itself or modify loaded data and then output it. Three rules apply:

* If the element already exists under the specified path, it is overwritten.
* If it does not exist yet, it is created.
* Exactly one element can be edited per call.

### Simple values

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~EJD-CreateNewData(jdat)~

{EJD-DataOK(jdat)}
   ~EJD-DA-SetStringValue(testString,abc,jdat)~
   ~EJD-DA-SetNumberValue(testInteger,1,jdat)~
   ~EJD-DA-SetRealValue(testReal,1.23,jdat)~
   ~EJD-DA-SetToTrue(testTrue,jdat)~
   ~EJD-DA-SetToFalse(testFalse,jdat)~
   ~EJD-DA-SetToNull(testNull,jdat)~

   ~EJD-RawDataOutput(jdat)~
{/EJD-DataOK(jdat)}
```

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{ "testString": "abc", "testInteger": 1, "testReal": 1.23, "testTrue": true, "testFalse": false, "testNull": null }
```

### Arrays

An empty array is created and then extended position by position. Whether you alternate between extending and filling, or first create all positions and then fill them, is up to you.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~EJD-CreateNewData(jdat)~

{EJD-DataOK(jdat)}
   ~EJD-DA-SetToEmptyArray(Crosslinks,jdat)~
   ~EJD-DA-ArrayExtend(Crosslinks,jdat)~
   ~EJD-DA-SetStringValue(Crosslinks[0],A-12345,jdat)~
   ~EJD-DA-ArrayExtend(Crosslinks,jdat)~
   ~EJD-DA-SetStringValue(Crosslinks[1],A-2323,jdat)~

   ~EJD-RawDataOutput(jdat)~
{/EJD-DataOK(jdat)}
```

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{ "Crosslinks": [ "A-12345", "A-2323" ] }
```

If the array itself is to be the top level, the path is `_root_`.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~EJD-DA-SetToEmptyArray(_root_,jdat)~
~EJD-DA-ArrayExtend(_root_,jdat)~
~EJD-DA-SetStringValue(_root_[0],A-12345,jdat)~
```

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
[ "A-12345" ]
```

Removing an element:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~EJD-DA-DeleteElement(Crosslinks[1],jdat)~
```

### Nested data

Each level is first created as an empty object and then filled.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~EJD-CreateNewData(jdat)~

{EJD-DataOK(jdat)}
   ~EJD-DA-SetToEmptyObject(Data,jdat)~
   ~EJD-DA-SetToEmptyObject(Data.Images,jdat)~
   ~EJD-DA-SetStringValue(Data.Images.Image small,img-5678.jpg,jdat)~
   ~EJD-DA-SetStringValue(Data.Images.Image big,img-1234.jpg,jdat)~

   ~EJD-DA-SetToEmptyArray(Data.Crosslinks,jdat)~
   ~EJD-DA-ArrayExtend(Data.Crosslinks,jdat)~
   ~EJD-DA-SetStringValue(Data.Crosslinks[0],A-2256,jdat)~

   ~EJD-RawDataOutput(jdat)~
{/EJD-DataOK(jdat)}
```

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{ "Data": { "Images": { "Image small": "img-5678.jpg", "Image big": "img-1234.jpg" }, "Crosslinks": [ "A-2256" ] } }
```

### Checking whether the modification succeeded

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{EJD-ModificationOK}
   JSON-Daten erfolgreich geändert.
{/EJD-ModificationOK}

{!EJD-ModificationOK}
   Fehler: ~EJD-ModificationOK~
{/!EJD-ModificationOK}

~EJD-ResetModificationOK~
```

> [!WARNING]
>
> The error state persists even if a later modification succeeds. Therefore reset it with `EJD-ResetModificationOK`; otherwise, from the first failed modification onwards, you will always be checking the same old error.

Reference: EJD-CreateNewData() · EJD-DA-SetStringValue() · EJD-DA-SetNumberValue() · EJD-DA-SetRealValue() · EJD-DA-SetToTrue() · EJD-DA-SetToFalse() · EJD-DA-SetToNull() · EJD-DA-SetToEmptyArray() · EJD-DA-SetToEmptyObject() · EJD-DA-ArrayExtend() · EJD-DA-DeleteElement() · EJD-RawDataOutput() · EJD-ModificationOK · EJD-ResetModificationOK

## Processing data from external systems

Responses from payment providers, shipping service providers or the shop system itself are not available as files. They arrive at the moment of the call and are therefore called internal.

> [!NOTE]
>
> With files, you know what they contain because you uploaded them yourself. With internal data, this is often not the case. `EJD-RawDataOutput()` therefore outputs everything that has arrived. This is the fastest way to find out what you are dealing with.

### Step 1: Passing the data to the interface

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<!-- Antwort auf "getOrderDetails" bei Kauf auf Rechnung über PayPal Checkout -->
~EJD-SetRawDataInput($PPC-OrderDetailsRawResponse$)~

<!-- Antwort mit dem Zahlungstoken von Paymorrow -->
~EJD-SetRawDataInput($PAYMORROW-JSONResponseGetPaymentToken$)~

<!-- Antwort der Sendungsverfolgung -->
~EJD-SetRawDataInput($SHIPTRACK-JSONResult$)~
```

You can find out which name applies to your case from the respective service provider or from WEBSALE. If the data arrives hex-encoded, use `EJD-SetRawDataHexCodedInput()` instead.

### Step 2: Loading and assigning an identifier

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~EJD-SetRawDataInput($XYZ-technischeBezeichnung-JSON$)~

~EJD-LoadData(intern,rawdatainput,jdat)~

~EJD-RawDataOutput(jdat)~
```

For internal data, the second parameter is not a path but a technical name that depends on the use case.

> [!NOTE]
>
> Some internal data comes directly from the shop system and does not need step 1. The hreflang information, for example, can be loaded directly:
>
> ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
> ~EJD-LoadData(intern,hreflang-prod-$PR-ProdIndex$,href)~
> ~EJD-RawDataOutput(href)~
> ```

Everything else, i.e. checking, accessing individual values and output, works the same as with files.

Reference: EJD-SetRawDataInput() · EJD-SetRawDataHexCodedInput()

Guide: hreflang attribute

## Related topics

* Use cases: JSON interface
* Guide: Embedding external content
* Guide: Exchanging data with external systems
* Guide: DHL shipment tracking


## Related topics

- [Interfaces](https://dokumentation.websale.de/en/v8s/schnittstellen.md)
- [EJD- (JSON interface)](https://dokumentation.websale.de/en/v8s/referenz/tags/ejd.md)
- [External services: Overview](https://dokumentation.websale.de/en/v8s/externe-dienste/externe-dienste.md)
- [EASYCREDIT- (installment purchase)](https://dokumentation.websale.de/en/v8s/referenz/tags/easycredit.md)
- [KLARNA- (Klarna Payments)](https://dokumentation.websale.de/en/v8s/referenz/tags/klarna-payments.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.