> ## 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.

# Exchanging data with external systems

> Send data asynchronously to third-party systems (ASSE), fetch product data synchronously from them (RPDE), and pass prices in technical format.

Besides content that comes into the shop from outside, there is the reverse route and a special case in between. This page covers both directions and the format in which numbers should cross the system boundary.

| Task | Tool | Does the shop wait? |
| - | - | - |
| Send data to a third-party system | ASSE | no |
| Fetch product data from a third-party system | RPDE | yes |
| Output prices and quantities in machine-readable form | technical tags | not applicable |

## Sending data: ASSE

Asynchronous Server-Side Events, ASSE for short, transmits any data from the shop via HTTPS to third-party systems. The format is free; JSON and XML are common. Typical uses are order data, newsletter sign-ups and tracking events.

The key word is asynchronous: The data goes from the shop server to the recipient, not via the visitor's browser. Page rendering does not wait for the response. If the remote system does not respond at all, the visitor notices nothing.

| Property | Options |
| - | - |
| Target | one or more addresses, exclusively via HTTPS |
| Transfer method | POST, GET or PUT |
| Data format | free, JSON and XML are common |
| Additional information | custom parameter name and additional entries in the HTTP header |
| Error handling | multiple delivery attempts, plus a time span for the response |

> [!WARNING]
>
> Transmission errors are visible neither in the shop nor in the online service area, precisely because the transfer runs asynchronously. If all delivery attempts fail, the data ends up in an error directory, and WEBSALE system monitoring contacts your shop administrator.

### Step 1: Activation

ASSE must be activated, either globally or per subshop. Contact your WEBSALE contact person.

### Step 2: Configuring the transfer

Each transfer gets its own `<+Entry>` in the `<ASSE>` section of `shop.config`.

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<ASSE>
   <+Entry>
      ID              = shopconfirm
      Endpoint        = https://api.shop.de/shop-certification/v2/order/log
      Type            = POST
      ContentType     = application/json
      ServiceCategory = OrderNotification
   </+Entry>
</ASSE>
```

| Parameter | Meaning |
| - | - |
| `ID` | unique name used to trigger the transfer in the template |
| `Endpoint` | address of the recipient, WEBSALE tags are allowed here |
| `Type` | `POST`, `GET` or `PUT` |
| `ContentType` | format of the data sent, for example `application/json` |
| `ServiceCategory` | `Tracking` or `OrderNotification`, behind which are the values predefined by WEBSALE for time span and delivery attempts |

> [!NOTE]
>
> The value for `ContentType` is determined by the recipient. Enter exactly what its documentation requires.

### When a delivery counts as successful

Without further specification, any response counts as success. Using `<DefinitionOfOK>`, you define what really counts. Multiple conditions are combined with AND, so all of them must be met.

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<ASSE>
   <+Entry>
      ...
      <DefinitionOfOK>
         <+ConditionGroup>
            <+Condition>
               Proof        = HTTP-StatusCode
               DataSelector =
               Type         = value
               Value        = 200
            </+Condition>
         </+ConditionGroup>
      </DefinitionOfOK>
   </+Entry>
</ASSE>
```

| Value for `Proof` | What is checked |
| - | - |
| `HTTP-StatusCode` | the status code of the response, for example `200` |
| `ContentType` | the format of the response |
| `ResponsePlain` | the response text itself, for example `OK` |
| `ResponseJSON` | whether the response can be read as JSON at all |
| `ResponseJSONData` | a specific data field of the response, selected via `DataSelector` |

If the condition is met, the delivery is considered complete and no further attempts follow.

### Additional entries in the HTTP header

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<ASSE>
   <+Entry>
      ...
      <AdditionalHeaders>
         <+HttpHeader>
            Name  =
            Value =
         </+HttpHeader>
      </AdditionalHeaders>
   </+Entry>
</ASSE>
```

Reference: ASSE section

### Step 3: Storing credentials securely

If a key or password belongs in the data, do not write it into the template. Stored in the `<FreeMessages-Txt>` section, it does not appear in plain text in the editing templates on the server.

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<FreeMessages-Txt>
   MyApiKey = abcdef12345
</FreeMessages-Txt>
```

In the template, you retrieve the value via the corresponding tag, here `~FMSG-MyApiKey~`.

Reference: FreeMessages-Txt section

Guide: Defining free standard texts

### Step 4: Assembling and sending the data

The transfer is triggered with `ASSE-Fire()`. The tag takes two arguments: the identifier from the configuration and the data to be sent.

The following example assembles the order data on the order confirmation page and sends it.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~DC-FPFireJSON_set({"apiKey": "$FMSG-MyApiKey$", "email": "$A-E-Mail$", )~
~DC-FPFireJSON_append("orderId": "$WS-OrderID$", "productItemIds": )~

{BASKET-PR-Data}
   ~DC-Int1_set(0)~
   ~DC-FPFireJSON_append([
      {@BASKET-PR-Data}
         $DC-Int1_add(1)${!DC-Int1(1)},{/!DC-Int1(1)}"$BASKET-PR-Number$"
      {/@BASKET-PR-Data}
   ]})~
{/BASKET-PR-Data}

