diff --git a/api/.eslintrc.js b/api/.eslintrc.js
index f6c62bee279534a2a2ce7ee4424670655fbd2a4c..8e34f1ea92b73633f2be969865474d6ca4e5cb9c 100644
--- a/api/.eslintrc.js
+++ b/api/.eslintrc.js
@@ -20,5 +20,6 @@ module.exports = {
     '@typescript-eslint/explicit-function-return-type': 'off',
     '@typescript-eslint/explicit-module-boundary-types': 'off',
     '@typescript-eslint/no-explicit-any': 'off',
+    'prettier/prettier': ['error', { "endOfLine": "auto"}, { usePrettierrc: true }],
   },
 };
diff --git a/api/package-lock.json b/api/package-lock.json
index a0fb8a8365088a38d2f372e8de42ac083a77386a..88182859b9a42510792332bff648111830b823b3 100644
--- a/api/package-lock.json
+++ b/api/package-lock.json
@@ -19,6 +19,8 @@
         "apollo-server-express": "^3.3.0",
         "axios": "^0.21.1",
         "graphql": "^15.5.3",
+        "graphql-type-json": "^0.3.2",
+        "jsonata": "^1.8.5",
         "reflect-metadata": "^0.1.13",
         "rimraf": "^3.0.2",
         "rxjs": "^7.2.0"
@@ -5581,6 +5583,14 @@
         "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0"
       }
     },
+    "node_modules/graphql-type-json": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/graphql-type-json/-/graphql-type-json-0.3.2.tgz",
+      "integrity": "sha512-J+vjof74oMlCWXSvt0DOf2APEdZOCdubEvGDUAlqH//VBYcOYsGgRW7Xzorr44LvkjiuvecWc8fChxuZZbChtg==",
+      "peerDependencies": {
+        "graphql": ">=0.8.0"
+      }
+    },
     "node_modules/graphql-ws": {
       "version": "5.4.0",
       "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.4.0.tgz",
@@ -7172,6 +7182,14 @@
         "node": ">=6"
       }
     },
+    "node_modules/jsonata": {
+      "version": "1.8.5",
+      "resolved": "https://registry.npmjs.org/jsonata/-/jsonata-1.8.5.tgz",
+      "integrity": "sha512-ilDyTBkg6qhNoNVr8PUPzz5GYvRK+REKOM5MdOGzH2y6V4yvPRMegSvbZLpbTtI0QAgz09QM7drDhSHUlwp9pA==",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
     "node_modules/jsonc-parser": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz",
@@ -14879,6 +14897,12 @@
         "tslib": "^2.1.0"
       }
     },
+    "graphql-type-json": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/graphql-type-json/-/graphql-type-json-0.3.2.tgz",
+      "integrity": "sha512-J+vjof74oMlCWXSvt0DOf2APEdZOCdubEvGDUAlqH//VBYcOYsGgRW7Xzorr44LvkjiuvecWc8fChxuZZbChtg==",
+      "requires": {}
+    },
     "graphql-ws": {
       "version": "5.4.0",
       "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.4.0.tgz",
@@ -16079,6 +16103,11 @@
         "minimist": "^1.2.5"
       }
     },
+    "jsonata": {
+      "version": "1.8.5",
+      "resolved": "https://registry.npmjs.org/jsonata/-/jsonata-1.8.5.tgz",
+      "integrity": "sha512-ilDyTBkg6qhNoNVr8PUPzz5GYvRK+REKOM5MdOGzH2y6V4yvPRMegSvbZLpbTtI0QAgz09QM7drDhSHUlwp9pA=="
+    },
     "jsonc-parser": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz",
diff --git a/api/package.json b/api/package.json
index 848e67878898649298ce812ddcef10ec95c47dc1..1885442d70f4ac545ac7fc662ec9bef27d1d21de 100644
--- a/api/package.json
+++ b/api/package.json
@@ -32,6 +32,8 @@
     "apollo-server-express": "^3.3.0",
     "axios": "^0.21.1",
     "graphql": "^15.5.3",
+    "graphql-type-json": "^0.3.2",
+    "jsonata": "^1.8.5",
     "reflect-metadata": "^0.1.13",
     "rimraf": "^3.0.2",
     "rxjs": "^7.2.0"
@@ -76,4 +78,4 @@
     "coverageDirectory": "../coverage",
     "testEnvironment": "node"
   }
-}
\ No newline at end of file
+}
diff --git a/api/src/engine/connectors/datashield/main.connector.ts b/api/src/engine/connectors/datashield/main.connector.ts
index c81cc65fbef911bcb160acc7bdb516ec3aa80e1d..45bf43a1df7f8fc7877f297a69e5edf6eec50d6d 100644
--- a/api/src/engine/connectors/datashield/main.connector.ts
+++ b/api/src/engine/connectors/datashield/main.connector.ts
@@ -1,14 +1,43 @@
 import { Observable } from 'rxjs';
 import { IEngineService } from 'src/engine/engine.interfaces';
 import { Domain } from 'src/engine/models/domain.model';
