diff --git a/backend/app/app/api/endpoints/keggs.py b/backend/app/app/api/endpoints/keggs.py
new file mode 100644
index 0000000000000000000000000000000000000000..eceda53cf75cad826c103e3bed266b0ea91e6bd7
--- /dev/null
+++ b/backend/app/app/api/endpoints/keggs.py
@@ -0,0 +1,61 @@
+from typing import List
+
+from fastapi import Depends, APIRouter, HTTPException
+from sqlalchemy.exc import NoResultFound, IntegrityError
+from sqlmodel import Session
+
+from app.db import get_session
+from app.core.schemas.entities.kegg import KeggRead, KeggUpdate, KeggCreate
+from app.core.use_cases.crud.kegg import CrudKeggUseCase
+
+
+router = APIRouter()
+
+
+@router.get("/", response_model=List[KeggRead])
+async def get_keggs(session: Session = Depends(get_session)):
+    use_case = CrudKeggUseCase()
+    keggs = use_case.get_all(session=session)
+    return keggs
+
+
+@router.get("/{kegg_id}", response_model=KeggRead)
+async def get_kegg(kegg_id: str, session: Session = Depends(get_session)):
+    use_case = CrudKeggUseCase()
+    try:
+        kegg = use_case.get_kegg(kegg_id, session=session)
+    except NoResultFound:
+        raise HTTPException(status_code=404, detail=f"Kegg [{kegg_id}] not found.")
+    return kegg
+
+
+@router.post("/", response_model=KeggRead)
+async def create_kegg(kegg: KeggCreate, session: Session = Depends(get_session)):
+    use_case = CrudKeggUseCase()
+    try:
+        kegg = use_case.create_kegg(kegg, session=session)
+    except IntegrityError:
+        raise HTTPException(
+            status_code=403, detail=f"Kegg [{kegg.name}] already exists."
+        )
+    return kegg
+
+
+@router.put("/", response_model=KeggUpdate)
+async def update_kegg(kegg: KeggCreate, session: Session = Depends(get_session)):
+    use_case = CrudKeggUseCase()
+    try:
+        kegg = use_case.update_kegg(kegg, session=session)
+    except NoResultFound:
+        raise HTTPException(status_code=404, detail=f"Kegg [{kegg.name}] not found.")
+    return kegg
+
+
+@router.delete("/{kegg_id}")
+async def delete_kegg(kegg_id: str, session: Session = Depends(get_session)):
+    use_case = CrudKeggUseCase()
+    try:
+        use_case.delete_kegg(kegg_id, session=session)
+    except NoResultFound:
+        raise HTTPException(status_code=404, detail=f"Kegg [{kegg_id}] not found.")
+    return {"deleted": True}
diff --git a/backend/app/app/api/router.py b/backend/app/app/api/router.py
index 3dfd0e244c3fa849c104c940737d2b013fbaee93..2f7a5a750dd414c10b8687beeec7be58941c165f 100644
--- a/backend/app/app/api/router.py
+++ b/backend/app/app/api/router.py
@@ -1,6 +1,6 @@
 from fastapi import APIRouter
 
-from app.api.endpoints import catalogs, experiments, genes
+from app.api.endpoints import catalogs, experiments, genes, keggs
 
 api_router = APIRouter()
 api_router.include_router(genes.router, prefix="/genes", tags=["Genes"])
