diff --git a/external_entities.services.yml b/external_entities.services.yml
index 8f790cd2d49c7e94f6b2a38b02f810ca22236e93..32c4bd44b6aaf030b1e22c997e58b7e7606b8ad6 100644
--- a/external_entities.services.yml
+++ b/external_entities.services.yml
@@ -34,3 +34,7 @@ services:
     arguments: ['@entity_type.manager']
     tags:
       - { name: route_processor_outbound }
+  serialization.external_entities_api_json:
+    class: \Drupal\external_entities\Serialization\JsonApi
+    tags:
+      - { name: external_entity_response_decoder }
diff --git a/src/Plugin/ExternalEntities/StorageClient/JsonApi.php b/src/Plugin/ExternalEntities/StorageClient/JsonApi.php
index 23a3376e876d346042fc15737bf8cd828dcddc6e..16b3402e46383a013d64755649c60b3481f32a8f 100644
--- a/src/Plugin/ExternalEntities/StorageClient/JsonApi.php
+++ b/src/Plugin/ExternalEntities/StorageClient/JsonApi.php
@@ -67,7 +67,7 @@ class JsonApi extends RestClient {
       ],
       'response_format' => [
         '#type' => 'hidden',
-        '#default_value' => 'json',
+        '#default_value' => 'external_entities_api_json',
       ],
       'data_path' => [
         '#type' => NULL,
@@ -90,7 +90,7 @@ class JsonApi extends RestClient {
       ],
       'pager' => [
         '#type' => NULL,
-        // Drupal uses a 50 elements per bage basis so we go for 1 query per
+        // Drupal uses a 50 elements per page basis so we go for 1 query per
         // page. 50 is the JSON:API default limit anyway.
         'default_limit' => [
           '#type' => 'hidden',
@@ -347,16 +347,49 @@ class JsonApi extends RestClient {
 
     $result = parent::load($id);
 
-    // Check for "included".
-    if (!empty($result[1])) {
-      // JSONPath returned an array of object so we got "extra" from "included".
-      $included = array_slice($result, 1);
-      $result = $result[0];
-      $result['included'] = $included;
-    }
     static::$cachedData[$this->configuration['endpoint']][$id] = $result;
 
     return $result;
   }
 
+  protected function resolveRelationships(&$result): void
+  {
+    // Collect all includes and index them by type and id.
+    $includedRegistry = [];
+    foreach ($result['included'] as $included_entry) {
+      $included_id = ($included_entry['type'] ?? NULL) . ':' . $included_entry['id'];
+      $includedRegistry[$included_id] = $included_entry;
+    }
+    $this->_resolveRelationsRecursive($result['relationships'], $includedRegistry);
+  }
+
+  protected function _resolveRelationsRecursive(&$relationships, $includedRegistry): void
+  {
+    foreach ($relationships as $field => $relationship) {
+      if (!empty($relationship['data'])) {
+        // Relationships can be single or multi-value.
+        if (isset($relationship['data']['id'])) {
+          $this->_mapRelationshipData($relationships[$field]['data'], $includedRegistry);
+        } else {
+          foreach ($relationship['data'] as $i => $data) {
+            $this->_mapRelationshipData($relationships[$field]['data'][$i], $includedRegistry);
+          }
+        }
+      }
+    }
+  }
+
+  protected function _mapRelationshipData(&$data, array $includedRegistry): void
+  {
+    if (isset($data['id'])) {
+      $included_id = ($data['type'] ?? NULL) . ':' . $data['id'];
+      if (isset($includedRegistry[$included_id])) {
+        $data['included'] = $includedRegistry[$included_id];
+      }
+      if (!empty($data['relationships'])) {
+        $this->_resolveRelationsRecursive($data['relationships'], $includedRegistry);
+      }
+    }
+  }
+
 }
diff --git a/src/Serialization/JsonApi.php b/src/Serialization/JsonApi.php
new file mode 100644
index 0000000000000000000000000000000000000000..282983bf5a9fd7e5bcef73b2e3cb61d5589c74be
--- /dev/null
+++ b/src/Serialization/JsonApi.php
@@ -0,0 +1,96 @@
+<?php
+
+namespace Drupal\external_entities\Serialization;
+
+use Drupal\Component\Serialization\Json;
+
+/**
+ * Denormalizes the json:api response
+ *
+ * This is handled via a Serialization handler as this is the first opportunity
+ * to handle raw responses fetched by the RestClient. Which means the processing
+ * applies to _all_ types of requests single & multiple load scenarios.
+ *
+ * The denormalization is necessary because json:api normalizes data references
+ * into the "included" property which is outside the actual data set.
+ * However, jsonpath does not provide a sane way to access this included data
+ * bits from the result item itself.
+ * So this recursive handling will put _all_ included data into each result as
+ * well as adds the related included data to the relationships referencing the
+ * data.
+ * Allowing relative simple jsonPath expressions like:
+ * $.relationships.field_taxonomy_terms.data.included.attributes.field_body
+ *
+ * @TODO See if there's any way the existing jsonapi denormalizer can be used:
+ * \Drupal\jsonapi\Serializer\Serializer::denormalize()
+ */
+class JsonApi extends Json {
+
+  public static function getFileExtension()
+  {
+    return 'external_entities_api_json';
+  }
+
+  /**
+   * Denormalizes the json:api response
+   *
+   * @param $string
+   *
+   * @return mixed
+   */
+  public static function decode($string)
+  {
+    $decoded_data = parent::decode($string);
+
+    if (!empty($decoded_data['data']) && !empty($decoded_data['included'])) {
+      foreach ($decoded_data['data'] as $i => $result) {
+        $decoded_data['data'][$i]['included'] = $decoded_data['included'];
+        if (!empty($result['relationships'])) {
+          static::resolveRelationships($decoded_data['data'][$i]);
+        }
+      }
+    }
+
+    return $decoded_data;
+  }
+
+  protected static function resolveRelationships(&$result): void
+  {
+    // Collect all includes and index them by type and id.
+    $includedRegistry = [];
+    foreach ($result['included'] as $included_entry) {
+      $included_id = ($included_entry['type'] ?? NULL) . ':' . $included_entry['id'];
+      $includedRegistry[$included_id] = $included_entry;
+    }
+    static::_resolveRelationsRecursive($result['relationships'], $includedRegistry);
+  }
+
+  protected static function _resolveRelationsRecursive(&$relationships, $includedRegistry): void
+  {
+    foreach ($relationships as $field => $relationship) {
+      if (!empty($relationship['data'])) {
+        // Relationships can be single or multi-value.
+        if (isset($relationship['data']['id'])) {
+          static::_mapRelationshipData($relationships[$field]['data'], $includedRegistry);
+        } else {
+          foreach ($relationship['data'] as $i => $data) {
+            static::_mapRelationshipData($relationships[$field]['data'][$i], $includedRegistry);
+          }
+        }
+      }
+    }
+  }
+
+  protected static function _mapRelationshipData(&$data, array $includedRegistry): void
+  {
+    if (isset($data['id'])) {
+      $included_id = ($data['type'] ?? NULL) . ':' . $data['id'];
+      if (isset($includedRegistry[$included_id])) {
+        $data['included'] = $includedRegistry[$included_id];
+      }
+      if (!empty($data['relationships'])) {
+        static::_resolveRelationsRecursive($data['relationships'], $includedRegistry);
+      }
+    }
+  }
+}