~ASSE-Fire(shopconfirm,$WS-DisableXSSProtectionOnce$$DC-FPFireJSON$)~
```

> [!WARNING]
>
> Within a tag argument, other tags are written with dollar signs, not with tildes. So `$FMSG-MyApiKey$` belongs in the data structure; `~FMSG-MyApiKey~` would not be replaced there.

The counter in the loop inserts the comma between the entries, but not before the first one. The result is:

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{
   "apiKey": "abcdef12345",
   "email": "kunde@example.de",
   "orderId": "20250042",
   "productItemIds": ["4711", "4712"]
}
```

> [!NOTE]
>
> Instead of assembling the data with `DC-FPX_append`, it can also be generated via the JSON interface. For nested data, that is the clearer route.

### Detecting errors when triggering

Configuration errors when generating the event are reported by a dedicated tag. During setup, place it below the code that triggers the transfer.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{ASSE-LastErrorCode}
   Errorcode des aufgetretenen Fehlers: ~ASSE-LastErrorCode~
{/ASSE-LastErrorCode}
```

> [!NOTE]
>
> To check the data sent, services that provide an address for receiving and display what was received are useful, for example webhook.site. You can check the response of the real remote system with a tool such as reqbin.com.

Reference: ASSE-Fire() · ASSE-LastErrorCode · Freely usable DesignControl tags DC-FPX · DC-FPX\_set() · DC-FPX\_append

Application examples: ASSE

## Fetching product data: RPDE

RPDE stands for RemoteProductDataEnrichment. With it, the shop queries technical product data fields from a third-party system during page rendering and uses them immediately. Existing fields can be enriched or overwritten. The data is not stored at WEBSALE but comes via a secured server-to-server connection.

Typical cases are daily prices or values that only result from the customer's input.

> [!WARNING]
>
> RPDE is subject to strict limits:
>
> * Exactly one query is possible per displayed page, including on search result lists.
> * The product must be fully resolved, so all dependent variants must be selected.
> * For set products, the function is only available for the parent product, and this must be marked accordingly in the product data.
> * RPDE cannot be used together with the cookie basket or the order generator.
> * The function cannot be guaranteed alongside other external service providers such as W2P.

You assemble the data passed to the third-party system freely in the template. The response is expected in JSON format and is read via the JSON interface.

### Example: Labelprint24

Labelprint24 prints custom-sized packaging. The customer enters length, width and height, the shop sends these values together with the product's basic data, and Labelprint24 checks whether it can be manufactured that way and returns the price and weight. Both end up in the product data.

A contract with Labelprint24 is required, and the connection must be set up by WEBSALE.

#### Step 1: Marking product data

The relevant products are marked in the product data. The details are in the interface documentation "Produkte PRO".

#### Step 2: Adding an error message

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<NotifyMessages-Txt>
   ...
   RPDE_Labelprint-BasketError = Das Produkt konnte nicht in den Warenkorb gelegt werden. Bitte versuchen Sie es erneut oder kontaktieren Sie uns.
   ...
</NotifyMessages-Txt>
```

#### Step 3: Assigning the template

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<Templates>
   ...
   RPDE_Labelprint = extern_labelprint.json
   ...
</Templates>
```

#### Step 4: Creating the transfer template

Create the template under the assigned name in your template directory.

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{
   "action": "get_product_price",
   "token": "~WS-RPDE_Labelprint_token~",
   "language": "de-AT",
   "currency": "~WS-Currency~",
   "product": {
      "id": "~PR-Index~",
      "deeplink": "~PR-SetLink~",
      "height": ~PR-RPDE_Labelprint_height(1)~,
      "width": ~PR-RPDE_Labelprint_width(1)~,
      "length": ~PR-RPDE_Labelprint_length(1)~,
      "quantity": ~PR-Quantity~
   }
}
```

> [!WARNING]
>
> Labelprint24 determines which information the template must contain. Coordinate the content with them before you test.

#### Step 5: Input fields on the product detail view

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
RPDE: ~PR-RPDE~<br>
{PR-RPDE_Labelprint_width_input}
   Breite: <input type="text" name="~PR-RPDE_Labelprint_width_input~" value="~PR-RPDE_Labelprint_width(2)~" onBlur="SubmitSelection()">
   Länge:  <input type="text" name="~PR-RPDE_Labelprint_length_input~" value="~PR-RPDE_Labelprint_length(2)~" onBlur="SubmitSelection()">
   Höhe:   <input type="text" name="~PR-RPDE_Labelprint_height_input~" value="~PR-RPDE_Labelprint_height(2)~" onBlur="SubmitSelection()">

   {PR-RPDE_OK}Abfrage erfolgreich{/PR-RPDE_OK}
   {!PR-RPDE_OK}Abfrage nicht erfolgreich{/!PR-RPDE_OK}
{/PR-RPDE_Labelprint_width_input}
```

> [!NOTE]
>
> Reloading via AJAX when leaving the field is recommended, as in the example via `onBlur`. Otherwise, the customer only finds out after submitting whether their dimensions can be manufactured.

> [!NOTE]
>
> Length, width and height cannot be prefilled, and the shop does not check them on the server side. The check is performed solely by the third-party system.

#### Step 6: Display in the basket

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
RPDE: ~BASKET-PR-RPDE~<br>
{BASKET-PR-RPDE_Labelprint_width_input}
   Breite: ~BASKET-PR-RPDE_Labelprint_width~
   Länge:  ~BASKET-PR-RPDE_Labelprint_length~
   Höhe:   ~BASKET-PR-RPDE_Labelprint_height~
{/BASKET-PR-RPDE_Labelprint_width_input}
```