+import { ExperimentCreateInput } from 'src/engine/models/experiment/input/experiment-create.input';
+import {
+  Experiment,
+  PartialExperiment,
+} from 'src/engine/models/experiment/experiment.model';
+import { ListExperiments } from 'src/engine/models/experiment/list-experiments.model';
+import { ExperimentEditInput } from 'src/engine/models/experiment/input/experiment-edit.input';
 
 export default class DataShieldService implements IEngineService {
-  getDomains(): Domain[] {
+  createExperiment(
+    data: ExperimentCreateInput,
+    isTransient: boolean,
+  ): Experiment | Promise<Experiment> {
     throw new Error('Method not implemented.');
   }
-
-  demo(): string {
-    return 'datashield';
+  listExperiments(
+    page: number,
+    name: string,
+  ): ListExperiments | Promise<ListExperiments> {
+    throw new Error('Method not implemented.');
+  }
+  getExperiment(uuid: string): Experiment | Promise<Experiment> {
+    throw new Error('Method not implemented.');
+  }
+  removeExperiment(
+    uuid: string,
+  ): PartialExperiment | Promise<PartialExperiment> {
+    throw new Error('Method not implemented.');
+  }
+  editExperient(
+    uuid: string,
+    expriment: ExperimentEditInput,
+  ): Experiment | Promise<Experiment> {
+    throw new Error('Method not implemented.');
+  }
+  getDomains(): Domain[] {
+    throw new Error('Method not implemented.');
   }
 
   getActiveUser(): Observable<string> {
@@ -19,7 +48,7 @@ export default class DataShieldService implements IEngineService {
     throw new Error('Method not implemented.');
   }
 
-  getExperiment(): Observable<string> {
+  getExperimentAPI(): Observable<string> {
     throw new Error('Method not implemented.');
   }
 
@@ -27,7 +56,7 @@ export default class DataShieldService implements IEngineService {
     throw new Error('Method not implemented.');
   }
 
-  editExperiment(): Observable<string> {
+  editExperimentAPI(): Observable<string> {
     throw new Error('Method not implemented.');
   }
 
diff --git a/api/src/engine/connectors/exareme/converters.ts b/api/src/engine/connectors/exareme/converters.ts
index 72e62044aa2241b824b46d376ff8c14c31b35779..63d689f3fecf19bf9987d640bf916df3ec464a0f 100644
--- a/api/src/engine/connectors/exareme/converters.ts
+++ b/api/src/engine/connectors/exareme/converters.ts
@@ -1,9 +1,20 @@
 import { Category } from 'src/engine/models/category.model';
+import { AlgorithmParameter } from 'src/engine/models/experiment/algorithm-parameter.model';
+import {
+  Experiment,
+  ResultUnion,
+} from 'src/engine/models/experiment/experiment.model';
+import { ExperimentCreateInput } from 'src/engine/models/experiment/input/experiment-create.input';
 import { Group } from 'src/engine/models/group.model';
+import { RawResult } from 'src/engine/models/result/raw-result.model';
+import { TableResult } from 'src/engine/models/result/table-result.model';
 import { Variable } from 'src/engine/models/variable.model';
+import { Entity } from './interfaces/entity.interface';
+import { ExperimentData } from './interfaces/experiment/experiment.interface';
+import { ResultExperiment } from './interfaces/experiment/result-experiment.interface';
 import { Hierarchy } from './interfaces/hierarchy.interface';
 import { VariableEntity } from './interfaces/variable-entity.interface';
-import { Entity } from './interfaces/entity.interface';
+import { transformToExperiment, transientToTable } from './transformations';
 
 export const dataToGroup = (data: Hierarchy): Group => {
   return {
@@ -33,3 +44,93 @@ export const dataToVariable = (data: VariableEntity): Variable => {
     groups: [],
   };
 };
+
+const algoParamInputToData = (param: AlgorithmParameter) => {
+  return {
+    name: param.name,
+    value: param.value.join(','),
+  };
+};
+
+export const experimentInputToData = (data: ExperimentCreateInput) => {
+  return {
+    algorithm: {
+      parameters: [
+        {
+          name: 'dataset',
+          value: data.datasets.join(','),
+        },
+        {
+          name: 'filter',
+          value: data.filter,
+        },
+        {
+          name: 'pathology',
+          value: data.domain,
+        },
+        {
+          name: 'y',
+          value: data.variables.join(','),
+        },
+      ].concat(data.algorithm.parameters.map(algoParamInputToData)),
+      type: data.algorithm.type ?? 'string',
+      name: data.algorithm.name,
+    },
+    name: data.name,
+  };
+};
+
+export const descriptiveDataToTableResult = (
+  data: ResultExperiment,
+): TableResult[] => {
+  return transientToTable.evaluate(data);
+};
+
+export const dataToExperiment = (data: ExperimentData): Experiment => {
+  const expTransform = transformToExperiment.evaluate(data);
+
+  const exp: Experiment = {
+    ...expTransform,
+    results: [],
+  };
+
+  exp.results = data.result
+    ? data.result
+        .map((result) => dataToResult(result, exp.algorithm.name))
+        .flat()
+    : [];
+
+  return exp;
+};
+
+export const dataToRaw = (result: ResultExperiment): RawResult[] => {
+  return [
+    {
+      data: result.data,
+    },
+  ];
+};
+
+export const dataToResult = (
+  result: ResultExperiment,
+  algo: string,
+): Array<typeof ResultUnion> => {
+  switch (result.type.toLowerCase()) {
+    case 'application/json':
+      return dataJSONtoResult(result, algo);
+    default:
+      return dataToRaw(result);
+  }
+};
+
+export const dataJSONtoResult = (
+  result: ResultExperiment,
+  algo: string,
+): Array<typeof ResultUnion> => {
+  switch (algo.toLowerCase()) {
+    case 'descriptive_stats':
+      return descriptiveDataToTableResult(result);
+    default:
+      return [];
+  }
+};
diff --git a/api/src/engine/connectors/exareme/interfaces/experiment/experiment.interface.ts b/api/src/engine/connectors/exareme/interfaces/experiment/experiment.interface.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7412cb0560c9eda88fe61dd4ebbf8128c94e2c62
--- /dev/null
+++ b/api/src/engine/connectors/exareme/interfaces/experiment/experiment.interface.ts
@@ -0,0 +1,11 @@
+import { ResultExperiment } from './result-experiment.interface';
+
+export interface ExperimentData {
+  name: string;
+  uuid?: string;
+  status?: string;
+  createdBy?: string;
+  shared?: boolean;
+  viewed?: boolean;
+  result?: ResultExperiment[];
+}
diff --git a/api/src/engine/connectors/exareme/interfaces/experiment/experiments.interface.ts b/api/src/engine/connectors/exareme/interfaces/experiment/experiments.interface.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5ef0c0f84568d7a7e87dd1f759c1db3b17e8066a
--- /dev/null
+++ b/api/src/engine/connectors/exareme/interfaces/experiment/experiments.interface.ts
@@ -0,0 +1,8 @@
+import { ExperimentData } from './experiment.interface';
+
+export interface ExperimentsData {
+  experiments: ExperimentData[];
+  currentpage?: number;
+  totalExperiments?: number;
+  totalPages?: number;
+}
diff --git a/api/src/engine/connectors/exareme/interfaces/experiment/result-experiment.interface.ts b/api/src/engine/connectors/exareme/interfaces/experiment/result-experiment.interface.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e655151c9e7b113a2dbff0402d8e99c61534adee
--- /dev/null
+++ b/api/src/engine/connectors/exareme/interfaces/experiment/result-experiment.interface.ts
@@ -0,0 +1,4 @@
+export interface ResultExperiment {
+  data: unknown;
+  type: string;
+}
diff --git a/api/src/engine/connectors/exareme/main.connector.ts b/api/src/engine/connectors/exareme/main.connector.ts
index aa8fd7d531f63c3b44f0c546619889269f8c0dcb..81ed14ab64999708295fd7bbbc38678994d1ba86 100644
--- a/api/src/engine/connectors/exareme/main.connector.ts
+++ b/api/src/engine/connectors/exareme/main.connector.ts
@@ -1,12 +1,27 @@
 import { HttpService } from '@nestjs/axios';
-import { HttpException, HttpStatus } from '@nestjs/common';
+import { BadRequestException, HttpException, HttpStatus } from '@nestjs/common';
 import { Request } from 'express';
 import { firstValueFrom, map, Observable } from 'rxjs';
 import { IEngineOptions, IEngineService } from 'src/engine/engine.interfaces';
 import { Domain } from 'src/engine/models/domain.model';
+import {
+  Experiment,
+  PartialExperiment,
+} from 'src/engine/models/experiment/experiment.model';
+import { ExperimentCreateInput } from 'src/engine/models/experiment/input/experiment-create.input';
+import { ExperimentEditInput } from 'src/engine/models/experiment/input/experiment-edit.input';
+import { ListExperiments } from 'src/engine/models/experiment/list-experiments.model';
 import { Group } from 'src/engine/models/group.model';
 import { Variable } from 'src/engine/models/variable.model';
-import { dataToCategory, dataToGroup, dataToVariable } from './converters';
+import {
+  dataToCategory,
+  dataToExperiment,
+  dataToGroup,
+  dataToVariable,
+  experimentInputToData,
+} from './converters';
+import { ExperimentData } from './interfaces/experiment/experiment.interface';
+import { ExperimentsData } from './interfaces/experiment/experiments.interface';
 import { Hierarchy } from './interfaces/hierarchy.interface';
 import { Pathology } from './interfaces/pathology.interface';
 
@@ -16,6 +31,71 @@ export default class ExaremeService implements IEngineService {
     private readonly httpService: HttpService,
   ) {}
 
+  async createExperiment(
+    data: ExperimentCreateInput,
+    isTransient = false,
+  ): Promise<Experiment> {
+    const form = experimentInputToData(data);
+
+    const path =
+      this.options.baseurl + `experiments${isTransient ? '/transient' : ''}`;
+
+    const resultAPI = await firstValueFrom(
+      this.httpService.post<ExperimentData>(path, form),
+    );
+
+    return dataToExperiment(resultAPI.data);
+  }
+
+  async listExperiments(page: number, name: string): Promise<ListExperiments> {
+    const path = this.options.baseurl + 'experiments';
+
+    const resultAPI = await firstValueFrom(
+      this.httpService.get<ExperimentsData>(path, { params: { page, name } }),
+    );
+
+    return {
+      ...resultAPI.data,
+      experiments: resultAPI.data.experiments.map(dataToExperiment),
+    };
+  }
+
+  async getExperiment(uuid: string): Promise<Experiment> {
+    const path = this.options.baseurl + `experiments/${uuid}`;
+
+    const resultAPI = await firstValueFrom(
+      this.httpService.get<ExperimentData>(path),
+    );
+
+    return dataToExperiment(resultAPI.data);
+  }
+
+  async editExperient(
+    uuid: string,
+    expriment: ExperimentEditInput,
+  ): Promise<Experiment> {
+    const path = this.options.baseurl + `experiments/${uuid}`;
+
+    const resultAPI = await firstValueFrom(
+      this.httpService.patch<ExperimentData>(path, expriment),
+    );
+
+    return dataToExperiment(resultAPI.data);
+  }
+
+  async removeExperiment(uuid: string): Promise<PartialExperiment> {
+    const path = this.options.baseurl + `experiments/${uuid}`;
+
+    try {
+      await firstValueFrom(this.httpService.delete(path));
+      return {
+        uuid: uuid,
+      };
+    } catch (error) {
+      throw new BadRequestException(`${uuid} does not exists`);
+    }
+  }
+
   async getDomains(ids: string[]): Promise<Domain[]> {
     const path = this.options.baseurl + 'pathologies';
 
@@ -48,10 +128,6 @@ export default class ExaremeService implements IEngineService {
     }
   }
 
-  demo(): string {
-    return 'exareme';
-  }
-
   getActiveUser(): Observable<string> {
     const path = this.options.baseurl + 'activeUser';
 
@@ -68,7 +144,7 @@ export default class ExaremeService implements IEngineService {
       .pipe(map((response) => response.data));
   }
 
-  getExperiment(uuid: string): Observable<string> {
+  getExperimentAPI(uuid: string): Observable<string> {
     const path = this.options.baseurl + `experiments/${uuid}`;
 
     return this.httpService
@@ -82,11 +158,11 @@ export default class ExaremeService implements IEngineService {
     return this.httpService.delete(path).pipe(map((response) => response.data));
   }
 
-  editExperiment(uuid: string, request: Request): Observable<string> {
+  editExperimentAPI(uuid: string, request: Request): Observable<string> {
     const path = this.options.baseurl + `experiments/${uuid}`;
 
     return this.httpService
-      .post(path, request.body)
+      .patch(path, request.body)
       .pipe(map((response) => response.data));
   }
 
@@ -106,22 +182,23 @@ export default class ExaremeService implements IEngineService {
       .pipe(map((response) => response.data));
   }
 
-  getExperiments(): Observable<string> {
+  getExperiments(request: Request): Observable<string> {
     const path = this.options.baseurl + 'experiments';
 
     return this.httpService
-      .get<string>(path)
+      .get<string>(path, { params: request.query })
       .pipe(map((response) => response.data));
   }
 
-  getAlgorithms(): Observable<string> {
+  getAlgorithms(request: Request): Observable<string> {
     const path = this.options.baseurl + 'algorithms';
 
     return this.httpService
-      .get<string>(path)
+      .get<string>(path, { params: request.query })
       .pipe(map((response) => response.data));
   }
 
+  // UTILITIES
   private flattenGroups = (data: Hierarchy): Group[] => {
     let groups: Group[] = [dataToGroup(data)];
 
diff --git a/api/src/engine/connectors/exareme/transformations.ts b/api/src/engine/connectors/exareme/transformations.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4f574db08df84e0023b924ec987809d025e6e4e1
--- /dev/null
+++ b/api/src/engine/connectors/exareme/transformations.ts
@@ -0,0 +1,76 @@
+// This file contains all transformation queries for JSONata
+// see : https://docs.jsonata.org/
+
+import * as jsonata from 'jsonata'; // old import style needed due to 'export = jsonata'
+
+export const transformToExperiment = jsonata(`
+( 
+    $params := ["y", "pathology", "dataset", "filter"];
+
+    {
+        "name": name,
+        "uuid": uuid,
+        "author": createdBy,
+        "viewed": viewed,
+        "status": status,
+        "createdAt": created,
+        "finishedAt": finished,
+        "shared": shared,
+        "updateAt": updated,
+        "domains": algorithm.parameters[name = "pathology"].value,
+        "variables": $split(algorithm.parameters[name = "y"].value, ','),
+        "filter": algorithm.parameters[name = "filter"].value,
+        "datasets": $split(algorithm.parameters[name = "dataset"].value, ','),
+        "algorithm": {
+            "name": algorithm.name,
+            "parameters" : 
+                algorithm.parameters[$not(name in $params)].({
+                    "name": name,
+                    "label": label,
+                    "value": value
+                })
+        }
+    }
+)
+`);
+
+export const transientToTable = jsonata(`
+( 
+    $e := function($x, $r) {($x != null) ? $x : ($r ? $r : '')};
+
+    $fn := function($o, $prefix) {
+        $type($o) = 'object' ? 
+        $each($o, function($v, $k) {(
+            $type($v) = 'object' ? { $k: $v.count & ' (' & $v.percentage & '%)' } : {
+                $k: $v
+            }
+        )}) ~> $merge()
+        : {}
+    };
+
+    data.[
+        $.single.*@$p#$i.(
+            $ks := $keys($p.*.data[$type($) = 'object']);
+            {
+            'groupBy' : 'single',
+            'name': $keys(%)[$i],
+            'headers': $append("", $keys(*)).{
+                'name': $,
+                'type': 'string'
+            },
+            'data' : [
+                [$keys(%)[$i], $p.*.($e(num_total))],
+                ['Datapoints', $p.*.($e(num_datapoints))],
+                ['Nulls', $p.*.($e(num_nulls))],
+                $p.*.data.($fn($)) ~> $reduce(function($a, $b) {
+                    $map($ks, function($k) {(
+                        {
+                            $k : [$e($lookup($a,$k), "No data"), $e($lookup($b,$k), "No data")]
+                        }
+                    )}) ~> $merge()
+                }) ~> $each(function($v, $k) {$append($k,$v)})
+            ]
+        })
+    ]
+)
+`);
diff --git a/api/src/engine/engine.controller.ts b/api/src/engine/engine.controller.ts
index a495a2c317efa7911dc3f2e43915c88f9fb13830..b3e12d13ff2b2004e576f05b4358991f27eabd08 100644
--- a/api/src/engine/engine.controller.ts
+++ b/api/src/engine/engine.controller.ts
@@ -19,11 +19,6 @@ export class EngineController {
     @Inject(ENGINE_SERVICE) private readonly engineService: IEngineService,
   ) {}
 
-  @Get('/test')
-  getTest(): string {
-    return this.engineService.demo();
-  }
-
   @Get('/algorithms')
   getAlgorithms(@Req() request: Request): Observable<string> {
     return this.engineService.getAlgorithms(request);
@@ -36,7 +31,7 @@ export class EngineController {
 
   @Get('/experiments/:uuid')
   getExperiment(@Param('uuid') uuid: string): Observable<string> {
-    return this.engineService.getExperiment(uuid);
+    return this.engineService.getExperimentAPI(uuid);
   }
 
   @Delete('/experiments/:uuid')
@@ -52,7 +47,7 @@ export class EngineController {
     @Param('uuid') uuid: string,
     @Req() request: Request,
   ): Observable<string> {
-    return this.engineService.editExperiment(uuid, request);
+    return this.engineService.editExperimentAPI(uuid, request);
   }
 
   @Post('experiments/transient')
diff --git a/api/src/engine/engine.interfaces.ts b/api/src/engine/engine.interfaces.ts
index 09b86b731d670a83b598936d834b8993f4a8b27f..e754a1fd068a47d1f235fb4ca54a692fd4470342 100644
--- a/api/src/engine/engine.interfaces.ts
+++ b/api/src/engine/engine.interfaces.ts
@@ -1,6 +1,13 @@
 import { Request } from 'express';
 import { Observable } from 'rxjs';
 import { Domain } from './models/domain.model';
+import {
+  Experiment,
+  PartialExperiment,
+} from './models/experiment/experiment.model';
+import { ExperimentCreateInput } from './models/experiment/input/experiment-create.input';
+import { ExperimentEditInput } from './models/experiment/input/experiment-edit.input';
+import { ListExperiments } from './models/experiment/list-experiments.model';
 
 export interface IEngineOptions {
   type: string;
@@ -8,19 +15,40 @@ export interface IEngineOptions {
 }
 
 export interface IEngineService {
-  demo(): string;
-
+  //GraphQL
   getDomains(ids: string[]): Domain[] | Promise<Domain[]>;
 
+  createExperiment(
+    data: ExperimentCreateInput,
+    isTransient: boolean,
+  ): Promise<Experiment> | Experiment;
+
+  listExperiments(
+    page: number,
+    name: string,
+  ): Promise<ListExperiments> | ListExperiments;
+
+  getExperiment(uuid: string): Promise<Experiment> | Experiment;
+
+  removeExperiment(
+    uuid: string,
+  ): Promise<PartialExperiment> | PartialExperiment;
+
+  editExperient(
+    uuid: string,
+    expriment: ExperimentEditInput,
+  ): Promise<Experiment> | Experiment;
+
+  // Standard REST API call
   getAlgorithms(request: Request): Observable<string>;
 
   getExperiments(request: Request): Observable<string>;
 
-  getExperiment(uuid: string): Observable<string>;
+  getExperimentAPI(uuid: string): Observable<string>;
 
   deleteExperiment(uuid: string, request: Request): Observable<string>;
 
-  editExperiment(uuid: string, request: Request): Observable<string>;
+  editExperimentAPI(uuid: string, request: Request): Observable<string>;
 
   startExperimentTransient(request: Request): Observable<string>;
 
diff --git a/api/src/engine/engine.resolver.ts b/api/src/engine/engine.resolver.ts
index beeb589fc6de4f3294efffea16e4b55c1ac96f61..dfd7dc73ca78f22ce7378ef82895bb99db54f42b 100644
--- a/api/src/engine/engine.resolver.ts
+++ b/api/src/engine/engine.resolver.ts
@@ -1,8 +1,15 @@
 import { Inject } from '@nestjs/common';
-import { Args, Query, Resolver } from '@nestjs/graphql';
+import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
 import { ENGINE_SERVICE } from './engine.constants';
 import { IEngineService } from './engine.interfaces';
 import { Domain } from './models/domain.model';
+import {
+  Experiment,
+  PartialExperiment,
+} from './models/experiment/experiment.model';
+import { ExperimentCreateInput } from './models/experiment/input/experiment-create.input';
+import { ExperimentEditInput } from './models/experiment/input/experiment-edit.input';
+import { ListExperiments } from './models/experiment/list-experiments.model';
 
 @Resolver()
 export class EngineResolver {
@@ -17,4 +24,44 @@ export class EngineResolver {
   ) {
     return this.engineService.getDomains(ids);
   }
+
+  @Query(() => ListExperiments)
+  async experiments(
+    @Args('page', { nullable: true, defaultValue: 0 }) page: number,
+    @Args('name', { nullable: true, defaultValue: '' }) name: string,
+  ) {
+    return this.engineService.listExperiments(page, name);
+  }
+
+  @Query(() => Experiment)
+  async expriment(@Args('uuid') uuid: string) {
+    return this.engineService.getExperiment(uuid);
+  }
+
+  @Mutation(() => Experiment)
+  async createExperiment(
+    @Args('data') experimentCreateInput: ExperimentCreateInput,
+    @Args('transient', { nullable: true, defaultValue: false })
+    isTransient: boolean,
+  ) {
+    return this.engineService.createExperiment(
+      experimentCreateInput,
+      isTransient,
+    );
+  }
+
+  @Mutation(() => Experiment)
+  async editExperiment(
+    @Args('uuid') uuid: string,
+    @Args('data') experiment: ExperimentEditInput,
+  ) {
+    return this.engineService.editExperient(uuid, experiment);
+  }
+
+  @Mutation(() => PartialExperiment)
+  async removeExperiment(
+    @Args('uuid') uuid: string,
+  ): Promise<PartialExperiment> {
+    return this.engineService.removeExperiment(uuid);
+  }
 }
diff --git a/api/src/engine/models/category.model.ts b/api/src/engine/models/category.model.ts
index 877acc5c3c4f5cb3eaf19b05f71879950b69dd76..921ebfce8d518a66a484bf44d04cf330b8091915 100644
--- a/api/src/engine/models/category.model.ts
+++ b/api/src/engine/models/category.model.ts
@@ -1,10 +1,5 @@
-import { Field, ObjectType } from '@nestjs/graphql';
+import { ObjectType } from '@nestjs/graphql';
+import { Entity } from './entity.model';
 
 @ObjectType()
-export class Category {
-  @Field()
-  id: string;
-
-  @Field()
-  label: string;
-}
+export class Category extends Entity {}
diff --git a/api/src/engine/models/entity.model.ts b/api/src/engine/models/entity.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..32183fd7e970410a1ee3f479cef4d691d56fb7a7
--- /dev/null
+++ b/api/src/engine/models/entity.model.ts
@@ -0,0 +1,11 @@
+import { Field, InputType, ObjectType } from '@nestjs/graphql';
+
+@InputType()
+@ObjectType()
+export class Entity {
+  @Field()
+  id: string;
+
+  @Field({ nullable: true })
+  label?: string;
+}
diff --git a/api/src/engine/models/experiment/algorithm-parameter.model.ts b/api/src/engine/models/experiment/algorithm-parameter.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..79666de79a81e2a7d3c2e2c0756404a995479735
--- /dev/null
+++ b/api/src/engine/models/experiment/algorithm-parameter.model.ts
@@ -0,0 +1,10 @@
+import { Field, ObjectType } from '@nestjs/graphql';
+
+@ObjectType()
+export class AlgorithmParameter {
+  @Field()
+  name: string;
+
+  @Field(() => [String])
+  value: string[];
+}
diff --git a/api/src/engine/models/experiment/algorithm.model.ts b/api/src/engine/models/experiment/algorithm.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..30087c5b55d07d213508d125ba9eb491920073c2
--- /dev/null
+++ b/api/src/engine/models/experiment/algorithm.model.ts
@@ -0,0 +1,14 @@
+import { Field, ObjectType } from '@nestjs/graphql';
+import { AlgorithmParameter } from './algorithm-parameter.model';
+
+@ObjectType()
+export class Algorithm {
+  @Field()
+  name: string;
+
+  @Field(() => [AlgorithmParameter], { nullable: true, defaultValue: [] })
+  parameters: AlgorithmParameter[];
+
+  @Field()
+  type: string;
+}
diff --git a/api/src/engine/models/experiment/experiment.model.ts b/api/src/engine/models/experiment/experiment.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2ac6ec204f2f1021f8f5963771b37362cbce7b18
--- /dev/null
+++ b/api/src/engine/models/experiment/experiment.model.ts
@@ -0,0 +1,75 @@
+import {
+  createUnionType,
+  Field,
+  ObjectType,
+  PartialType,
+} from '@nestjs/graphql';
+import { RawResult } from '../result/raw-result.model';
+import { TableResult } from '../result/table-result.model';
+import { Algorithm } from './algorithm.model';
+
+export const ResultUnion = createUnionType({
+  name: 'ResultUnion',
+  types: () => [TableResult, RawResult],
+  resolveType(value) {
+    if (value.headers) {
+      return TableResult;
+    }
+    if (value.listMax) {
+      return RawResult;
+    }
+
+    return null;
+  },
+});
+
+@ObjectType()
+export class Experiment {
+  @Field({ nullable: true })
+  uuid?: string;
+
+  @Field({ nullable: true, defaultValue: '' })
+  author?: string;
+
+  @Field({ nullable: true })
+  createdAt?: number;
+
+  @Field({ nullable: true })
+  updateAt?: number;
+
+  @Field({ nullable: true })
+  finishedAt?: number;
+
+  @Field({ nullable: true, defaultValue: false })
+  viewed?: boolean;
+
+  @Field({ nullable: true })
+  status?: string;
+
+  @Field({ defaultValue: false })
+  shared?: boolean;
+
+  @Field(() => [ResultUnion], { nullable: true, defaultValue: [] })
+  results?: Array<typeof ResultUnion>;
+
+  @Field(() => [String])
+  datasets: string[];
+
+  @Field(() => String, { nullable: true })
+  filter?: string;
+
+  @Field()
+  domain: string;
+
+  @Field(() => [String])
+  variables: string[];
+
+  @Field()
+  algorithm: Algorithm;
+
+  @Field()
+  name: string;
+}
+
+@ObjectType()
+export class PartialExperiment extends PartialType(Experiment) {}
diff --git a/api/src/engine/models/experiment/input/algorithm-parameter.input.ts b/api/src/engine/models/experiment/input/algorithm-parameter.input.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8eb4cb26b5dade932440b6fef169275988d33b03
--- /dev/null
+++ b/api/src/engine/models/experiment/input/algorithm-parameter.input.ts
@@ -0,0 +1,10 @@
+import { Field, InputType } from '@nestjs/graphql';
+
+@InputType()
+export class AlgorithmParamInput {
+  @Field()
+  name: string;
+
+  @Field(() => [String])
+  value: string[];
+}
diff --git a/api/src/engine/models/experiment/input/algorithm.input.ts b/api/src/engine/models/experiment/input/algorithm.input.ts
new file mode 100644
index 0000000000000000000000000000000000000000..54d26b7686559c39b311cee5e5496bce530b0cf5
--- /dev/null
+++ b/api/src/engine/models/experiment/input/algorithm.input.ts
@@ -0,0 +1,14 @@
+import { Field, InputType } from '@nestjs/graphql';
+import { AlgorithmParamInput } from './algorithm-parameter.input';
+
+@InputType()
+export class AlgorithmInput {
+  @Field()
+  name: string;
+
+  @Field(() => [AlgorithmParamInput], { nullable: true, defaultValue: [] })
+  parameters: AlgorithmParamInput[];
+
+  @Field()
+  type: string;
+}
diff --git a/api/src/engine/models/experiment/input/experiment-create.input.ts b/api/src/engine/models/experiment/input/experiment-create.input.ts
new file mode 100644
index 0000000000000000000000000000000000000000..85a54049cffde188cd770237ba53ef1ccf847027
--- /dev/null
+++ b/api/src/engine/models/experiment/input/experiment-create.input.ts
@@ -0,0 +1,23 @@
+import { Field, InputType } from '@nestjs/graphql';
+import { AlgorithmInput } from './algorithm.input';
+
+@InputType()
+export class ExperimentCreateInput {
+  @Field(() => [String])
+  datasets: string[];
+
+  @Field(() => String, { nullable: true })
+  filter: string;
+
+  @Field()
+  domain: string;
+
+  @Field(() => [String])
+  variables: string[];
+
+  @Field()
+  algorithm: AlgorithmInput;
+
+  @Field()
+  name: string;
+}
diff --git a/api/src/engine/models/experiment/input/experiment-edit.input.ts b/api/src/engine/models/experiment/input/experiment-edit.input.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d37deb1e8d008d746fda7214bb6890142b74a12a
--- /dev/null
+++ b/api/src/engine/models/experiment/input/experiment-edit.input.ts
@@ -0,0 +1,10 @@
+import { Field, InputType } from '@nestjs/graphql';
+
+@InputType()
+export class ExperimentEditInput {
+  @Field({ nullable: true })
+  name?: string;
+
+  @Field({ nullable: true })
+  viewed?: boolean;
+}
diff --git a/api/src/engine/models/experiment/list-experiments.model.ts b/api/src/engine/models/experiment/list-experiments.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8f8592e52f1e3d85946d373a73b4edd00ac318f5
--- /dev/null
+++ b/api/src/engine/models/experiment/list-experiments.model.ts
@@ -0,0 +1,17 @@
+import { Field, ObjectType } from '@nestjs/graphql';
+import { Experiment } from './experiment.model';
+
+@ObjectType()
+export class ListExperiments {
+  @Field({ nullable: true, defaultValue: 0 })
+  currentPage?: number;
+
+  @Field({ nullable: true })
+  totalPages?: number;
+
+  @Field({ nullable: true })
+  totalExperiments?: number;
+
+  @Field(() => [Experiment])
+  experiments: Experiment[];
+}
diff --git a/api/src/engine/models/group.model.ts b/api/src/engine/models/group.model.ts
index d4b45f741c1a9b4b089e8187a136154bd3b695d7..c2087ba2c6023a4a3d7f17110e3e739709d08a90 100644
--- a/api/src/engine/models/group.model.ts
+++ b/api/src/engine/models/group.model.ts
@@ -1,14 +1,9 @@
 import { Field, ObjectType } from '@nestjs/graphql';
+import { Entity } from './entity.model';
 import { Variable } from './variable.model';
 
 @ObjectType()
-export class Group {
-  @Field()
-  id: string;
-
-  @Field()
-  label: string;
-
+export class Group extends Entity {
   @Field({ nullable: true })
   description?: string;
 
diff --git a/api/src/engine/models/result/common/header.model.ts b/api/src/engine/models/result/common/header.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..27844983c4724df06cd8d8d79caf83ae4e00a6de
--- /dev/null
+++ b/api/src/engine/models/result/common/header.model.ts
@@ -0,0 +1,10 @@
+import { Field, ObjectType } from '@nestjs/graphql';
+
+@ObjectType()
+export class Header {
+  @Field()
+  name: string;
+
+  @Field()
+  type: string;
+}
diff --git a/api/src/engine/models/result/common/result.model.ts b/api/src/engine/models/result/common/result.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ca86bfb4e109c44d0d4c06ea0e70ac05e3bf656a
--- /dev/null
+++ b/api/src/engine/models/result/common/result.model.ts
@@ -0,0 +1,7 @@
+import { Field, ObjectType } from '@nestjs/graphql';
+
+@ObjectType()
+export abstract class Result {
+  @Field({ nullable: true })
+  groupBy?: string;
+}
diff --git a/api/src/engine/models/result/raw-result.model.ts b/api/src/engine/models/result/raw-result.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5074e015cc483a3b4fe899f9608d8ddba76f0bfa
--- /dev/null
+++ b/api/src/engine/models/result/raw-result.model.ts
@@ -0,0 +1,12 @@
+import { Field, ObjectType } from '@nestjs/graphql';
+import { GraphQLJSONObject } from 'graphql-type-json';
+import { Result } from './common/result.model';
+
+@ObjectType()
+export class RawResult extends Result {
+  @Field(() => GraphQLJSONObject)
+  data: unknown;
+
+  @Field(() => [String], { defaultValue: [] })
+  listMax?: string[];
+}
diff --git a/api/src/engine/models/result/table-result.model.ts b/api/src/engine/models/result/table-result.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..002d59c5b15ce974e56bc9a9b0d9272212961c31
--- /dev/null
+++ b/api/src/engine/models/result/table-result.model.ts
@@ -0,0 +1,15 @@
+import { Field, ObjectType } from '@nestjs/graphql';
+import { Header } from './common/header.model';
+import { Result } from './common/result.model';
+
+@ObjectType()
+export class TableResult extends Result {
+  @Field()
+  name: string;
+
+  @Field(() => [[String]])
+  data: string[][];
+
+  @Field(() => [Header])
+  headers: Header[];
+}
diff --git a/api/src/engine/models/variable.model.ts b/api/src/engine/models/variable.model.ts
index 058feaf0be1e6a94b35c9f9d4ea98ac529ab0e83..e3c4098e31fccbcc4bd223c82ea55225559edaaf 100644
--- a/api/src/engine/models/variable.model.ts
+++ b/api/src/engine/models/variable.model.ts
@@ -1,15 +1,10 @@
 import { Field, ObjectType } from '@nestjs/graphql';
 import { Category } from './category.model';
+import { Entity } from './entity.model';
 import { Group } from './group.model';
 
 @ObjectType()
-export class Variable {
-  @Field()
-  id: string;
-
-  @Field({ nullable: true })
-  label?: string;
-
+export class Variable extends Entity {
   @Field()
   type: string;
 
diff --git a/api/src/schema.gql b/api/src/schema.gql
index 023cdbeda9b5556163b2cd09140be601bd7cbc9c..7f7184b1a4848433930c010edd5aa3090207fd79 100644
--- a/api/src/schema.gql
+++ b/api/src/schema.gql
@@ -4,7 +4,7 @@
 
 type Category {
   id: String!
-  label: String!
+  label: String
 }
 
 type Variable {
@@ -18,7 +18,7 @@ type Variable {
 
 type Group {
   id: String!
-  label: String!
+  label: String
   description: String
   groups: [Group!]!
   variables: [Variable!]!
@@ -26,7 +26,7 @@ type Group {
 
 type Domain {
   id: String!
-  label: String!
+  label: String
   description: String
   groups: [Group!]!
   variables: [Variable!]!
@@ -34,6 +34,118 @@ type Domain {
   rootGroup: Group!
 }
 
+type Header {
+  name: String!
+  type: String!
+}
+
+type AlgorithmParameter {
+  name: String!
+  value: [String!]!
+}
+
+type Algorithm {
+  name: String!
+  parameters: [AlgorithmParameter!]
+  type: String!
+}
+
+type Experiment {
+  uuid: String
+  author: String
+  createdAt: Float
+  updateAt: Float
+  finishedAt: Float
+  viewed: Boolean
+  status: String
+  shared: Boolean!
+  results: [ResultUnion!]
+  datasets: [String!]!
+  filter: String
+  domain: String!
+  variables: [String!]!
+  algorithm: Algorithm!
+  name: String!
+}
+
+union ResultUnion = TableResult | RawResult
+
+type TableResult {
+  groupBy: String
+  name: String!
+  data: [[String!]!]!
+  headers: [Header!]!
+}
+
+type RawResult {
+  groupBy: String
+  data: JSONObject!
+  listMax: [String!]!
+}
+
+"""
+The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).
+"""
+scalar JSONObject @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf")
+
+type PartialExperiment {
+  uuid: String
+  author: String
+  createdAt: Float
+  updateAt: Float
+  finishedAt: Float
+  viewed: Boolean
+  status: String
+  shared: Boolean
+  results: [ResultUnion!]
+  datasets: [String!]
+  filter: String
+  domain: String
+  variables: [String!]
+  algorithm: Algorithm
+  name: String
+}
+
+type ListExperiments {
+  currentPage: Float
+  totalPages: Float
+  totalExperiments: Float
+  experiments: [Experiment!]!
+}
+
 type Query {
   domains(ids: [String!] = []): [Domain!]!
+  experiments(name: String = "", page: Float = 0): ListExperiments!
+  expriment(uuid: String!): Experiment!
+}
+
+type Mutation {
+  createExperiment(transient: Boolean = false, data: ExperimentCreateInput!): Experiment!
+  editExperiment(data: ExperimentEditInput!, uuid: String!): Experiment!
+  removeExperiment(uuid: String!): PartialExperiment!
+}
+
+input ExperimentCreateInput {
+  datasets: [String!]!
+  filter: String
+  domain: String!
+  variables: [String!]!
+  algorithm: AlgorithmInput!
+  name: String!
+}
+
+input AlgorithmInput {
+  name: String!
+  parameters: [AlgorithmParamInput!] = []
+  type: String!
+}
+
+input AlgorithmParamInput {
+  name: String!
+  value: [String!]!
+}
+
+input ExperimentEditInput {
+  name: String
+  viewed: Boolean
 }