@@ -8,3 +8,4 @@ api_router.include_router(catalogs.router, prefix="/catalogs", tags=["Catalogs"]
 api_router.include_router(
     experiments.router, prefix="/experiments", tags=["Experiments"]
 )
+api_router.include_router(keggs.router, prefix="/keggs", tags=["Keggs"])
diff --git a/backend/app/app/core/models/kegg.py b/backend/app/app/core/models/kegg.py
index 12ebe7ec7bcf7d4723ebe4301d8920071a4c82fd..0aa19e08c3a27862afdb47471fe2408964416a65 100644
--- a/backend/app/app/core/models/kegg.py
+++ b/backend/app/app/core/models/kegg.py
@@ -1,11 +1,11 @@
 from typing import List
 
 from slugify import slugify
-from sqlmodel import Field, Relationship, SQLModel
+from sqlmodel import Field, Relationship, SQLModel, VARCHAR, Column
 
 
 class KeggBase(SQLModel):
-    kegg_id: str
+    kegg_id: str = Field(sa_column=Column("kegg_id", VARCHAR, unique=True))
     name: str = Field(index=False)
 
     @property
diff --git a/backend/app/app/core/repositories/kegg.py b/backend/app/app/core/repositories/kegg.py
new file mode 100644
index 0000000000000000000000000000000000000000..c480d167bde4b9682ed37fc6e05fcaae26ceb15e
--- /dev/null
+++ b/backend/app/app/core/repositories/kegg.py
@@ -0,0 +1,64 @@
+import abc
+from typing import List
+
+from sqlmodel import Session, select
+
+from app.core.models.kegg import Kegg
+from app.core.schemas.entities.kegg import KeggCreate, KeggUpdate
+
+
+class KeggsRepo(abc.ABC):
+    @abc.abstractmethod
+    def get(self, kegg_name: str) -> Kegg:
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def get_all(self) -> List[Kegg]:
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def create(self, kegg_input: KeggCreate) -> Kegg:
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def update(self, kegg_input: KeggUpdate) -> Kegg:
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def delete(self, kegg_name: str):
+        raise NotImplementedError
+
+
+class SqlModelKeggsRepo(KeggsRepo):
+    def get(self, kegg_id, session: Session) -> Kegg:
+        """Retrieve one kegg from name."""
+        statement = select(Kegg).where(Kegg.kegg_id == kegg_id)
+        return session.exec(statement).one()
+
+    def get_all(self, session: Session) -> List[Kegg]:
+        """Retrieve all keggs."""
+        keggs = session.exec(select(Kegg)).all()
+        return keggs
+
+    def create(self, kegg_input: KeggCreate, session: Session) -> Kegg:
+        """Create a kegg entry."""
+        kegg = Kegg(kegg_id=kegg_input.kegg_id, name=kegg_input.name)
+        session.add(kegg)
+        session.commit()
+        session.refresh(kegg)
+        return kegg
+
+    def update(self, kegg_input: KeggUpdate, session: Session) -> Kegg:
+        """Update a kegg entry."""
+        kegg = self.get(kegg_input.kegg_id, session)
+        for k, v in kegg_input.dict().items():
+            setattr(kegg, k, v)
+        session.add(kegg)
+        session.commit()
+        session.refresh(kegg)
+        return kegg
+
+    def delete(self, kegg_id: str, session: Session):
+        kegg = self.get(kegg_id, session)
+        session.delete(kegg)
+        session.commit()
diff --git a/backend/app/app/core/schemas/entities/kegg.py b/backend/app/app/core/schemas/entities/kegg.py
index bbd565c98e8ccfdb4bb6b6139b4608b606bbd0e5..953ae670178a607a498b04c940aa52da4ca12e28 100644
--- a/backend/app/app/core/schemas/entities/kegg.py
+++ b/backend/app/app/core/schemas/entities/kegg.py
@@ -7,3 +7,7 @@ class KeggRead(KeggBase):
 
 class KeggCreate(KeggBase):
     pass
+
+
+class KeggUpdate(KeggBase):
+    pass
diff --git a/backend/app/app/core/use_cases/crud/kegg.py b/backend/app/app/core/use_cases/crud/kegg.py
new file mode 100644
index 0000000000000000000000000000000000000000..0fc173f1fdfa636cedd58c436c2b701c73a1e5f1
--- /dev/null
+++ b/backend/app/app/core/use_cases/crud/kegg.py
@@ -0,0 +1,28 @@
+from typing import List
+
+import inject
+
+from app.core.models.kegg import Kegg
+from app.core.schemas.entities.kegg import KeggCreate, KeggUpdate
+from app.core.repositories.kegg import KeggsRepo
+
+
+class CrudKeggUseCase:
+    @inject.autoparams("keggs_repo")
+    def __init__(self, keggs_repo: KeggsRepo):
+        self._keggs_repo = keggs_repo
+
+    def create_kegg(self, kegg_input: KeggCreate, **kwargs) -> Kegg:
+        return self._keggs_repo.create(kegg_input, **kwargs)
+
+    def update_kegg(self, kegg_input: KeggUpdate, **kwargs) -> Kegg:
+        return self._keggs_repo.update(kegg_input, **kwargs)
+
+    def delete_kegg(self, kegg_name: str, **kwargs):
+        return self._keggs_repo.delete(kegg_name, **kwargs)
+
+    def get_kegg(self, kegg_id: str, **kwargs) -> Kegg:
+        return self._keggs_repo.get(kegg_id, **kwargs)
+
+    def get_all(self, **kwargs) -> List[Kegg]:
+        return self._keggs_repo.get_all(**kwargs)
diff --git a/backend/app/app/dependency_injections.py b/backend/app/app/dependency_injections.py
index 2a409860856c2b130c4c9691b42f631d747c15a9..10f4c827a80191219e29a1854c1555741765190f 100644
--- a/backend/app/app/dependency_injections.py
+++ b/backend/app/app/dependency_injections.py
@@ -1,11 +1,17 @@
 import inject
 
 from app.core.repositories.catalog import CatalogsRepo, SqlModelCatalogsRepo
+from app.core.repositories.kegg import KeggsRepo, SqlModelKeggsRepo
 
 
 def di_configuration(binder):
     binder.bind(CatalogsRepo, SqlModelCatalogsRepo())
+    binder.bind(KeggsRepo, SqlModelKeggsRepo())
 
 
 def run_di():
     inject.configure(di_configuration)
+
+
+def clear_di():
+    inject.clear()
diff --git a/backend/app/tests/api/endpoints/base_api_test.py b/backend/app/tests/api/endpoints/base_api_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..322fdd31c6e5cfc1dd8fe98ee55c1da1dd1a7a3c
--- /dev/null
+++ b/backend/app/tests/api/endpoints/base_api_test.py
@@ -0,0 +1,44 @@
+import unittest
+
+from sqlmodel import create_engine, Session, SQLModel
+from sqlmodel.pool import StaticPool
+from fastapi.testclient import TestClient
+
+from app.db import get_session
+from app.dependency_injections import run_di, clear_di
+from app.main import app
+
+
+class BaseApiTests(unittest.TestCase):
+    @classmethod
+    def setUpClass(cls) -> None:
+        # Dependency injections
+        run_di()
+
+        cls.engine = create_engine(
+            "sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool
+        )
+        SQLModel.metadata.create_all(cls.engine)
+        with Session(cls.engine) as session:
+            cls._create_test_db(session)
+
+    @classmethod
+    def _create_test_db(cls, session: Session):
+        pass
+
+    def setUp(self) -> None:
+        self.session = Session(self.engine)
+
+        def get_session_override():
+            return self.session
+
+        app.dependency_overrides[get_session] = get_session_override
+        self.client = TestClient(app)
+
+    def tearDown(self) -> None:
+        app.dependency_overrides.clear()
+        self.session.close()
+
+    @classmethod
+    def tearDownClass(cls) -> None:
+        clear_di()
diff --git a/backend/app/tests/api/endpoints/test_catalogs.py b/backend/app/tests/api/endpoints/test_catalogs.py
index 4bb7f4cf61b37d48114d19f21ef90a64713851b4..98840a5da2162920814e9e52a82d31b9da7f9f1c 100644
--- a/backend/app/tests/api/endpoints/test_catalogs.py
+++ b/backend/app/tests/api/endpoints/test_catalogs.py
@@ -1,14 +1,9 @@
-import unittest
+from sqlmodel import Session, select
 
-from sqlmodel import create_engine, Session, SQLModel, select
-from sqlmodel.pool import StaticPool
-from fastapi.testclient import TestClient
-
-from app.db import get_session
-from app.dependency_injections import run_di
-from app.main import app
 from app.core.models.catalog import Catalog
 
+from .base_api_test import BaseApiTests
+
 
 def create_test_db(session: Session):
     test_catalog = Catalog(name="test-catalog")
@@ -16,31 +11,12 @@ def create_test_db(session: Session):
     session.commit()
 
 
-class TestCatalogs(unittest.TestCase):
+class TestCatalogs(BaseApiTests):
     @classmethod
-    def setUpClass(cls) -> None:
-        # Dependency injections
-        run_di()
-
-        cls.engine = create_engine(
-            "sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool
-        )
-        SQLModel.metadata.create_all(cls.engine)
-        with Session(cls.engine) as session:
-            create_test_db(session)
-
-    def setUp(self) -> None:
-        self.session = Session(self.engine)
-
-        def get_session_override():
-            return self.session
-
-        app.dependency_overrides[get_session] = get_session_override
-        self.client = TestClient(app)
-
-    def tearDown(self) -> None:
-        app.dependency_overrides.clear()
-        self.session.close()
+    def _create_test_db(cls, session: Session):
+        test_catalog = Catalog(name="test-catalog")
+        session.add(test_catalog)
+        session.commit()
 
     def test_get_catalog_non_existing(self):
         # When
diff --git a/backend/app/tests/api/endpoints/test_keggs.py b/backend/app/tests/api/endpoints/test_keggs.py
new file mode 100644
index 0000000000000000000000000000000000000000..2b2ca84066e2f3f88f29126ff3e8e8faf5640a01
--- /dev/null
+++ b/backend/app/tests/api/endpoints/test_keggs.py
@@ -0,0 +1,116 @@
+from sqlmodel import Session, select
+
+from app.core.models.kegg import Kegg
+
+from .base_api_test import BaseApiTests
+
+
+def create_test_db(session: Session):
+    test_kegg = Kegg(name="test-kegg")
+    session.add(test_kegg)
+    session.commit()
+
+
+class TestKeggs(BaseApiTests):
+    @classmethod
+    def _create_test_db(cls, session: Session):
+        test_kegg = Kegg(kegg_id="k1", name="test-kegg")
+        session.add(test_kegg)
+        session.commit()
+
+    def test_get_kegg_non_existing(self):
+        # When
+        response = self.client.get("/api/keggs/non-existing")
+        # Then
+        self.assertEqual(response.status_code, 404)
+
+    def test_get_kegg_existing(self):
+        # Given
+        expected_id = "k1"
+        expected_data = {"kegg_id": expected_id, "name": "test-kegg"}
+        # When
+        response = self.client.get(f"/api/keggs/{expected_id}")
+        # Then
+        self.assertEqual(response.status_code, 200)
+        self.assertDictEqual(response.json(), expected_data)
+
+    def test_get_all_keggs(self):
+        # Given
+        expected_data = [{"kegg_id": "k1", "name": "test-kegg"}]
+        # When
+        response = self.client.get(f"/api/keggs/")
+        # Then
+        self.assertEqual(response.status_code, 200)
+        self.assertListEqual(response.json(), expected_data)
+
+    def test_create_kegg(self):
+        # Given
+        kegg_id = "k9"
+        kegg_name = "created_kegg"
+        json_input = {"kegg_id": kegg_id, "name": kegg_name}
+        expected_data = {"kegg_id": kegg_id, "name": kegg_name}
+        # When
+        response = self.client.post("/api/keggs/", json=json_input)
+        # Then
+        self.assertEqual(response.status_code, 200)
+        self.assertDictEqual(response.json(), expected_data)
+        # Finally delete item
+        cat = self.session.exec(select(Kegg).where(Kegg.kegg_id == kegg_id)).one()
+        self.session.delete(cat)
+        self.session.commit()
+
+    def test_create_existing_kegg(self):
+        # Given
+        kegg_id = "k1"
+        kegg_name = "test-kegg"
+        json_input = {"kegg_id": kegg_id, "name": kegg_name}
+        # When
+        response = self.client.post("/api/keggs/", json=json_input)
+        # Then
+        self.assertEqual(response.status_code, 403)
+
+    def test_delete_kegg_non_existing(self):
+        # When
+        response = self.client.delete(f"/api/keggs/non-existing")
+        # Then
+        self.assertEqual(response.status_code, 404)
+
+    def test_delete_kegg(self):
+        # Given
+        kegg_id = "k5"
+        name_to_delete = "delete-me"
+        # - create kegg to delete
+        kegg_to_delete = Kegg(kegg_id=kegg_id, name=name_to_delete)
+        self.session.add(kegg_to_delete)
+        self.session.commit()
+        # When
+        response = self.client.delete(f"/api/keggs/{kegg_id}")
+        # Then
+        self.assertEqual(response.status_code, 200)
+
+    def test_update_kegg_non_existing(self):
+        # When
+        json_input = {"kegg_id": "i-dont-exist", "name": "12345"}
+        response = self.client.put(f"/api/keggs/", json=json_input)
+        # Then
+        self.assertEqual(response.status_code, 404)
+
+    def test_update_kegg(self):
+        # Given
+        kegg_id = "k2"
+        name_to_update = "update-me"
+        new_name = "new-name"
+        # - create kegg to update
+        kegg_to_update = Kegg(kegg_id=kegg_id, name=name_to_update)
+        self.session.add(kegg_to_update)
+        self.session.commit()
+        json_input = {"kegg_id": kegg_id, "name": new_name}
+        expected_data = json_input
+        # When
+        response = self.client.put(f"/api/keggs/", json=json_input)
+        # Then
+        self.assertEqual(response.status_code, 200)
+        self.assertDictEqual(response.json(), expected_data)
+        # Finally
+        self.session.delete(kegg_to_update)
+        self.session.commit()
diff --git a/backend/app/tests/core/use_cases/crud/test_kegg.py b/backend/app/tests/core/use_cases/crud/test_kegg.py
new file mode 100644
index 0000000000000000000000000000000000000000..ffa2c5f8f306acce15a2d7b12b627a7b3f92e5ec
--- /dev/null
+++ b/backend/app/tests/core/use_cases/crud/test_kegg.py
@@ -0,0 +1,76 @@
+import unittest
+
+from app.core.use_cases.crud.kegg import CrudKeggUseCase
+from app.core.schemas.entities.kegg import KeggCreate, KeggUpdate
+
+GET_ACTION = "Returning kegg"
+GET_ALL_ACTION = "Returning all keggs"
+CREATE_ACTION = "Creating kegg"
+UPDATE_ACTION = "Updating kegg"
+DELETE_ACTION = "Deleting kegg"
+
+
+class MockKeggsRepo:
+    def get(self, kegg_id: str):
+        return GET_ACTION
+
+    def get_all(self):
+        return GET_ALL_ACTION
+
+    def create(self, kegg_input: KeggCreate):
+        return CREATE_ACTION
+
+    def update(self, kegg_input: KeggUpdate):
+        return UPDATE_ACTION
+
+    def delete(self, kegg_id: str):
+        return DELETE_ACTION
+
+
+class TestCrudKeggUseCase(unittest.TestCase):
+    def setUp(self) -> None:
+        self.use_case_test = CrudKeggUseCase(keggs_repo=MockKeggsRepo())
+
+    def test_create_kegg(self):
+        # Given
+        kegg_test = KeggCreate(kegg_id="k01", name="test-kegg")
+        expected_output = CREATE_ACTION
+        # When
+        test_output = self.use_case_test.create_kegg(kegg_test)
+        # Then
+        self.assertEqual(test_output, expected_output)
+
+    def test_update_kegg(self):
+        # Given
+        kegg_test = KeggCreate(kegg_id="k01", name="test-kegg")
+        expected_output = UPDATE_ACTION
+        # When
+        test_output = self.use_case_test.update_kegg(kegg_test)
+        # Then
+        self.assertEqual(test_output, expected_output)
+
+    def test_delete_kegg(self):
+        # Given
+        kegg_id_test = "test-kegg"
+        expected_output = DELETE_ACTION
+        # When
+        test_output = self.use_case_test.delete_kegg(kegg_id_test)
+        # Then
+        self.assertEqual(test_output, expected_output)
+
+    def test_get_kegg(self):
+        # Given
+        kegg_id_test = "test-kegg"
+        expected_output = GET_ACTION
+        # When
+        test_output = self.use_case_test.get_kegg(kegg_id_test)
+        # Then
+        self.assertEqual(test_output, expected_output)
+
+    def test_get_all(self):
+        # Given
+        expected_output = GET_ALL_ACTION
+        # When
+        output = self.use_case_test.get_all()
+        # Then
+        self.assertEqual(output, expected_output)