#### Troubleshooting

For testing purposes, output messages from the interface via `MSG-InternalErrorMessage`. Two further tags let you look at the data actually sent and received.

Reference: MSG-InternalErrorMessage · PR-RPDE · PR-RPDE\_OK · PR-RPDE\_Data · BASKET-PR-RPDE\_Data · WS-RPDE\_DebugInfo\_RequestData · WS-RPDE\_DebugInfo\_ResponseData

Reference: WS-RPDE\_Labelprint\_token · PR-RPDE\_Labelprint\_width · PR-RPDE\_Labelprint\_length · PR-RPDE\_Labelprint\_height

## Passing prices in machine-readable form

Prices shown in the shop are formatted for humans: with thousands separators, decimal commas and currency symbols. A third-party system cannot do anything with that. For the transfer, there is therefore a technical counterpart for all amounts and quantities.

Without additional arguments, these tags are output without a thousands separator, with a period as the decimal separator and with two decimal places.

| Tag | Content |
| - | - |
| `BASKET-PR-TechnicalPrice` | Price per product of a basket item |
| `BASKET-PR-TechnicalSum` | Total of a basket item |
| `BASKET-PR-TechnicalSetPrice` | Unit price of a set in the basket |
| `BASKET-PR-TechnicalSetSum` | Total price of a set in the basket |
| `BASKET-PR-TechnicalQuantity` | Quantity of a basket item |
| `BASKET-TechnicalValueOfGoods` | Pure value of goods without discounts |
| `BASKET-TechnicalSubTotalSum` | Value of goods with discounts, gross or net as defined in the shop |
| `BASKET-TechnicalSubTotalGross` | Gross value of goods with discounts, for net prices |
| `BASKET-TechnicalSubTotalNet` | Net value of goods with discounts, for gross prices |
| `BASKET-TechnicalSubTotalVAT` | VAT on the value of goods |
| `BASKET-TechnicalDeliveryCost` | Shipping costs |
| `BASKET-TechnicalPaymentCost` | Fee of the selected payment method |
| `BASKET-TechnicalOrderTotal` | Grand total |

### Adjusting the format

All tags take up to three comma-separated arguments:

| Position | Meaning | Default |
| - | - | - |
| 1 | Decimal separator | `.` |
| 2 | Number of decimal places | `2` |
| 3 | Multiplier | `1` |

For a value of 12.99, the result is:

| Notation | Result |
| - | - |
| `~BASKET-TechnicalOrderTotal~` | `12.99` |
| `~BASKET-TechnicalOrderTotal(\,)~` | `12,99` |
| `~BASKET-TechnicalOrderTotal(#)~` | `12#99` |
| `~BASKET-TechnicalOrderTotal(,4)~` | `12.9900` |
| `~BASKET-TechnicalOrderTotal(,,2)~` | `25.98` |
| `~BASKET-TechnicalOrderTotal(,0,100)~` | `1299` |
| `~BASKET-TechnicalOrderTotal(\,,2,100)~` | `1299,00` |

> [!WARNING]
>
> A comma as a decimal separator must be written as `\,`. Unescaped, it separates the arguments from each other, and the shop reads it as an empty first argument.

> [!NOTE]
>
> An empty position means "keep the default". `(,0,100)` therefore leaves the decimal separator unchanged, sets zero decimal places and multiplies by 100. This is the usual form for systems that expect amounts in cents.

Guide: Displaying the basket

## Related topics

* Guide: Integrating external content
* Guide: JSON interface
* Guide: Integrating tracking
* Application examples: ASSE


## Related topics

- [External services: Overview](https://dokumentation.websale.de/en/v8s/externe-dienste/externe-dienste.md)
- [Integrating external content](https://dokumentation.websale.de/en/v8s/externe-dienste/externe-inhalte-einbinden.md)
- [ASSE- (Asynchronous data transfer)](https://dokumentation.websale.de/en/v8s/referenz/tags/asse.md)
- [JSON interface](https://dokumentation.websale.de/en/v8s/externe-dienste/json-schnittstelle.md)
- [Integrating Inxmail](https://dokumentation.websale.de/en/v8s/externe-dienste/inxmail.md)


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