diff --git a/src/components/SPA/MinervaSPA.component.tsx b/src/components/SPA/MinervaSPA.component.tsx
index c4b61c47c268f3421b3e2fa908b7853e2b6ff8e6..c9b5381584b0a04df6a647779e15e82e4bff4962 100644
--- a/src/components/SPA/MinervaSPA.component.tsx
+++ b/src/components/SPA/MinervaSPA.component.tsx
@@ -2,6 +2,9 @@ import { Manrope } from '@next/font/google';
 import { twMerge } from 'tailwind-merge';
 import { Map } from '@/components/Map';
 import { FunctionalArea } from '@/components/FunctionalArea';
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import { useEffect } from 'react';
+import { getModels } from '@/redux/models/models.thunks';
 
 const manrope = Manrope({
   variable: '--font-manrope',
@@ -10,9 +13,17 @@ const manrope = Manrope({
   subsets: ['latin'],
 });
 
-export const MinervaSPA = (): JSX.Element => (
-  <div className={twMerge('relative', manrope.variable)}>
-    <FunctionalArea />
-    <Map />
-  </div>
-);
+export const MinervaSPA = (): JSX.Element => {
+  const dispatch = useAppDispatch();
+
+  useEffect(() => {
+    dispatch(getModels());
+  }, [dispatch]);
+
+  return (
+    <div className={twMerge('relative', manrope.variable)}>
+      <FunctionalArea />
+      <Map />
+    </div>
+  );
+};
diff --git a/src/models/authorSchema.ts b/src/models/authorSchema.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2dfa82ec918b797f2a3b1cd8816e197274cd2f1c
--- /dev/null
+++ b/src/models/authorSchema.ts
@@ -0,0 +1,3 @@
+import { z } from 'zod';
+
+export const authorSchema = z.string();
diff --git a/src/models/fixtures/modelsFixture.ts b/src/models/fixtures/modelsFixture.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3d4e39e35e9ec6500ecf7759da7c3fa028f54c09
--- /dev/null
+++ b/src/models/fixtures/modelsFixture.ts
@@ -0,0 +1,10 @@
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { createFixture } from 'zod-fixture';
+import { z } from 'zod';
+import { ZOD_SEED } from '@/constants';
+import { modelSchema } from '@/models/modelSchema';
+
+export const modelsFixture = createFixture(z.array(modelSchema), {
+  seed: ZOD_SEED,
+  array: { min: 2, max: 2 },
+});
diff --git a/src/models/modelSchema.ts b/src/models/modelSchema.ts
new file mode 100644
index 0000000000000000000000000000000000000000..64752c8c1bd4043d1ff24cc0de26022f5f22daa2
--- /dev/null
+++ b/src/models/modelSchema.ts
@@ -0,0 +1,31 @@
+import { z } from 'zod';
+import { referenceSchema } from './referenceSchema';
+import { authorSchema } from './authorSchema';
+
+export const modelSchema = z.object({
+  /** name of the map */
+  name: z.string(),
+  description: z.string(),
+  /** map id */
+  idObject: z.number(),
+  /** map width */
+  width: z.number(),
+  /** map height */
+  height: z.number(),
+  /** size of the png tile used to visualize in frontend */
+  tileSize: z.number(),
+  /** default x center used in frontend visualization */
+  defaultCenterX: z.union([z.number(), z.null()]),
+  /** default y center used in frontend visualization */
+  defaultCenterY: z.union([z.number(), z.null()]),
+  /** default zoom level used in frontend visualization */
+  defaultZoomLevel: z.union([z.number(), z.null()]),
+  /** minimum zoom level availbale for the map */
+  minZoom: z.number(),
+  /** maximum zoom level available for the map */
+  maxZoom: z.number(),
+  authors: z.array(authorSchema),
+  references: z.array(referenceSchema),
+  creationDate: z.union([z.string(), z.null()]),
+  modificationDates: z.array(z.string()),
+});
diff --git a/src/redux/apiPath.ts b/src/redux/apiPath.ts
index 8469a3d16b0f7eb0e9144339ff69da900564e86c..11ce6f11c1e59f6e8f6a4bf38037ac62e2e501a2 100644
--- a/src/redux/apiPath.ts
+++ b/src/redux/apiPath.ts
@@ -7,6 +7,7 @@ export const apiPath = {
     `projects/${PROJECT_ID}/drugs:search?query=${searchQuery}`,
   getMirnasStringWithQuery: (searchQuery: string): string =>
     `projects/${PROJECT_ID}/miRnas:search?query=${searchQuery}`,
+  getModelsString: (): string => `projects/${PROJECT_ID}/models/`,
   getChemicalsStringWithQuery: (searchQuery: string): string =>
     `projects/${PROJECT_ID}/chemicals:search?query=${searchQuery}`,
 };
diff --git a/src/redux/models/models.reducers.test.ts b/src/redux/models/models.reducers.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c130ae0ee5a782380554a87b39e9a77f31ec3864
--- /dev/null
+++ b/src/redux/models/models.reducers.test.ts
@@ -0,0 +1,72 @@
+import { HttpStatusCode } from 'axios';
+import { modelsFixture } from '@/models/fixtures/modelsFixture';
+import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import {
+  ToolkitStoreWithSingleSlice,
+  createStoreInstanceUsingSliceReducer,
+} from '@/utils/createStoreInstanceUsingSliceReducer';
+import { apiPath } from '@/redux/apiPath';
+import { getModels } from './models.thunks';
+import modelsReducer from './models.slice';
+import { ModelsState } from './models.types';
+
+const mockedAxiosClient = mockNetworkResponse();
+
+const INITIAL_STATE: ModelsState = {
+  data: [],
+  loading: 'idle',
+  error: { name: '', message: '' },
+};
+
+describe('models reducer', () => {
+  let store = {} as ToolkitStoreWithSingleSlice<ModelsState>;
+  beforeEach(() => {
+    store = createStoreInstanceUsingSliceReducer('models', modelsReducer);
+  });
+
+  it('should match initial state', () => {
+    const action = { type: 'unknown' };
+
+    expect(modelsReducer(undefined, action)).toEqual(INITIAL_STATE);
+  });
+  it('should update store after succesfull getModels query', async () => {
+    mockedAxiosClient.onGet(apiPath.getModelsString()).reply(HttpStatusCode.Ok, modelsFixture);
+
+    const { type } = await store.dispatch(getModels());
+    const { data, loading, error } = store.getState().models;
+
+    expect(type).toBe('project/getModels/fulfilled');
+    expect(loading).toEqual('succeeded');
+    expect(error).toEqual({ message: '', name: '' });
+    expect(data).toEqual(modelsFixture);
+  });
+
+  it('should update store after failed getModels query', async () => {
+    mockedAxiosClient.onGet(apiPath.getModelsString()).reply(HttpStatusCode.NotFound, []);
+
+    const { type } = await store.dispatch(getModels());
+    const { data, loading, error } = store.getState().models;
+
+    expect(type).toBe('project/getModels/rejected');
+    expect(loading).toEqual('failed');
+    expect(error).toEqual({ message: '', name: '' });
+    expect(data).toEqual([]);
+  });
+
+  it('should update store on loading getModels query', async () => {
+    mockedAxiosClient.onGet(apiPath.getModelsString()).reply(HttpStatusCode.Ok, modelsFixture);
+
+    const modelsPromise = store.dispatch(getModels());
+
+    const { data, loading } = store.getState().models;
+    expect(data).toEqual([]);
+    expect(loading).toEqual('pending');
+
+    modelsPromise.then(() => {
+      const { data: dataPromiseFulfilled, loading: promiseFulfilled } = store.getState().models;
+
+      expect(dataPromiseFulfilled).toEqual(modelsFixture);
+      expect(promiseFulfilled).toEqual('succeeded');
+    });
+  });
+});
diff --git a/src/redux/models/models.reducers.ts b/src/redux/models/models.reducers.ts
new file mode 100644
index 0000000000000000000000000000000000000000..28f71efbe06a26fde0b4f5cdb8b11599965f5713
--- /dev/null
+++ b/src/redux/models/models.reducers.ts
@@ -0,0 +1,17 @@
+import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
+import { ModelsState } from './models.types';
+import { getModels } from './models.thunks';
+
+export const getModelsReducer = (builder: ActionReducerMapBuilder<ModelsState>): void => {
+  builder.addCase(getModels.pending, state => {
+    state.loading = 'pending';
+  });
+  builder.addCase(getModels.fulfilled, (state, action) => {
+    state.data = action.payload;
+    state.loading = 'succeeded';
+  });
+  builder.addCase(getModels.rejected, state => {
+    state.loading = 'failed';
+    // TODO to discuss manage state of failure
+  });
+};
diff --git a/src/redux/models/models.slice.ts b/src/redux/models/models.slice.ts
new file mode 100644
index 0000000000000000000000000000000000000000..61c765b6b8668424f2b518eb50f463c8629d769f
--- /dev/null
+++ b/src/redux/models/models.slice.ts
@@ -0,0 +1,20 @@
+import { createSlice } from '@reduxjs/toolkit';
+import { ModelsState } from '@/redux/models/models.types';
+import { getModelsReducer } from './models.reducers';
+
+const initialState: ModelsState = {
+  data: [],
+  loading: 'idle',
+  error: { name: '', message: '' },
+};
+
+export const modelsSlice = createSlice({
+  name: 'models',
+  initialState,
+  reducers: {},
+  extraReducers: builder => {
+    getModelsReducer(builder);
+  },
+});
+
+export default modelsSlice.reducer;
diff --git a/src/redux/models/models.thunks.test.ts b/src/redux/models/models.thunks.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3d85a15e274e0d0ee6352353d25e504de8097259
--- /dev/null
+++ b/src/redux/models/models.thunks.test.ts
@@ -0,0 +1,36 @@
+import { HttpStatusCode } from 'axios';
+import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import {
+  ToolkitStoreWithSingleSlice,
+  createStoreInstanceUsingSliceReducer,
+} from '@/utils/createStoreInstanceUsingSliceReducer';
+import { ModelsState } from '@/redux/models/models.types';
+import { apiPath } from '@/redux/apiPath';
+import { modelsFixture } from '@/models/fixtures/modelsFixture';
+import modelsReducer from './models.slice';
+import { getModels } from './models.thunks';
+
+const mockedAxiosClient = mockNetworkResponse();
+
+describe('models thunks', () => {
+  let store = {} as ToolkitStoreWithSingleSlice<ModelsState>;
+  beforeEach(() => {
+    store = createStoreInstanceUsingSliceReducer('models', modelsReducer);
+  });
+  describe('getModels', () => {
+    it('should return data when data response from API is valid', async () => {
+      mockedAxiosClient.onGet(apiPath.getModelsString()).reply(HttpStatusCode.Ok, modelsFixture);
+
+      const { payload } = await store.dispatch(getModels());
+      expect(payload).toEqual(modelsFixture);
+    });
+    it('should return undefined when data response from API is not valid ', async () => {
+      mockedAxiosClient
+        .onGet(apiPath.getModelsString())
+        .reply(HttpStatusCode.Ok, { randomProperty: 'randomValue' });
+
+      const { payload } = await store.dispatch(getModels());
+      expect(payload).toEqual(undefined);
+    });
+  });
+});
diff --git a/src/redux/models/models.thunks.ts b/src/redux/models/models.thunks.ts
new file mode 100644
index 0000000000000000000000000000000000000000..430bafb0e14acf41302102c42eddcc54fe5ca72c
--- /dev/null
+++ b/src/redux/models/models.thunks.ts
@@ -0,0 +1,18 @@
+import { z } from 'zod';
+import { createAsyncThunk } from '@reduxjs/toolkit';
+import { axiosInstance } from '@/services/api/utils/axiosInstance';
+import { Model } from '@/types/models';
+import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
+import { apiPath } from '@/redux/apiPath';
+import { modelSchema } from '@/models/modelSchema';
+
+export const getModels = createAsyncThunk(
+  'project/getModels',
+  async (): Promise<Model[] | undefined> => {
+    const response = await axiosInstance.get<Model[]>(apiPath.getModelsString());
+
+    const isDataValid = validateDataUsingZodSchema(response.data, z.array(modelSchema));
+
+    return isDataValid ? response.data : undefined;
+  },
+);
diff --git a/src/redux/models/models.types.ts b/src/redux/models/models.types.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c3a6b9824eb8abc7a30d10137a1ae0f87ce4f5e7
--- /dev/null
+++ b/src/redux/models/models.types.ts
@@ -0,0 +1,4 @@
+import { FetchDataState } from '@/types/fetchDataState';
+import { Model } from '@/types/models';
+
+export type ModelsState = FetchDataState<Model[]>;
diff --git a/src/redux/store.ts b/src/redux/store.ts
index a095912bdda990fb9677b2b8814e0cd848014d6a..1999d33f1373323b288bed176473fca135a77067 100644
--- a/src/redux/store.ts
+++ b/src/redux/store.ts
@@ -1,6 +1,7 @@
 import bioEntityContentsReducer from '@/redux/bioEntityContents/bioEntityContents.slice';
 import chemicalsReducer from '@/redux/chemicals/chemicals.slice';
 import drawerReducer from '@/redux/drawer/drawer.slice';
+import modelsReducer from '@/redux/models/models.slice';
 import drugsReducer from '@/redux/drugs/drugs.slice';
 import mirnasReducer from '@/redux/mirnas/mirnas.slice';
 import projectSlice from '@/redux/project/project.slice';
@@ -16,6 +17,7 @@ export const store = configureStore({
     chemicals: chemicalsReducer,
     bioEntityContents: bioEntityContentsReducer,
     drawer: drawerReducer,
+    models: modelsReducer,
   },
   devTools: true,
 });
diff --git a/src/types/models.ts b/src/types/models.ts
index abadf02ac342719044fbc94260c65ed3704d8b71..8902849349a999a58661d14d73d5734574f96130 100644
--- a/src/types/models.ts
+++ b/src/types/models.ts
@@ -6,6 +6,7 @@ import { mirnaSchema } from '@/models/mirnaSchema';
 import { organism } from '@/models/organism';
 import { projectSchema } from '@/models/project';
 import { z } from 'zod';
+import { modelSchema } from '@/models/modelSchema';
 
 export type Project = z.infer<typeof projectSchema>;
 export type Organism = z.infer<typeof organism>;
@@ -13,4 +14,5 @@ export type Disease = z.infer<typeof disease>;
 export type Drug = z.infer<typeof drugSchema>;
 export type Mirna = z.infer<typeof mirnaSchema>;
 export type BioEntityContent = z.infer<typeof bioEntityContentSchema>;
+export type Model = z.infer<typeof modelSchema>;
 export type Chemical = z.infer<typeof chemicalSchema>;